diff --git a/crates/solidity/inputs/language/bindings/rules.msgb b/crates/solidity/inputs/language/bindings/rules.msgb index 9a691a495..cfd55d5bd 100644 --- a/crates/solidity/inputs/language/bindings/rules.msgb +++ b/crates/solidity/inputs/language/bindings/rules.msgb @@ -12,6 +12,7 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i ;; Keeps a link to the enclosing contract definition to provide a parent for ;; method calls (to correctly resolve virtual methods) inherit .enclosing_def +inherit .parent_scope ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Source unit (aka .sol file) @@ -30,6 +31,11 @@ inherit .enclosing_def edge export -> @source_unit.defs let @source_unit.enclosing_def = #null + + ;; This defines a parent_scope at the source unit level (this attribute is + ;; inherited) for contracts to resolve bases (both in inheritance lists and + ;; override specifiers) + let @source_unit.parent_scope = @source_unit.lexical_scope } ;; Top-level definitions... @@ -67,16 +73,6 @@ inherit .enclosing_def edge @source_unit.lexical_scope -> @import.defs } -;; Contracts need access to the parent scope to resolve bases. This is purely -;; for convenience, as contracts can only appear in SourceUnits so we could -;; potentially connect this directly when connecting to the base contract -;; identifiers (but that would make the query longer) -@source_unit [SourceUnit [SourceUnitMembers - [SourceUnitMember @contract [ContractDefinition]] -]] { - let @contract.parent_scope = @source_unit.lexical_scope -} - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Imports @@ -201,7 +197,12 @@ inherit .enclosing_def edge @contract.lexical_scope -> @contract.members edge @contract.lexical_scope -> @contract.type_members - edge @contract.lexical_scope -> @contract.modifiers + + ;; Modifiers are available as a contract type members through a special '@modifier' symbol + node modifier + attr (modifier) pop_symbol = "@modifier" + edge @contract.type_members -> modifier + edge modifier -> @contract.modifiers let @contract.enclosing_def = @contract.def } @@ -354,7 +355,6 @@ inherit .enclosing_def [ContractMember @member ( [FunctionDefinition] | [StateVariableDefinition] - | [ModifierDefinition] )] ]] { edge @contract.lexical_scope -> @member.def @@ -385,17 +385,18 @@ inherit .enclosing_def item: [ContractMember @modifier variant: [ModifierDefinition]] ]] { edge @contract.modifiers -> @modifier.def + + ;; This may prioritize this definition (when there are multiple options) + ;; according to the C3 linerisation ordering + attr (@modifier.def) tag = "c3" + attr (@modifier.def) parents = [@contract.def] } -@contract [ContractDefinition [ContractMembers [ContractMember - [FunctionDefinition [FunctionAttributes [FunctionAttribute - [OverrideSpecifier [OverridePathsDeclaration [OverridePaths - @base_ident [IdentifierPath] - ]]] - ]]] +@override [OverrideSpecifier [OverridePathsDeclaration [OverridePaths + @base_ident [IdentifierPath] ]]] { - ;; Resolve overriden bases when listed in the function modifiers - edge @base_ident.left -> @contract.parent_scope + ;; Resolve overriden bases when listed in the function or modifiers modifiers + edge @base_ident.left -> @override.parent_scope } @@ -633,9 +634,10 @@ inherit .enclosing_def node @id_path.right } -[IdentifierPath @name [Identifier]] { +@id_path [IdentifierPath @name [Identifier]] { node @name.ref attr (@name.ref) node_reference = @name + attr (@name.ref) parents = [@id_path.enclosing_def] } @id_path [IdentifierPath @name [Identifier] .] { @@ -752,7 +754,11 @@ inherit .enclosing_def @modifier [ModifierInvocation @name [IdentifierPath]] { node @modifier.lexical_scope - edge @name.left -> @modifier.lexical_scope + node modifier + attr (modifier) push_symbol = "@modifier" + + edge @name.left -> modifier + edge modifier -> @modifier.lexical_scope } @modifier [ModifierInvocation @args [ArgumentsDeclaration]] { @@ -855,18 +861,18 @@ inherit .enclosing_def ;;; Function modifiers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +@modifier [ModifierDefinition] { + node @modifier.def + node @modifier.lexical_scope +} + @modifier [ModifierDefinition @name name: [Identifier] body: [FunctionBody @body [Block]] ] { - node @modifier.def - node @modifier.lexical_scope - - node def - attr (def) node_definition = @name - attr (def) definiens_node = @modifier + attr (@modifier.def) node_definition = @name + attr (@modifier.def) definiens_node = @modifier - edge @modifier.def -> def edge @body.lexical_scope -> @modifier.lexical_scope } diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs index 2c1c9aca4..330dfccc1 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs @@ -17,6 +17,7 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i ;; Keeps a link to the enclosing contract definition to provide a parent for ;; method calls (to correctly resolve virtual methods) inherit .enclosing_def +inherit .parent_scope ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Source unit (aka .sol file) @@ -35,6 +36,11 @@ inherit .enclosing_def edge export -> @source_unit.defs let @source_unit.enclosing_def = #null + + ;; This defines a parent_scope at the source unit level (this attribute is + ;; inherited) for contracts to resolve bases (both in inheritance lists and + ;; override specifiers) + let @source_unit.parent_scope = @source_unit.lexical_scope } ;; Top-level definitions... @@ -72,16 +78,6 @@ inherit .enclosing_def edge @source_unit.lexical_scope -> @import.defs } -;; Contracts need access to the parent scope to resolve bases. This is purely -;; for convenience, as contracts can only appear in SourceUnits so we could -;; potentially connect this directly when connecting to the base contract -;; identifiers (but that would make the query longer) -@source_unit [SourceUnit [SourceUnitMembers - [SourceUnitMember @contract [ContractDefinition]] -]] { - let @contract.parent_scope = @source_unit.lexical_scope -} - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Imports @@ -206,7 +202,12 @@ inherit .enclosing_def edge @contract.lexical_scope -> @contract.members edge @contract.lexical_scope -> @contract.type_members - edge @contract.lexical_scope -> @contract.modifiers + + ;; Modifiers are available as a contract type members through a special '@modifier' symbol + node modifier + attr (modifier) pop_symbol = "@modifier" + edge @contract.type_members -> modifier + edge modifier -> @contract.modifiers let @contract.enclosing_def = @contract.def } @@ -359,7 +360,6 @@ inherit .enclosing_def [ContractMember @member ( [FunctionDefinition] | [StateVariableDefinition] - | [ModifierDefinition] )] ]] { edge @contract.lexical_scope -> @member.def @@ -390,17 +390,18 @@ inherit .enclosing_def item: [ContractMember @modifier variant: [ModifierDefinition]] ]] { edge @contract.modifiers -> @modifier.def + + ;; This may prioritize this definition (when there are multiple options) + ;; according to the C3 linerisation ordering + attr (@modifier.def) tag = "c3" + attr (@modifier.def) parents = [@contract.def] } -@contract [ContractDefinition [ContractMembers [ContractMember - [FunctionDefinition [FunctionAttributes [FunctionAttribute - [OverrideSpecifier [OverridePathsDeclaration [OverridePaths - @base_ident [IdentifierPath] - ]]] - ]]] +@override [OverrideSpecifier [OverridePathsDeclaration [OverridePaths + @base_ident [IdentifierPath] ]]] { - ;; Resolve overriden bases when listed in the function modifiers - edge @base_ident.left -> @contract.parent_scope + ;; Resolve overriden bases when listed in the function or modifiers modifiers + edge @base_ident.left -> @override.parent_scope } @@ -638,9 +639,10 @@ inherit .enclosing_def node @id_path.right } -[IdentifierPath @name [Identifier]] { +@id_path [IdentifierPath @name [Identifier]] { node @name.ref attr (@name.ref) node_reference = @name + attr (@name.ref) parents = [@id_path.enclosing_def] } @id_path [IdentifierPath @name [Identifier] .] { @@ -757,7 +759,11 @@ inherit .enclosing_def @modifier [ModifierInvocation @name [IdentifierPath]] { node @modifier.lexical_scope - edge @name.left -> @modifier.lexical_scope + node modifier + attr (modifier) push_symbol = "@modifier" + + edge @name.left -> modifier + edge modifier -> @modifier.lexical_scope } @modifier [ModifierInvocation @args [ArgumentsDeclaration]] { @@ -860,18 +866,18 @@ inherit .enclosing_def ;;; Function modifiers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +@modifier [ModifierDefinition] { + node @modifier.def + node @modifier.lexical_scope +} + @modifier [ModifierDefinition @name name: [Identifier] body: [FunctionBody @body [Block]] ] { - node @modifier.def - node @modifier.lexical_scope - - node def - attr (def) node_definition = @name - attr (def) definiens_node = @modifier + attr (@modifier.def) node_definition = @name + attr (@modifier.def) definiens_node = @modifier - edge @modifier.def -> def edge @body.lexical_scope -> @modifier.lexical_scope } diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/modifiers.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/modifiers.rs index 81fff76ce..040df7aac 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/modifiers.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/modifiers.rs @@ -4,11 +4,26 @@ use anyhow::Result; use crate::bindings_output::runner::run; +#[test] +fn diamond() -> Result<()> { + run("modifiers", "diamond") +} + +#[test] +fn inherited() -> Result<()> { + run("modifiers", "inherited") +} + #[test] fn simple() -> Result<()> { run("modifiers", "simple") } +#[test] +fn virtual_modifier() -> Result<()> { + run("modifiers", "virtual_modifier") +} + #[test] fn with_args() -> Result<()> { run("modifiers", "with_args") diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/generated/0.4.11-failure.txt new file mode 100644 index 000000000..649459320 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/generated/0.4.11-failure.txt @@ -0,0 +1,56 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected OpenBrace or Semicolon. + ╭─[input.sol:2:18] + │ + 2 │ modifier foo virtual { _; } + │ ───────┬─────── + │ ╰───────── Error occurred here. +───╯ +Error: Expected OpenBrace or Semicolon. + ╭─[input.sol:6:18] + │ + 6 │ modifier foo virtual override { _; } + │ ────────────┬─────────── + │ ╰───────────── Error occurred here. +───╯ +Error: Expected OpenBrace or Semicolon. + ╭─[input.sol:10:18] + │ + 10 │ modifier foo virtual override { _; } + │ ────────────┬─────────── + │ ╰───────────── Error occurred here. +────╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + │ + 5 │ contract A is Base { + │ ┬ ──┬─ + │ ╰────────── def: 2 + │ │ + │ ╰─── ref: 1 + │ + 9 │ contract B is Base { + │ ┬ ──┬─ + │ ╰────────── def: 3 + │ │ + │ ╰─── ref: 1 + │ + 13 │ contract Test is B, A { + │ ──┬─ ┬ ┬ + │ ╰─────────── def: 4 + │ │ │ + │ ╰───── ref: 3 + │ │ + │ ╰── ref: 2 + 14 │ function test() public foo {} + │ ──┬─ ─┬─ + │ ╰──────────────── def: 5 + │ │ + │ ╰─── unresolved +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/generated/0.6.0-success.txt new file mode 100644 index 000000000..a735ab121 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/generated/0.6.0-success.txt @@ -0,0 +1,49 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + 2 │ modifier foo virtual { _; } + │ ─┬─ ┬ + │ ╰─────────────── def: 2 + │ │ + │ ╰── unresolved + │ + 5 │ contract A is Base { + │ ┬ ──┬─ + │ ╰────────── def: 3 + │ │ + │ ╰─── ref: 1 + 6 │ modifier foo virtual override { _; } + │ ─┬─ ┬ + │ ╰──────────────────────── def: 4 + │ │ + │ ╰── unresolved + │ + 9 │ contract B is Base { + │ ┬ ──┬─ + │ ╰────────── def: 5 + │ │ + │ ╰─── ref: 1 + 10 │ modifier foo virtual override { _; } + │ ─┬─ ┬ + │ ╰──────────────────────── def: 6 + │ │ + │ ╰── unresolved + │ + 13 │ contract Test is B, A { + │ ──┬─ ┬ ┬ + │ ╰─────────── def: 7 + │ │ │ + │ ╰───── ref: 5 + │ │ + │ ╰── ref: 3 + 14 │ function test() public foo {} + │ ──┬─ ─┬─ + │ ╰──────────────── def: 8 + │ │ + │ ╰─── ref: 4 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/input.sol b/crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/input.sol new file mode 100644 index 000000000..c1ab988fc --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/diamond/input.sol @@ -0,0 +1,15 @@ +contract Base { + modifier foo virtual { _; } +} + +contract A is Base { + modifier foo virtual override { _; } +} + +contract B is Base { + modifier foo virtual override { _; } +} + +contract Test is B, A { + function test() public foo {} +} diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/inherited/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/modifiers/inherited/generated/0.4.11-success.txt new file mode 100644 index 000000000..340143bf7 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/inherited/generated/0.4.11-success.txt @@ -0,0 +1,25 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + 2 │ modifier foo { _; } + │ ─┬─ ┬ + │ ╰─────── def: 2 + │ │ + │ ╰── unresolved + │ + 5 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 3 + │ │ + │ ╰─── ref: 1 + 6 │ function test() public foo { + │ ──┬─ ─┬─ + │ ╰──────────────── def: 4 + │ │ + │ ╰─── ref: 2 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/inherited/input.sol b/crates/solidity/testing/snapshots/bindings_output/modifiers/inherited/input.sol new file mode 100644 index 000000000..deeb4ee04 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/inherited/input.sol @@ -0,0 +1,8 @@ +contract Base { + modifier foo { _; } +} + +contract Test is Base { + function test() public foo { + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/generated/0.4.11-failure.txt b/crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/generated/0.4.11-failure.txt new file mode 100644 index 000000000..f372fc430 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/generated/0.4.11-failure.txt @@ -0,0 +1,31 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Parse errors: +Error: Expected OpenBrace or Semicolon. + ╭─[input.sol:2:18] + │ + 2 │ modifier foo virtual { _; } + │ ───────┬─────── + │ ╰───────── Error occurred here. +───╯ +Error: Expected OpenBrace or Semicolon. + ╭─[input.sol:6:18] + │ + 6 │ ╭─▶ modifier foo override(Base) { _; } + 7 │ ├─▶ function test() public foo {} + │ │ + │ ╰─────────────────────────────────────── Error occurred here. +───╯ +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + │ + 5 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 2 + │ │ + │ ╰─── ref: 1 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/generated/0.6.0-success.txt b/crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/generated/0.6.0-success.txt new file mode 100644 index 000000000..9168f2ff0 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/generated/0.6.0-success.txt @@ -0,0 +1,32 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract Base { + │ ──┬─ + │ ╰─── def: 1 + 2 │ modifier foo virtual { _; } + │ ─┬─ ┬ + │ ╰─────────────── def: 2 + │ │ + │ ╰── unresolved + │ + 5 │ contract Test is Base { + │ ──┬─ ──┬─ + │ ╰─────────── def: 3 + │ │ + │ ╰─── ref: 1 + 6 │ modifier foo override(Base) { _; } + │ ─┬─ ──┬─ ┬ + │ ╰────────────────────── def: 4 + │ │ │ + │ ╰──────── ref: 1 + │ │ + │ ╰── unresolved + 7 │ function test() public foo {} + │ ──┬─ ─┬─ + │ ╰──────────────── def: 5 + │ │ + │ ╰─── ref: 4 +───╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/input.sol b/crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/input.sol new file mode 100644 index 000000000..a467856ab --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/modifiers/virtual_modifier/input.sol @@ -0,0 +1,8 @@ +contract Base { + modifier foo virtual { _; } +} + +contract Test is Base { + modifier foo override(Base) { _; } + function test() public foo {} +}