Skip to content

Commit b124729

Browse files
authored
Add utility methods to AST API (#1511)
Add some additional utility methods to AST nodes and the `Definition` type: - `ast::*::node_id()` and `Definition::node_id()` to retrieve the underlying `NodeId` associated to the CST node - `Definition::identifier()` to retrieve the identifier acting as the name of a definition - `Definition::text_offset()` to get the text offset of the start of the definition Also collect text offsets of identifier terminals, since this is now needed to be able to return it for `Identifier` AST types.
1 parent a881802 commit b124729

File tree

8 files changed

+610
-51
lines changed

8 files changed

+610
-51
lines changed

crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/contracts.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ impl ContractDefinitionStruct {
5050
base_node_ids
5151
.iter()
5252
.map(|node_id| {
53-
let base_definition = Rc::new(Definition::create(*node_id, &self.semantic));
53+
let base_definition =
54+
Definition::try_create(*node_id, &self.semantic).expect("node is a definition");
5455
ContractBase::from_definition(&base_definition)
5556
.expect("Linearised base is either a contract or interface")
5657
})
@@ -138,7 +139,7 @@ impl ContractDefinitionStruct {
138139
(None, None) => Ordering::Equal,
139140
(None, Some(_)) => Ordering::Less,
140141
(Some(_), None) => Ordering::Greater,
141-
(Some(a), Some(b)) => a.unparse().cmp(&b.unparse()),
142+
(Some(a), Some(b)) => a.name().cmp(&b.name()),
142143
});
143144
functions
144145
}

crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/definitions.rs

Lines changed: 145 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ use crate::backend::ir::ast::{
2424
create_variable_declaration_statement, create_yul_function_definition, create_yul_label,
2525
};
2626
use crate::backend::{binder, SemanticAnalysis};
27-
use crate::cst::NodeId;
27+
use crate::cst::{NodeId, TextIndex};
2828

2929
// __SLANG_DEFINITION_TYPES__ keep in sync with binder
30+
#[derive(Clone)]
3031
pub enum Definition {
3132
Constant(ConstantDefinition),
3233
Contract(ContractDefinition),
@@ -54,13 +55,13 @@ pub enum Definition {
5455
}
5556

5657
impl Definition {
57-
pub(crate) fn create(definition_id: NodeId, semantic: &Rc<SemanticAnalysis>) -> Self {
58-
let definition = semantic
59-
.binder()
60-
.find_definition_by_id(definition_id)
61-
.expect("definition_id references a definition node");
58+
pub(crate) fn try_create(
59+
definition_id: NodeId,
60+
semantic: &Rc<SemanticAnalysis>,
61+
) -> Option<Self> {
62+
let definition = semantic.binder().find_definition_by_id(definition_id)?;
6263

63-
match definition {
64+
let definition = match definition {
6465
binder::Definition::Constant(constant_definition) => Self::Constant(
6566
create_constant_definition(&constant_definition.ir_node, semantic),
6667
),
@@ -133,6 +134,140 @@ impl Definition {
133134
binder::Definition::YulVariable(yul_variable_definition) => Self::YulVariable(
134135
create_yul_identifier(&yul_variable_definition.ir_node, semantic),
135136
),
137+
};
138+
Some(definition)
139+
}
140+
141+
pub fn node_id(&self) -> NodeId {
142+
match self {
143+
Definition::Constant(constant_definition) => constant_definition.node_id(),
144+
Definition::Contract(contract_definition) => contract_definition.node_id(),
145+
Definition::Enum(enum_definition) => enum_definition.node_id(),
146+
Definition::EnumMember(identifier) => identifier.node_id(),
147+
Definition::Error(error_definition) => error_definition.node_id(),
148+
Definition::Event(event_definition) => event_definition.node_id(),
149+
Definition::Function(function_definition) => function_definition.node_id(),
150+
Definition::Import(path_import) => path_import.node_id(),
151+
Definition::ImportedSymbol(import_deconstruction_symbol) => {
152+
import_deconstruction_symbol.node_id()
153+
}
154+
Definition::Interface(interface_definition) => interface_definition.node_id(),
155+
Definition::Library(library_definition) => library_definition.node_id(),
156+
Definition::Modifier(function_definition) => function_definition.node_id(),
157+
Definition::Parameter(parameter) => parameter.node_id(),
158+
Definition::StateVariable(state_variable_definition) => {
159+
state_variable_definition.node_id()
160+
}
161+
Definition::Struct(struct_definition) => struct_definition.node_id(),
162+
Definition::StructMember(struct_member) => struct_member.node_id(),
163+
Definition::TypeParameter(parameter) => parameter.node_id(),
164+
Definition::UserDefinedValueType(user_defined_value_type_definition) => {
165+
user_defined_value_type_definition.node_id()
166+
}
167+
Definition::Variable(variable_declaration_statement) => {
168+
variable_declaration_statement.node_id()
169+
}
170+
Definition::YulFunction(yul_function_definition) => yul_function_definition.node_id(),
171+
Definition::YulLabel(yul_label) => yul_label.node_id(),
172+
Definition::YulParameter(identifier) => identifier.node_id(),
173+
Definition::YulVariable(identifier) => identifier.node_id(),
174+
}
175+
}
176+
177+
pub fn identifier(&self) -> Identifier {
178+
match self {
179+
Definition::Constant(constant_definition) => constant_definition.name(),
180+
Definition::Contract(contract_definition) => contract_definition.name(),
181+
Definition::Enum(enum_definition) => enum_definition.name(),
182+
Definition::EnumMember(identifier) => Rc::clone(identifier),
183+
Definition::Error(error_definition) => error_definition.name(),
184+
Definition::Event(event_definition) => event_definition.name(),
185+
Definition::Function(function_definition) => {
186+
// functions that are definitions always have a name
187+
function_definition
188+
.name()
189+
.expect("function definitions have a name")
190+
}
191+
Definition::Import(path_import) => {
192+
// imports that are definition always have a name
193+
path_import
194+
.alias()
195+
.expect("path import definitions have a name")
196+
}
197+
Definition::ImportedSymbol(import_deconstruction_symbol) => {
198+
import_deconstruction_symbol
199+
.alias()
200+
.unwrap_or_else(|| import_deconstruction_symbol.name())
201+
}
202+
Definition::Interface(interface_definition) => interface_definition.name(),
203+
Definition::Library(library_definition) => library_definition.name(),
204+
Definition::Modifier(function_definition) => {
205+
// modifiers always have a name
206+
function_definition.name().expect("modifiers have a name")
207+
}
208+
Definition::Parameter(parameter) => {
209+
// parameters that are definitions always have a name
210+
parameter.name().expect("parameter definitions have a name")
211+
}
212+
Definition::StateVariable(state_variable_definition) => {
213+
state_variable_definition.name()
214+
}
215+
Definition::Struct(struct_definition) => struct_definition.name(),
216+
Definition::StructMember(struct_member) => struct_member.name(),
217+
Definition::TypeParameter(parameter) => {
218+
// parameters that are definitions always have a name
219+
parameter
220+
.name()
221+
.expect("type parameter definitions have a name")
222+
}
223+
Definition::UserDefinedValueType(user_defined_value_type_definition) => {
224+
user_defined_value_type_definition.name()
225+
}
226+
Definition::Variable(variable_declaration_statement) => {
227+
variable_declaration_statement.name()
228+
}
229+
Definition::YulFunction(yul_function_definition) => yul_function_definition.name(),
230+
Definition::YulLabel(yul_label) => yul_label.label(),
231+
Definition::YulParameter(identifier) => Rc::clone(identifier),
232+
Definition::YulVariable(identifier) => Rc::clone(identifier),
233+
}
234+
}
235+
236+
pub fn text_offset(&self) -> TextIndex {
237+
match self {
238+
Definition::Constant(constant_definition) => constant_definition.text_offset(),
239+
Definition::Contract(contract_definition) => contract_definition.text_offset(),
240+
Definition::Enum(enum_definition) => enum_definition.text_offset(),
241+
Definition::EnumMember(identifier) => identifier.text_offset(),
242+
Definition::Error(error_definition) => error_definition.text_offset(),
243+
Definition::Event(event_definition) => event_definition.text_offset(),
244+
Definition::Function(function_definition) => function_definition.text_offset(),
245+
Definition::Import(path_import) => path_import.text_offset(),
246+
Definition::ImportedSymbol(import_deconstruction_symbol) => {
247+
import_deconstruction_symbol.text_offset()
248+
}
249+
Definition::Interface(interface_definition) => interface_definition.text_offset(),
250+
Definition::Library(library_definition) => library_definition.text_offset(),
251+
Definition::Modifier(function_definition) => function_definition.text_offset(),
252+
Definition::Parameter(parameter) => parameter.text_offset(),
253+
Definition::StateVariable(state_variable_definition) => {
254+
state_variable_definition.text_offset()
255+
}
256+
Definition::Struct(struct_definition) => struct_definition.text_offset(),
257+
Definition::StructMember(struct_member) => struct_member.text_offset(),
258+
Definition::TypeParameter(parameter) => parameter.text_offset(),
259+
Definition::UserDefinedValueType(user_defined_value_type_definition) => {
260+
user_defined_value_type_definition.text_offset()
261+
}
262+
Definition::Variable(variable_declaration_statement) => {
263+
variable_declaration_statement.text_offset()
264+
}
265+
Definition::YulFunction(yul_function_definition) => {
266+
yul_function_definition.text_offset()
267+
}
268+
Definition::YulLabel(yul_label) => yul_label.text_offset(),
269+
Definition::YulParameter(identifier) => identifier.text_offset(),
270+
Definition::YulVariable(identifier) => identifier.text_offset(),
136271
}
137272
}
138273

@@ -182,6 +317,9 @@ macro_rules! define_references_method {
182317
pub fn references(&self) -> Vec<Reference> {
183318
self.semantic.references_binding_to(self.ir_node.node_id)
184319
}
320+
pub fn as_definition(&self) -> Option<Definition> {
321+
Definition::try_create(self.ir_node.node_id, &self.semantic)
322+
}
185323
}
186324
}
187325
};

crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/identifiers.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::rc::Rc;
33
use super::super::IdentifierPathStruct;
44
use super::Definition;
55
use crate::backend::SemanticAnalysis;
6-
use crate::cst::{NodeId, TerminalKind, TerminalNode};
6+
use crate::cst::{NodeId, TerminalKind, TerminalNode, TextIndex};
77

88
pub type Identifier = Rc<IdentifierStruct>;
99

@@ -24,7 +24,11 @@ pub struct IdentifierStruct {
2424
}
2525

2626
impl IdentifierStruct {
27-
pub fn unparse(&self) -> String {
27+
pub fn node_id(&self) -> NodeId {
28+
self.ir_node.id()
29+
}
30+
31+
pub fn name(&self) -> String {
2832
self.ir_node.unparse()
2933
}
3034

@@ -42,10 +46,24 @@ impl IdentifierStruct {
4246
.binder()
4347
.find_reference_by_identifier_node_id(self.ir_node.id())?;
4448
let definition_id = reference.resolution.as_definition_id()?;
45-
Some(Definition::create(definition_id, &self.semantic))
49+
Definition::try_create(definition_id, &self.semantic)
4650
}
4751

52+
/// Returns `true` if the identifier itself is a definition (eg. an enum member)
4853
pub fn is_definition(&self) -> bool {
54+
self.as_definition().is_some()
55+
}
56+
57+
/// Returns the `Definition` corresponding to this identifier. Panics if the
58+
/// identifier is not a definition by itself, ie. this can only be called
59+
/// safely if `is_definition()` returns `true`.
60+
pub fn as_definition(&self) -> Option<Definition> {
61+
Definition::try_create(self.ir_node.id(), &self.semantic)
62+
}
63+
64+
/// Returns `true` if the identifier is a definition itself, or is the name
65+
/// identifier of a definition
66+
pub fn is_name_of_definition(&self) -> bool {
4967
self.semantic
5068
.binder()
5169
.find_definition_by_identifier_node_id(self.ir_node.id())
@@ -56,6 +74,12 @@ impl IdentifierStruct {
5674
pub fn references(&self) -> Vec<Reference> {
5775
self.semantic.references_binding_to(self.ir_node.id())
5876
}
77+
78+
pub fn text_offset(&self) -> TextIndex {
79+
self.semantic
80+
.get_text_offset_by_node_id(self.ir_node.id())
81+
.unwrap()
82+
}
5983
}
6084

6185
pub type YulIdentifierStruct = IdentifierStruct;
@@ -98,10 +122,10 @@ impl Reference {
98122
}
99123
}
100124

101-
pub fn unparse(&self) -> String {
125+
pub fn name(&self) -> String {
102126
match self {
103127
Reference::Identifier(identifier) | Reference::YulIdentifier(identifier) => {
104-
identifier.unparse()
128+
identifier.name()
105129
}
106130
}
107131
}
@@ -131,7 +155,7 @@ impl SemanticAnalysis {
131155
}
132156

133157
impl IdentifierPathStruct {
134-
pub fn unparse(&self) -> String {
158+
pub fn name(&self) -> String {
135159
self.ir_nodes
136160
.iter()
137161
.map(|ir_node| ir_node.unparse())
@@ -146,6 +170,6 @@ impl IdentifierPathStruct {
146170
.binder()
147171
.find_reference_by_identifier_node_id(ir_node.id())?;
148172
let definition_id = reference.resolution.as_definition_id()?;
149-
Some(Definition::create(definition_id, &self.semantic))
173+
Definition::try_create(definition_id, &self.semantic)
150174
}
151175
}

0 commit comments

Comments
 (0)