|
| 1 | +//! Parsing and validation of source item definitions |
| 2 | +//! |
| 3 | +//! This module contains structs for each of the source item types that can be documented with `NatSpec`. |
| 4 | +//! The [`Definition`] type provides a unified interface to interact with the various types. |
| 5 | +//! The [`find_items`] function takes the tree root [`Cursor`] from a Solidity document and returns all the parsed |
| 6 | +//! definitions contained within. |
| 7 | +//! Some helper functions allow to extract useful information from [`Cursor`]s. |
1 | 8 | use constructor::ConstructorDefinition;
|
2 | 9 | use derive_more::{Display, From};
|
3 | 10 | use enumeration::EnumDefinition;
|
@@ -304,7 +311,7 @@ impl Definition {
|
304 | 311 | }
|
305 | 312 | }
|
306 | 313 |
|
307 |
| -/// Find source item definitions from a root CST cursor |
| 314 | +/// Find source item definitions from a root CST [`Cursor`] |
308 | 315 | pub fn find_items(cursor: Cursor) -> Vec<Definition> {
|
309 | 316 | let mut out = Vec::new();
|
310 | 317 | for m in cursor.query(vec![
|
@@ -357,7 +364,7 @@ pub fn find_items(cursor: Cursor) -> Vec<Definition> {
|
357 | 364 |
|
358 | 365 | /// Extract parameters from a function-like source item.
|
359 | 366 | ///
|
360 |
| -/// The node kind that holds the `Identifier` (`Parameter`, `EventParameter`) is provided as `kind`. |
| 367 | +/// The node kind that holds the `Identifier` (`Parameter`, `EventParameter`) must be provided with `kind`. |
361 | 368 | #[must_use]
|
362 | 369 | pub fn extract_params(cursor: &Cursor, kind: NonterminalKind) -> Vec<Identifier> {
|
363 | 370 | let mut cursor = cursor.spawn();
|
@@ -474,6 +481,60 @@ pub fn extract_identifiers(cursor: &Cursor) -> Vec<Identifier> {
|
474 | 481 | out
|
475 | 482 | }
|
476 | 483 |
|
| 484 | +/// Extract the attributes (visibility and override) from a function-like item or state variable |
| 485 | +#[must_use] |
| 486 | +pub fn extract_attributes(cursor: &Cursor) -> Attributes { |
| 487 | + let mut cursor = cursor.spawn(); |
| 488 | + let mut out = Attributes::default(); |
| 489 | + while cursor.go_to_next_terminal_with_kinds(&[ |
| 490 | + TerminalKind::ExternalKeyword, |
| 491 | + TerminalKind::InternalKeyword, |
| 492 | + TerminalKind::PrivateKeyword, |
| 493 | + TerminalKind::PublicKeyword, |
| 494 | + TerminalKind::OverrideKeyword, |
| 495 | + ]) { |
| 496 | + match cursor |
| 497 | + .node() |
| 498 | + .as_terminal() |
| 499 | + .expect("should be terminal kind") |
| 500 | + .kind |
| 501 | + { |
| 502 | + TerminalKind::ExternalKeyword => out.visibility = Visibility::External, |
| 503 | + TerminalKind::InternalKeyword => out.visibility = Visibility::Internal, |
| 504 | + TerminalKind::PrivateKeyword => out.visibility = Visibility::Private, |
| 505 | + TerminalKind::PublicKeyword => out.visibility = Visibility::Public, |
| 506 | + TerminalKind::OverrideKeyword => out.r#override = true, |
| 507 | + _ => unreachable!(), |
| 508 | + } |
| 509 | + } |
| 510 | + out |
| 511 | +} |
| 512 | + |
| 513 | +/// Find the parent's name (contract, interface, library), if any |
| 514 | +#[must_use] |
| 515 | +pub fn extract_parent_name(mut cursor: Cursor) -> Option<Parent> { |
| 516 | + while cursor.go_to_parent() { |
| 517 | + if let Some(parent) = cursor.node().as_nonterminal_with_kinds(&[ |
| 518 | + NonterminalKind::ContractDefinition, |
| 519 | + NonterminalKind::InterfaceDefinition, |
| 520 | + NonterminalKind::LibraryDefinition, |
| 521 | + ]) { |
| 522 | + for child in &parent.children { |
| 523 | + if child.is_terminal_with_kind(TerminalKind::Identifier) { |
| 524 | + let name = child.node.unparse().trim().to_string(); |
| 525 | + return Some(match parent.kind { |
| 526 | + NonterminalKind::ContractDefinition => Parent::Contract(name), |
| 527 | + NonterminalKind::InterfaceDefinition => Parent::Interface(name), |
| 528 | + NonterminalKind::LibraryDefinition => Parent::Library(name), |
| 529 | + _ => unreachable!(), |
| 530 | + }); |
| 531 | + } |
| 532 | + } |
| 533 | + } |
| 534 | + } |
| 535 | + None |
| 536 | +} |
| 537 | + |
477 | 538 | /// Check a list of params to see if they are documented with a corresponding item in the [`NatSpec`], and generate a
|
478 | 539 | /// diagnostic for each missing one or if there are more than 1 entry per param.
|
479 | 540 | #[must_use]
|
@@ -542,60 +603,6 @@ pub fn check_returns(
|
542 | 603 | res
|
543 | 604 | }
|
544 | 605 |
|
545 |
| -/// Extract the attributes (visibility and override) from a function-like item or state variable |
546 |
| -#[must_use] |
547 |
| -pub fn extract_attributes(cursor: &Cursor) -> Attributes { |
548 |
| - let mut cursor = cursor.spawn(); |
549 |
| - let mut out = Attributes::default(); |
550 |
| - while cursor.go_to_next_terminal_with_kinds(&[ |
551 |
| - TerminalKind::ExternalKeyword, |
552 |
| - TerminalKind::InternalKeyword, |
553 |
| - TerminalKind::PrivateKeyword, |
554 |
| - TerminalKind::PublicKeyword, |
555 |
| - TerminalKind::OverrideKeyword, |
556 |
| - ]) { |
557 |
| - match cursor |
558 |
| - .node() |
559 |
| - .as_terminal() |
560 |
| - .expect("should be terminal kind") |
561 |
| - .kind |
562 |
| - { |
563 |
| - TerminalKind::ExternalKeyword => out.visibility = Visibility::External, |
564 |
| - TerminalKind::InternalKeyword => out.visibility = Visibility::Internal, |
565 |
| - TerminalKind::PrivateKeyword => out.visibility = Visibility::Private, |
566 |
| - TerminalKind::PublicKeyword => out.visibility = Visibility::Public, |
567 |
| - TerminalKind::OverrideKeyword => out.r#override = true, |
568 |
| - _ => unreachable!(), |
569 |
| - } |
570 |
| - } |
571 |
| - out |
572 |
| -} |
573 |
| - |
574 |
| -/// Find the parent's name (contract, interface, library), if any |
575 |
| -#[must_use] |
576 |
| -pub fn extract_parent_name(mut cursor: Cursor) -> Option<Parent> { |
577 |
| - while cursor.go_to_parent() { |
578 |
| - if let Some(parent) = cursor.node().as_nonterminal_with_kinds(&[ |
579 |
| - NonterminalKind::ContractDefinition, |
580 |
| - NonterminalKind::InterfaceDefinition, |
581 |
| - NonterminalKind::LibraryDefinition, |
582 |
| - ]) { |
583 |
| - for child in &parent.children { |
584 |
| - if child.is_terminal_with_kind(TerminalKind::Identifier) { |
585 |
| - let name = child.node.unparse().trim().to_string(); |
586 |
| - return Some(match parent.kind { |
587 |
| - NonterminalKind::ContractDefinition => Parent::Contract(name), |
588 |
| - NonterminalKind::InterfaceDefinition => Parent::Interface(name), |
589 |
| - NonterminalKind::LibraryDefinition => Parent::Library(name), |
590 |
| - _ => unreachable!(), |
591 |
| - }); |
592 |
| - } |
593 |
| - } |
594 |
| - } |
595 |
| - } |
596 |
| - None |
597 |
| -} |
598 |
| - |
599 | 606 | #[cfg(test)]
|
600 | 607 | mod tests {
|
601 | 608 | use similar_asserts::assert_eq;
|
|
0 commit comments