diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs index 1b18c8d0b7..7f52c97a2b 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs @@ -104,19 +104,19 @@ fn check_bindings_coverage<'a>( ) .with_config(Config::default().with_color(false)); - let query = Query::parse("@identifier ([Identifier] | [YulIdentifier])").unwrap(); - let tree_cursor = part.parse_output.create_tree_cursor(); - for result in tree_cursor.query(vec![query]) { - let identifier_cursor = result.captures.get("identifier").unwrap().first().unwrap(); - let parent = { - let mut parent_cursor = identifier_cursor.spawn(); - parent_cursor.go_to_parent(); - parent_cursor.node() - }; - if parent.is_nonterminal_with_kind(NonterminalKind::ExperimentalFeature) { - // ignore identifiers in `pragma experimental` directives + let cursor = part.parse_output.create_tree_cursor(); + + while cursor + .go_to_next_terminal_with_kinds(&[TerminalKind::Identifier, TerminalKind::YulIdentifier]) + { + if matches!( + cursor.ancestors().next(), + Some(ancestor) if ancestor.kind == NonterminalKind::ExperimentalFeature + ) { + // ignore identifiers in `pragma experimental` directives, as they are unbound feature names: continue; } + if binding_graph.definition_at(identifier_cursor).is_none() && binding_graph.reference_at(identifier_cursor).is_none() { diff --git a/crates/solidity/testing/perf/benches/iai/main.rs b/crates/solidity/testing/perf/benches/iai/main.rs index 4224c80878..f7c9f755ec 100644 --- a/crates/solidity/testing/perf/benches/iai/main.rs +++ b/crates/solidity/testing/perf/benches/iai/main.rs @@ -2,28 +2,20 @@ #![allow(clippy::needless_pass_by_value)] use std::hint::black_box; +use std::rc::Rc; use iai_callgrind::{ library_benchmark, library_benchmark_group, main, Direction, FlamegraphConfig, LibraryBenchmarkConfig, Tool, ValgrindTool, }; -use slang_solidity::bindings::BindingGraphBuilder; +use slang_solidity::bindings::BindingGraph; use solidity_testing_perf::dataset::SourceFile; -use solidity_testing_perf::tests::definitions::Dependencies; use solidity_testing_perf::tests::parser::ParsedFile; mod __dependencies_used_in_lib__ { use {infra_utils as _, metaslang_bindings as _, semver as _}; } -macro_rules! define_benchmark { - ($name:ident) => { - #[library_benchmark] - fn $name() { - black_box(solidity_testing_perf::tests::$name::run()); - } - }; -} macro_rules! define_payload_benchmark { ($name:ident, $payload:ty) => { #[library_benchmark(setup = solidity_testing_perf::tests::$name::setup)] @@ -43,15 +35,14 @@ macro_rules! define_payload_benchmark { define_payload_benchmark!(parser, Vec); define_payload_benchmark!(cursor, Vec); define_payload_benchmark!(query, Vec); -define_benchmark!(init_bindings); -define_payload_benchmark!(definitions, Dependencies); -define_payload_benchmark!(references, BindingGraphBuilder); +define_payload_benchmark!(bindings_build, Vec); +define_payload_benchmark!(bindings_resolve, BuiltBindingGraph); library_benchmark_group!( name = benchmarks; // __SLANG_INFRA_BENCHMARKS_LIST__ (keep in sync) - benchmarks = parser, cursor, query, init_bindings, definitions, references + benchmarks = parser, cursor, query, bindings_build, bindings_resolve, ); main!( diff --git a/crates/solidity/testing/perf/src/lib.rs b/crates/solidity/testing/perf/src/lib.rs index 0b25500b67..8b58eabad1 100644 --- a/crates/solidity/testing/perf/src/lib.rs +++ b/crates/solidity/testing/perf/src/lib.rs @@ -11,14 +11,6 @@ mod __dependencies_used_in_benches__ { #[cfg(test)] mod unit_tests { - macro_rules! define_test { - ($name:ident) => { - #[test] - fn $name() { - crate::tests::$name::run(); - } - }; - } macro_rules! define_payload_test { ($name:ident) => { #[test] @@ -35,7 +27,6 @@ mod unit_tests { define_payload_test!(parser); define_payload_test!(cursor); define_payload_test!(query); - define_test!(init_bindings); - define_payload_test!(definitions); - define_payload_test!(references); + define_payload_test!(bindings_build); + define_payload_test!(bindings_resolve); } diff --git a/crates/solidity/testing/perf/src/tests/bindings_build.rs b/crates/solidity/testing/perf/src/tests/bindings_build.rs new file mode 100644 index 0000000000..35a95a963f --- /dev/null +++ b/crates/solidity/testing/perf/src/tests/bindings_build.rs @@ -0,0 +1,40 @@ +use std::rc::Rc; + +use infra_utils::paths::PathExtensions; +use metaslang_bindings::PathResolver; +use slang_solidity::bindings::{create_with_resolver, BindingGraph}; +use slang_solidity::cst::{Cursor, KindTypes}; + +use crate::dataset::SOLC_VERSION; +use crate::tests::parser::ParsedFile; + +pub fn setup() -> Vec { + super::parser::run(super::parser::setup()) +} + +pub fn run(files: Vec) -> Rc { + let mut bindings_graph_builder = + create_with_resolver(SOLC_VERSION, Rc::new(Resolver {})).unwrap(); + + for file in files { + bindings_graph_builder.add_user_file( + file.path.unwrap_str(), + file.parse_output.create_tree_cursor(), + ); + } + + bindings_graph_builder.build() +} + +struct Resolver; + +impl PathResolver for Resolver { + fn resolve_path(&self, _context_path: &str, path_to_resolve: &Cursor) -> Option { + let path = path_to_resolve.node().unparse(); + let path = path + .strip_prefix(|c| matches!(c, '"' | '\''))? + .strip_suffix(|c| matches!(c, '"' | '\''))?; + + Some(path.to_owned()) + } +} diff --git a/crates/solidity/testing/perf/src/tests/bindings_resolve.rs b/crates/solidity/testing/perf/src/tests/bindings_resolve.rs new file mode 100644 index 0000000000..1d1621431b --- /dev/null +++ b/crates/solidity/testing/perf/src/tests/bindings_resolve.rs @@ -0,0 +1,55 @@ +use std::rc::Rc; + +use slang_solidity::bindings::BindingGraph; +use slang_solidity::cst::{NonterminalKind, TerminalKind}; + +use crate::tests::parser::ParsedFile; + +pub struct BuiltBindingGraph { + files: Vec, + binding_graph: Rc, +} + +pub fn setup() -> BuiltBindingGraph { + let files = super::bindings_build::setup(); + let binding_graph = super::bindings_build::run(files.clone()); + + BuiltBindingGraph { + files, + binding_graph, + } +} + +pub fn run(dependencies: BuiltBindingGraph) { + let BuiltBindingGraph { + files, + binding_graph, + } = dependencies; + + for file in dependencies.files { + let cursor = file.parse_output.create_tree_cursor(); + + while cursor.go_to_next_terminal_with_kinds(&[ + TerminalKind::Identifier, + TerminalKind::YulIdentifier, + ]) { + if matches!( + cursor.ancestors().next(), + Some(ancestor) if ancestor.kind == NonterminalKind::ExperimentalFeature + ) { + // ignore identifiers in `pragma experimental` directives, as they are unbound feature names: + continue; + } + + if binding_graph.definition_at(identifier_cursor).is_none() + && binding_graph.reference_at(identifier_cursor).is_none() + { + panic!( + "Unbound identifier: '{value}' at '{range}'.", + value = cursor.node().unparse(), + range = cursor.text_range() + ); + } + } + } +} diff --git a/crates/solidity/testing/perf/src/tests/definitions.rs b/crates/solidity/testing/perf/src/tests/definitions.rs deleted file mode 100644 index 5812424b28..0000000000 --- a/crates/solidity/testing/perf/src/tests/definitions.rs +++ /dev/null @@ -1,37 +0,0 @@ -use slang_solidity::bindings::BindingGraphBuilder; - -use crate::tests::parser::ParsedFile; - -pub struct Dependencies { - pub binding_graph_builder: BindingGraphBuilder, - pub files: Vec, -} - -pub fn setup() -> Dependencies { - let binding_graph_builder = super::init_bindings::run(); - let files = super::parser::run(super::parser::setup()); - - Dependencies { - binding_graph_builder, - files, - } -} - -pub fn run(dependencies: Dependencies) -> BindingGraphBuilder { - let Dependencies { - mut binding_graph_builder, - files, - } = dependencies; - - for ParsedFile { - path, - contents: _, - parse_output, - } in &files - { - binding_graph_builder - .add_user_file(path.to_str().unwrap(), parse_output.create_tree_cursor()); - } - - binding_graph_builder -} diff --git a/crates/solidity/testing/perf/src/tests/init_bindings.rs b/crates/solidity/testing/perf/src/tests/init_bindings.rs deleted file mode 100644 index 78aec737a0..0000000000 --- a/crates/solidity/testing/perf/src/tests/init_bindings.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::rc::Rc; - -use metaslang_bindings::PathResolver; -use slang_solidity::bindings::{create_with_resolver, BindingGraphBuilder}; -use slang_solidity::cst::{Cursor, KindTypes}; - -use crate::dataset::SOLC_VERSION; - -pub fn run() -> BindingGraphBuilder { - create_with_resolver(SOLC_VERSION, Rc::new(NoOpResolver {})).unwrap() -} - -struct NoOpResolver; - -impl PathResolver for NoOpResolver { - fn resolve_path(&self, _context_path: &str, path_to_resolve: &Cursor) -> Option { - let path = path_to_resolve.node().unparse(); - let path = path - .strip_prefix(|c| matches!(c, '"' | '\''))? - .strip_suffix(|c| matches!(c, '"' | '\''))?; - - Some(path.to_owned()) - } -} diff --git a/crates/solidity/testing/perf/src/tests/mod.rs b/crates/solidity/testing/perf/src/tests/mod.rs index d593675b64..c9a1088461 100644 --- a/crates/solidity/testing/perf/src/tests/mod.rs +++ b/crates/solidity/testing/perf/src/tests/mod.rs @@ -1,6 +1,5 @@ +pub mod bindings_build; +pub mod bindings_resolve; pub mod cursor; -pub mod definitions; -pub mod init_bindings; pub mod parser; pub mod query; -pub mod references; diff --git a/crates/solidity/testing/perf/src/tests/parser.rs b/crates/solidity/testing/perf/src/tests/parser.rs index 6892a0429e..1eecbec387 100644 --- a/crates/solidity/testing/perf/src/tests/parser.rs +++ b/crates/solidity/testing/perf/src/tests/parser.rs @@ -4,6 +4,7 @@ use slang_solidity::parser::{ParseOutput, Parser}; use crate::dataset::{SourceFile, SOLC_VERSION}; +#[derive(Clone)] pub struct ParsedFile { pub path: PathBuf, diff --git a/crates/solidity/testing/perf/src/tests/references.rs b/crates/solidity/testing/perf/src/tests/references.rs deleted file mode 100644 index 65134d7791..0000000000 --- a/crates/solidity/testing/perf/src/tests/references.rs +++ /dev/null @@ -1,41 +0,0 @@ -use slang_solidity::bindings::BindingGraphBuilder; - -pub fn setup() -> BindingGraphBuilder { - let dependencies = super::definitions::setup(); - - super::definitions::run(dependencies) -} - -pub fn run(binding_graph_builder: BindingGraphBuilder) { - let binding_graph = binding_graph_builder.build(); - - let definition_count = binding_graph - .all_definitions() - .filter(|definition| definition.get_file().is_user()) - .count(); - - assert_eq!(definition_count, 882, "Failed to fetch all definitions"); - - let mut reference_count = 0_usize; - let mut resolved_references = 0_usize; - - for reference in binding_graph.all_references() { - if reference.get_file().is_system() { - // skip built-ins - continue; - } - reference_count += 1; - - let definitions = reference.definitions(); - if !definitions.is_empty() { - resolved_references += 1; - } - } - - assert_eq!(reference_count, 1652, "Failed to fetch all references"); - - assert_eq!( - resolved_references, 1490, - "Failed to resolve all references" - ); -}