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:
Christian Parpart
2021-02-10 18:13:09 +01:00
committed by chriseth
parent 72c6932bf5
commit 32ba5f5ae7
15 changed files with 112 additions and 46 deletions
+31 -16
View File
@@ -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()