mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
libsolidity: Extend the AST for named AST nodes in order to get precise locations for names.
The actual SourceLocation on an ASTNode is representing the whole ASTNode whereas in an LSP (for example) you are also interested in the SourceLocation of a name of a construct (e.g. variable decarlation, function definition, ...). This also properly encodes non-existend sources as `-1` in the JSON output (eliminating the use of `numeric_limits<size_t>::max()`).
This commit is contained in:
committed by
chriseth
parent
72c6932bf5
commit
32ba5f5ae7
@@ -226,6 +226,7 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
|
||||
expectToken(Token::Import);
|
||||
ASTPointer<ASTString> path;
|
||||
ASTPointer<ASTString> unitAlias = make_shared<string>();
|
||||
SourceLocation unitAliasLocation{};
|
||||
ImportDirective::SymbolAliasList symbolAliases;
|
||||
|
||||
if (m_scanner->currentToken() == Token::StringLiteral)
|
||||
@@ -234,7 +235,7 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
|
||||
if (m_scanner->currentToken() == Token::As)
|
||||
{
|
||||
m_scanner->next();
|
||||
unitAlias = expectIdentifierToken();
|
||||
tie(unitAlias, unitAliasLocation) = expectIdentifierWithLocation();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -250,8 +251,7 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
|
||||
if (m_scanner->currentToken() == Token::As)
|
||||
{
|
||||
expectToken(Token::As);
|
||||
aliasLocation = currentLocation();
|
||||
alias = expectIdentifierToken();
|
||||
tie(alias, aliasLocation) = expectIdentifierWithLocation();
|
||||
}
|
||||
symbolAliases.emplace_back(ImportDirective::SymbolAlias{move(id), move(alias), aliasLocation});
|
||||
if (m_scanner->currentToken() != Token::Comma)
|
||||
@@ -264,7 +264,7 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
|
||||
{
|
||||
m_scanner->next();
|
||||
expectToken(Token::As);
|
||||
unitAlias = expectIdentifierToken();
|
||||
tie(unitAlias, unitAliasLocation) = expectIdentifierWithLocation();
|
||||
}
|
||||
else
|
||||
fatalParserError(9478_error, "Expected string literal (path), \"*\" or alias list.");
|
||||
@@ -281,7 +281,7 @@ ASTPointer<ImportDirective> Parser::parseImportDirective()
|
||||
fatalParserError(6326_error, "Import path cannot be empty.");
|
||||
nodeFactory.markEndPosition();
|
||||
expectToken(Token::Semicolon);
|
||||
return nodeFactory.createNode<ImportDirective>(path, unitAlias, move(symbolAliases));
|
||||
return nodeFactory.createNode<ImportDirective>(path, unitAlias, unitAliasLocation, move(symbolAliases));
|
||||
}
|
||||
|
||||
std::pair<ContractKind, bool> Parser::parseContractKind()
|
||||
@@ -317,6 +317,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
||||
RecursionGuard recursionGuard(*this);
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
ASTPointer<ASTString> name = nullptr;
|
||||
SourceLocation nameLocation{};
|
||||
ASTPointer<StructuredDocumentation> documentation;
|
||||
vector<ASTPointer<InheritanceSpecifier>> baseContracts;
|
||||
vector<ASTPointer<ASTNode>> subNodes;
|
||||
@@ -325,7 +326,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
||||
{
|
||||
documentation = parseStructuredDocumentation();
|
||||
contractKind = parseContractKind();
|
||||
name = expectIdentifierToken();
|
||||
tie(name, nameLocation) = expectIdentifierWithLocation();
|
||||
if (m_scanner->currentToken() == Token::Is)
|
||||
do
|
||||
{
|
||||
@@ -385,6 +386,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
||||
expectToken(Token::RBrace);
|
||||
return nodeFactory.createNode<ContractDefinition>(
|
||||
name,
|
||||
nameLocation,
|
||||
documentation,
|
||||
baseContracts,
|
||||
subNodes,
|
||||
@@ -572,6 +574,7 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction)
|
||||
|
||||
Token kind = m_scanner->currentToken();
|
||||
ASTPointer<ASTString> name;
|
||||
SourceLocation nameLocation;
|
||||
if (kind == Token::Function)
|
||||
{
|
||||
m_scanner->next();
|
||||
@@ -586,6 +589,7 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction)
|
||||
{Token::Fallback, "fallback function"},
|
||||
{Token::Receive, "receive function"},
|
||||
}.at(m_scanner->currentToken());
|
||||
nameLocation = currentLocation();
|
||||
name = make_shared<ASTString>(TokenTraits::toString(m_scanner->currentToken()));
|
||||
string message{
|
||||
"This function is named \"" + *name + "\" but is not the " + expected + " of the contract. "
|
||||
@@ -599,7 +603,7 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction)
|
||||
m_scanner->next();
|
||||
}
|
||||
else
|
||||
name = expectIdentifierToken();
|
||||
tie(name, nameLocation) = expectIdentifierWithLocation();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -621,6 +625,7 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction)
|
||||
}
|
||||
return nodeFactory.createNode<FunctionDefinition>(
|
||||
name,
|
||||
nameLocation,
|
||||
header.visibility,
|
||||
header.stateMutability,
|
||||
_freeFunction,
|
||||
@@ -640,7 +645,7 @@ ASTPointer<StructDefinition> Parser::parseStructDefinition()
|
||||
RecursionGuard recursionGuard(*this);
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
expectToken(Token::Struct);
|
||||
ASTPointer<ASTString> name = expectIdentifierToken();
|
||||
auto [name, nameLocation] = expectIdentifierWithLocation();
|
||||
vector<ASTPointer<VariableDeclaration>> members;
|
||||
expectToken(Token::LBrace);
|
||||
while (m_scanner->currentToken() != Token::RBrace)
|
||||
@@ -650,7 +655,7 @@ ASTPointer<StructDefinition> Parser::parseStructDefinition()
|
||||
}
|
||||
nodeFactory.markEndPosition();
|
||||
expectToken(Token::RBrace);
|
||||
return nodeFactory.createNode<StructDefinition>(name, members);
|
||||
return nodeFactory.createNode<StructDefinition>(move(name), move(nameLocation), move(members));
|
||||
}
|
||||
|
||||
ASTPointer<EnumValue> Parser::parseEnumValue()
|
||||
@@ -666,7 +671,7 @@ ASTPointer<EnumDefinition> Parser::parseEnumDefinition()
|
||||
RecursionGuard recursionGuard(*this);
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
expectToken(Token::Enum);
|
||||
ASTPointer<ASTString> name = expectIdentifierToken();
|
||||
auto [name, nameLocation] = expectIdentifierWithLocation();
|
||||
vector<ASTPointer<EnumValue>> members;
|
||||
expectToken(Token::LBrace);
|
||||
|
||||
@@ -684,7 +689,7 @@ ASTPointer<EnumDefinition> Parser::parseEnumDefinition()
|
||||
|
||||
nodeFactory.markEndPosition();
|
||||
expectToken(Token::RBrace);
|
||||
return nodeFactory.createNode<EnumDefinition>(name, members);
|
||||
return nodeFactory.createNode<EnumDefinition>(name, nameLocation, members);
|
||||
}
|
||||
|
||||
ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
@@ -717,6 +722,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
Visibility visibility(Visibility::Default);
|
||||
VariableDeclaration::Location location = VariableDeclaration::Location::Unspecified;
|
||||
ASTPointer<ASTString> identifier;
|
||||
SourceLocation nameLocation{};
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -795,7 +801,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
else
|
||||
{
|
||||
nodeFactory.markEndPosition();
|
||||
identifier = expectIdentifierToken();
|
||||
tie(identifier, nameLocation) = expectIdentifierWithLocation();
|
||||
}
|
||||
ASTPointer<Expression> value;
|
||||
if (_options.allowInitialValue)
|
||||
@@ -810,6 +816,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
return nodeFactory.createNode<VariableDeclaration>(
|
||||
type,
|
||||
identifier,
|
||||
nameLocation,
|
||||
value,
|
||||
visibility,
|
||||
documentation,
|
||||
@@ -830,7 +837,7 @@ ASTPointer<ModifierDefinition> Parser::parseModifierDefinition()
|
||||
ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation();
|
||||
|
||||
expectToken(Token::Modifier);
|
||||
ASTPointer<ASTString> name(expectIdentifierToken());
|
||||
auto [name, nameLocation] = expectIdentifierWithLocation();
|
||||
ASTPointer<ParameterList> parameters;
|
||||
if (m_scanner->currentToken() == Token::LParen)
|
||||
{
|
||||
@@ -875,7 +882,15 @@ ASTPointer<ModifierDefinition> Parser::parseModifierDefinition()
|
||||
else
|
||||
m_scanner->next(); // just consume the ';'
|
||||
|
||||
return nodeFactory.createNode<ModifierDefinition>(name, documentation, parameters, isVirtual, overrides, block);
|
||||
return nodeFactory.createNode<ModifierDefinition>(name, nameLocation, documentation, parameters, isVirtual, overrides, block);
|
||||
}
|
||||
|
||||
pair<ASTPointer<ASTString>, SourceLocation> Parser::expectIdentifierWithLocation()
|
||||
{
|
||||
SourceLocation nameLocation = currentLocation();
|
||||
ASTPointer<ASTString> name = expectIdentifierToken();
|
||||
|
||||
return {move(name), move(nameLocation)};
|
||||
}
|
||||
|
||||
ASTPointer<EventDefinition> Parser::parseEventDefinition()
|
||||
@@ -885,7 +900,7 @@ ASTPointer<EventDefinition> Parser::parseEventDefinition()
|
||||
ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation();
|
||||
|
||||
expectToken(Token::Event);
|
||||
ASTPointer<ASTString> name(expectIdentifierToken());
|
||||
auto [name, nameLocation] = expectIdentifierWithLocation();
|
||||
|
||||
VarDeclParserOptions options;
|
||||
options.allowIndexed = true;
|
||||
@@ -899,7 +914,7 @@ ASTPointer<EventDefinition> Parser::parseEventDefinition()
|
||||
}
|
||||
nodeFactory.markEndPosition();
|
||||
expectToken(Token::Semicolon);
|
||||
return nodeFactory.createNode<EventDefinition>(name, documentation, parameters, anonymous);
|
||||
return nodeFactory.createNode<EventDefinition>(name, nameLocation, documentation, parameters, anonymous);
|
||||
}
|
||||
|
||||
ASTPointer<UsingForDirective> Parser::parseUsingDirective()
|
||||
|
||||
Reference in New Issue
Block a user