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:
parent
72c6932bf5
commit
32ba5f5ae7
@ -15,6 +15,7 @@ Bugfixes:
|
||||
|
||||
AST Changes:
|
||||
* Support field `documentation` to hold NatSpec comments above each statement.
|
||||
* Adds `nameLocation` to declarations to represent the exact location of the symbolic name.
|
||||
|
||||
### 0.8.1 (2021-01-27)
|
||||
|
||||
|
@ -34,9 +34,11 @@ SourceLocation const parseSourceLocation(std::string const& _input, std::string
|
||||
|
||||
boost::algorithm::split(pos, _input, boost::is_any_of(":"));
|
||||
|
||||
solAssert(pos.size() == 3, "SourceLocation string must have 3 colon separated numeric fields.");
|
||||
auto const sourceIndex = stoi(pos[Index]);
|
||||
|
||||
astAssert(
|
||||
pos.size() == 3 &&
|
||||
_maxIndex >= static_cast<size_t>(stoi(pos[Index])),
|
||||
sourceIndex == -1 || _maxIndex >= static_cast<size_t>(sourceIndex),
|
||||
"'src'-field ill-formatted or src-index too high"
|
||||
);
|
||||
|
||||
@ -44,7 +46,9 @@ SourceLocation const parseSourceLocation(std::string const& _input, std::string
|
||||
int end = start + stoi(pos[Length]);
|
||||
|
||||
// ASSUMPTION: only the name of source is used from here on, the m_source of the CharStream-Object can be empty
|
||||
std::shared_ptr<langutil::CharStream> source = std::make_shared<langutil::CharStream>("", _sourceName);
|
||||
std::shared_ptr<langutil::CharStream> source;
|
||||
if (sourceIndex != -1)
|
||||
source = std::make_shared<langutil::CharStream>("", _sourceName);
|
||||
|
||||
return SourceLocation{start, end, source};
|
||||
}
|
||||
|
@ -244,12 +244,14 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> _name,
|
||||
SourceLocation _nameLocation,
|
||||
Visibility _visibility = Visibility::Default
|
||||
):
|
||||
ASTNode(_id, _location), m_name(std::move(_name)), m_visibility(_visibility) {}
|
||||
ASTNode(_id, _location), m_name(std::move(_name)), m_nameLocation(std::move(_nameLocation)), m_visibility(_visibility) {}
|
||||
|
||||
/// @returns the declared name.
|
||||
ASTString const& name() const { return *m_name; }
|
||||
SourceLocation const& nameLocation() const noexcept { return m_nameLocation; }
|
||||
bool noVisibilitySpecified() const { return m_visibility == Visibility::Default; }
|
||||
Visibility visibility() const { return m_visibility == Visibility::Default ? defaultVisibility() : m_visibility; }
|
||||
bool isPublic() const { return visibility() >= Visibility::Public; }
|
||||
@ -287,6 +289,7 @@ protected:
|
||||
|
||||
private:
|
||||
ASTPointer<ASTString> m_name;
|
||||
SourceLocation m_nameLocation;
|
||||
Visibility m_visibility;
|
||||
};
|
||||
|
||||
@ -345,9 +348,10 @@ public:
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> _path,
|
||||
ASTPointer<ASTString> const& _unitAlias,
|
||||
SourceLocation _unitAliasLocation,
|
||||
SymbolAliasList _symbolAliases
|
||||
):
|
||||
Declaration(_id, _location, _unitAlias),
|
||||
Declaration(_id, _location, _unitAlias, std::move(_unitAliasLocation)),
|
||||
m_path(std::move(_path)),
|
||||
m_symbolAliases(move(_symbolAliases))
|
||||
{ }
|
||||
@ -477,13 +481,14 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
SourceLocation _nameLocation,
|
||||
ASTPointer<StructuredDocumentation> const& _documentation,
|
||||
std::vector<ASTPointer<InheritanceSpecifier>> _baseContracts,
|
||||
std::vector<ASTPointer<ASTNode>> _subNodes,
|
||||
ContractKind _contractKind = ContractKind::Contract,
|
||||
bool _abstract = false
|
||||
):
|
||||
Declaration(_id, _location, _name),
|
||||
Declaration(_id, _location, _name, std::move(_nameLocation)),
|
||||
StructurallyDocumented(_documentation),
|
||||
m_baseContracts(std::move(_baseContracts)),
|
||||
m_subNodes(std::move(_subNodes)),
|
||||
@ -643,9 +648,10 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
SourceLocation _nameLocation,
|
||||
std::vector<ASTPointer<VariableDeclaration>> _members
|
||||
):
|
||||
Declaration(_id, _location, _name), m_members(std::move(_members)) {}
|
||||
Declaration(_id, _location, _name, std::move(_nameLocation)), m_members(std::move(_members)) {}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@ -670,9 +676,10 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
SourceLocation _nameLocation,
|
||||
std::vector<ASTPointer<EnumValue>> _members
|
||||
):
|
||||
Declaration(_id, _location, _name), m_members(std::move(_members)) {}
|
||||
Declaration(_id, _location, _name, std::move(_nameLocation)), m_members(std::move(_members)) {}
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
@ -696,7 +703,7 @@ class EnumValue: public Declaration
|
||||
{
|
||||
public:
|
||||
EnumValue(int64_t _id, SourceLocation const& _location, ASTPointer<ASTString> const& _name):
|
||||
Declaration(_id, _location, _name) {}
|
||||
Declaration(_id, _location, _name, _location) {}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
@ -738,13 +745,14 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
SourceLocation _nameLocation,
|
||||
Visibility _visibility,
|
||||
ASTPointer<ParameterList> _parameters,
|
||||
bool _isVirtual = false,
|
||||
ASTPointer<OverrideSpecifier> _overrides = nullptr,
|
||||
ASTPointer<ParameterList> _returnParameters = ASTPointer<ParameterList>()
|
||||
):
|
||||
Declaration(_id, _location, _name, _visibility),
|
||||
Declaration(_id, _location, _name, std::move(_nameLocation), _visibility),
|
||||
m_parameters(std::move(_parameters)),
|
||||
m_overrides(std::move(_overrides)),
|
||||
m_returnParameters(std::move(_returnParameters)),
|
||||
@ -815,6 +823,7 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
SourceLocation const& _nameLocation,
|
||||
Visibility _visibility,
|
||||
StateMutability _stateMutability,
|
||||
bool _free,
|
||||
@ -827,7 +836,7 @@ public:
|
||||
ASTPointer<ParameterList> const& _returnParameters,
|
||||
ASTPointer<Block> const& _body
|
||||
):
|
||||
CallableDeclaration(_id, _location, _name, _visibility, _parameters, _isVirtual, _overrides, _returnParameters),
|
||||
CallableDeclaration(_id, _location, _name, std::move(_nameLocation), _visibility, _parameters, _isVirtual, _overrides, _returnParameters),
|
||||
StructurallyDocumented(_documentation),
|
||||
ImplementationOptional(_body != nullptr),
|
||||
m_stateMutability(_stateMutability),
|
||||
@ -928,6 +937,7 @@ public:
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<TypeName> _type,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
SourceLocation _nameLocation,
|
||||
ASTPointer<Expression> _value,
|
||||
Visibility _visibility,
|
||||
ASTPointer<StructuredDocumentation> const _documentation = nullptr,
|
||||
@ -936,7 +946,7 @@ public:
|
||||
ASTPointer<OverrideSpecifier> _overrides = nullptr,
|
||||
Location _referenceLocation = Location::Unspecified
|
||||
):
|
||||
Declaration(_id, _location, _name, _visibility),
|
||||
Declaration(_id, _location, _name, std::move(_nameLocation), _visibility),
|
||||
StructurallyDocumented(std::move(_documentation)),
|
||||
m_typeName(std::move(_type)),
|
||||
m_value(std::move(_value)),
|
||||
@ -1033,13 +1043,14 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
SourceLocation _nameLocation,
|
||||
ASTPointer<StructuredDocumentation> const& _documentation,
|
||||
ASTPointer<ParameterList> const& _parameters,
|
||||
bool _isVirtual,
|
||||
ASTPointer<OverrideSpecifier> const& _overrides,
|
||||
ASTPointer<Block> const& _body
|
||||
):
|
||||
CallableDeclaration(_id, _location, _name, Visibility::Internal, _parameters, _isVirtual, _overrides),
|
||||
CallableDeclaration(_id, _location, _name, std::move(_nameLocation), Visibility::Internal, _parameters, _isVirtual, _overrides),
|
||||
StructurallyDocumented(_documentation),
|
||||
ImplementationOptional(_body != nullptr),
|
||||
m_body(_body)
|
||||
@ -1108,11 +1119,12 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
SourceLocation _nameLocation,
|
||||
ASTPointer<StructuredDocumentation> const& _documentation,
|
||||
ASTPointer<ParameterList> const& _parameters,
|
||||
bool _anonymous = false
|
||||
):
|
||||
CallableDeclaration(_id, _location, _name, Visibility::Default, _parameters),
|
||||
CallableDeclaration(_id, _location, _name, std::move(_nameLocation), Visibility::Default, _parameters),
|
||||
StructurallyDocumented(_documentation),
|
||||
m_anonymous(_anonymous)
|
||||
{
|
||||
@ -1151,7 +1163,7 @@ class MagicVariableDeclaration: public Declaration
|
||||
{
|
||||
public:
|
||||
MagicVariableDeclaration(int _id, ASTString const& _name, Type const* _type):
|
||||
Declaration(_id, SourceLocation(), std::make_shared<ASTString>(_name)), m_type(_type) { }
|
||||
Declaration(_id, SourceLocation(), std::make_shared<ASTString>(_name), {}), m_type(_type) { }
|
||||
|
||||
void accept(ASTVisitor&) override
|
||||
{
|
||||
|
@ -107,21 +107,21 @@ void ASTJsonConverter::setJsonNode(
|
||||
m_currentValue[e.first] = std::move(e.second);
|
||||
}
|
||||
|
||||
size_t ASTJsonConverter::sourceIndexFromLocation(SourceLocation const& _location) const
|
||||
optional<size_t> ASTJsonConverter::sourceIndexFromLocation(SourceLocation const& _location) const
|
||||
{
|
||||
if (_location.source && m_sourceIndices.count(_location.source->name()))
|
||||
return m_sourceIndices.at(_location.source->name());
|
||||
else
|
||||
return numeric_limits<size_t>::max();
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) const
|
||||
{
|
||||
size_t sourceIndex = sourceIndexFromLocation(_location);
|
||||
optional<size_t> sourceIndexOpt = sourceIndexFromLocation(_location);
|
||||
int length = -1;
|
||||
if (_location.start >= 0 && _location.end >= 0)
|
||||
length = _location.end - _location.start;
|
||||
return to_string(_location.start) + ":" + to_string(length) + ":" + to_string(sourceIndex);
|
||||
return to_string(_location.start) + ":" + to_string(length) + ":" + (sourceIndexOpt.has_value() ? to_string(sourceIndexOpt.value()) : "-1");
|
||||
}
|
||||
|
||||
string ASTJsonConverter::namePathToString(std::vector<ASTString> const& _namePath)
|
||||
@ -243,6 +243,8 @@ bool ASTJsonConverter::visit(ImportDirective const& _node)
|
||||
addIfSet(attributes, "absolutePath", _node.annotation().absolutePath);
|
||||
|
||||
attributes.emplace_back("unitAlias", _node.name());
|
||||
attributes.emplace_back("nameLocation", Json::Value(sourceLocationToString(_node.nameLocation())));
|
||||
|
||||
Json::Value symbolAliases(Json::arrayValue);
|
||||
for (auto const& symbolAlias: _node.symbolAliases())
|
||||
{
|
||||
@ -250,6 +252,7 @@ bool ASTJsonConverter::visit(ImportDirective const& _node)
|
||||
solAssert(symbolAlias.symbol, "");
|
||||
tuple["foreign"] = toJson(*symbolAlias.symbol);
|
||||
tuple["local"] = symbolAlias.alias ? Json::Value(*symbolAlias.alias) : Json::nullValue;
|
||||
tuple["nameLocation"] = sourceLocationToString(_node.nameLocation());
|
||||
symbolAliases.append(tuple);
|
||||
}
|
||||
attributes.emplace_back("symbolAliases", std::move(symbolAliases));
|
||||
@ -261,6 +264,7 @@ bool ASTJsonConverter::visit(ContractDefinition const& _node)
|
||||
{
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
||||
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
||||
make_pair("contractKind", contractKind(_node.contractKind())),
|
||||
make_pair("abstract", _node.abstract()),
|
||||
@ -310,6 +314,7 @@ bool ASTJsonConverter::visit(StructDefinition const& _node)
|
||||
{
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
||||
make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
|
||||
make_pair("members", toJson(_node.members())),
|
||||
make_pair("scope", idOrNull(_node.scope()))
|
||||
@ -326,6 +331,7 @@ bool ASTJsonConverter::visit(EnumDefinition const& _node)
|
||||
{
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
||||
make_pair("members", toJson(_node.members()))
|
||||
};
|
||||
|
||||
@ -339,7 +345,8 @@ bool ASTJsonConverter::visit(EnumDefinition const& _node)
|
||||
bool ASTJsonConverter::visit(EnumValue const& _node)
|
||||
{
|
||||
setJsonNode(_node, "EnumValue", {
|
||||
make_pair("name", _node.name())
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
@ -364,6 +371,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
|
||||
{
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
||||
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
||||
make_pair("kind", _node.isFree() ? "freeFunction" : TokenTraits::toString(_node.kind())),
|
||||
make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())),
|
||||
@ -401,6 +409,7 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node)
|
||||
{
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
||||
make_pair("typeName", toJson(_node.typeName())),
|
||||
make_pair("constant", _node.isConstant()),
|
||||
make_pair("mutability", VariableDeclaration::mutabilityToString(_node.mutability())),
|
||||
@ -428,6 +437,7 @@ bool ASTJsonConverter::visit(ModifierDefinition const& _node)
|
||||
{
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
||||
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
||||
make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
|
||||
make_pair("parameters", toJson(_node.parameterList())),
|
||||
@ -455,6 +465,7 @@ bool ASTJsonConverter::visit(EventDefinition const& _node)
|
||||
m_inEvent = true;
|
||||
setJsonNode(_node, "EventDefinition", {
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
||||
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
||||
make_pair("parameters", toJson(_node.parameterList())),
|
||||
make_pair("anonymous", _node.isAnonymous())
|
||||
|
@ -137,7 +137,8 @@ private:
|
||||
std::string const& _nodeName,
|
||||
std::vector<std::pair<std::string, Json::Value>>&& _attributes
|
||||
);
|
||||
size_t sourceIndexFromLocation(langutil::SourceLocation const& _location) const;
|
||||
/// Maps source location to an index, if source is valid and a mapping does exist, otherwise returns std::nullopt.
|
||||
std::optional<size_t> sourceIndexFromLocation(langutil::SourceLocation const& _location) const;
|
||||
std::string sourceLocationToString(langutil::SourceLocation const& _location) const;
|
||||
static std::string namePathToString(std::vector<ASTString> const& _namePath);
|
||||
static Json::Value idOrNull(ASTNode const* _pt)
|
||||
|
@ -99,6 +99,13 @@ SourceLocation const ASTJsonImporter::createSourceLocation(Json::Value const& _n
|
||||
return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, m_sourceLocations.size());
|
||||
}
|
||||
|
||||
SourceLocation ASTJsonImporter::createNameSourceLocation(Json::Value const& _node)
|
||||
{
|
||||
astAssert(member(_node, "nameLocation").isString(), "'nameLocation' must be a string");
|
||||
|
||||
return solidity::langutil::parseSourceLocation(_node["nameLocation"].asString(), m_currentSourceName, m_sourceLocations.size());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
ASTPointer<T> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _node)
|
||||
{
|
||||
@ -272,6 +279,7 @@ ASTPointer<ImportDirective> ASTJsonImporter::createImportDirective(Json::Value c
|
||||
_node,
|
||||
path,
|
||||
unitAlias,
|
||||
createNameSourceLocation(_node),
|
||||
move(symbolAliases)
|
||||
);
|
||||
|
||||
@ -298,6 +306,7 @@ ASTPointer<ContractDefinition> ASTJsonImporter::createContractDefinition(Json::V
|
||||
return createASTNode<ContractDefinition>(
|
||||
_node,
|
||||
make_shared<ASTString>(_node["name"].asString()),
|
||||
createNameSourceLocation(_node),
|
||||
_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
|
||||
baseContracts,
|
||||
subNodes,
|
||||
@ -352,6 +361,7 @@ ASTPointer<ASTNode> ASTJsonImporter::createStructDefinition(Json::Value const& _
|
||||
return createASTNode<StructDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
createNameSourceLocation(_node),
|
||||
members
|
||||
);
|
||||
}
|
||||
@ -364,6 +374,7 @@ ASTPointer<EnumDefinition> ASTJsonImporter::createEnumDefinition(Json::Value con
|
||||
return createASTNode<EnumDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
createNameSourceLocation(_node),
|
||||
members
|
||||
);
|
||||
}
|
||||
@ -434,6 +445,7 @@ ASTPointer<FunctionDefinition> ASTJsonImporter::createFunctionDefinition(Json::V
|
||||
return createASTNode<FunctionDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
createNameSourceLocation(_node),
|
||||
vis,
|
||||
stateMutability(_node),
|
||||
freeFunction,
|
||||
@ -475,6 +487,7 @@ ASTPointer<VariableDeclaration> ASTJsonImporter::createVariableDeclaration(Json:
|
||||
_node,
|
||||
nullOrCast<TypeName>(member(_node, "typeName")),
|
||||
make_shared<ASTString>(member(_node, "name").asString()),
|
||||
createNameSourceLocation(_node),
|
||||
nullOrCast<Expression>(member(_node, "value")),
|
||||
visibility(_node),
|
||||
_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
|
||||
@ -490,6 +503,7 @@ ASTPointer<ModifierDefinition> ASTJsonImporter::createModifierDefinition(Json::V
|
||||
return createASTNode<ModifierDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
createNameSourceLocation(_node),
|
||||
_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
|
||||
createParameterList(member(_node, "parameters")),
|
||||
memberAsBool(_node, "virtual"),
|
||||
@ -515,6 +529,7 @@ ASTPointer<EventDefinition> ASTJsonImporter::createEventDefinition(Json::Value c
|
||||
return createASTNode<EventDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
createNameSourceLocation(_node),
|
||||
_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
|
||||
createParameterList(member(_node, "parameters")),
|
||||
memberAsBool(_node, "anonymous")
|
||||
|
@ -67,6 +67,7 @@ private:
|
||||
template<class T>
|
||||
ASTPointer<T> convertJsonToASTNode(Json::Value const& _node);
|
||||
|
||||
langutil::SourceLocation createNameSourceLocation(Json::Value const& _node);
|
||||
|
||||
/// \defgroup nodeCreators JSON to AST-Nodes
|
||||
///@{
|
||||
|
@ -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()
|
||||
|
@ -151,6 +151,7 @@ private:
|
||||
std::vector<ASTPointer<Expression>> parseFunctionCallListArguments();
|
||||
std::pair<std::vector<ASTPointer<Expression>>, std::vector<ASTPointer<ASTString>>> parseFunctionCallArguments();
|
||||
std::pair<std::vector<ASTPointer<Expression>>, std::vector<ASTPointer<ASTString>>> parseNamedArguments();
|
||||
std::pair<ASTPointer<ASTString>, langutil::SourceLocation> expectIdentifierWithLocation();
|
||||
///@}
|
||||
|
||||
///@{
|
||||
|
@ -187,7 +187,7 @@ Json::Value AsmJsonConverter::createAstNode(langutil::SourceLocation const& _loc
|
||||
int length = -1;
|
||||
if (_location.start >= 0 && _location.end >= 0)
|
||||
length = _location.end - _location.start;
|
||||
ret["src"] = to_string(_location.start) + ":" + to_string(length) + ":" + m_sourceIndex;
|
||||
ret["src"] = to_string(_location.start) + ":" + to_string(length) + ":" + (m_sourceIndex.has_value() ? to_string(m_sourceIndex.value()) : "-1");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <liblangutil/SourceLocation.h>
|
||||
#include <json/json.h>
|
||||
#include <boost/variant.hpp>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace solidity::yul
|
||||
@ -40,7 +41,7 @@ class AsmJsonConverter: public boost::static_visitor<Json::Value>
|
||||
public:
|
||||
/// Create a converter to JSON for any block of inline assembly
|
||||
/// @a _sourceIndex to be used to abbreviate source name in the source locations
|
||||
explicit AsmJsonConverter(size_t _sourceIndex): m_sourceIndex(std::to_string(_sourceIndex)) {}
|
||||
explicit AsmJsonConverter(std::optional<size_t> _sourceIndex): m_sourceIndex(_sourceIndex) {}
|
||||
|
||||
Json::Value operator()(Block const& _node) const;
|
||||
Json::Value operator()(TypedName const& _node) const;
|
||||
@ -65,7 +66,7 @@ private:
|
||||
template <class T>
|
||||
Json::Value vectorOfVariantsToJson(std::vector<T> const& vec) const;
|
||||
|
||||
std::string const m_sourceIndex;
|
||||
std::optional<size_t> const m_sourceIndex;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ JSON AST (compact format):
|
||||
18
|
||||
],
|
||||
"name": "Error1",
|
||||
"nameLocation": "71:6:0",
|
||||
"nodeType": "ContractDefinition",
|
||||
"nodes":
|
||||
[
|
||||
@ -59,6 +60,7 @@ JSON AST (compact format):
|
||||
"kind": "constructor",
|
||||
"modifiers": [],
|
||||
"name": "",
|
||||
"nameLocation": "-1:-1:-1",
|
||||
"nodeType": "FunctionDefinition",
|
||||
"parameters":
|
||||
{
|
||||
@ -120,6 +122,7 @@ JSON AST (compact format):
|
||||
"kind": "function",
|
||||
"modifiers": [],
|
||||
"name": "five",
|
||||
"nameLocation": "407:4:0",
|
||||
"nodeType": "FunctionDefinition",
|
||||
"parameters":
|
||||
{
|
||||
@ -139,6 +142,7 @@ JSON AST (compact format):
|
||||
"id": 12,
|
||||
"mutability": "mutable",
|
||||
"name": "",
|
||||
"nameLocation": "-1:-1:-1",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 17,
|
||||
"src": "434:4:0",
|
||||
|
@ -10,4 +10,4 @@
|
||||
2 | pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ }
|
||||
| ^
|
||||
|
||||
","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0"}],"src":"36:84:0"},"id":0}}}
|
||||
","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nameLocation":"68:7:0","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0"}],"src":"36:84:0"},"id":0}}}
|
||||
|
@ -1 +1 @@
|
||||
{"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"C":[6]},"id":7,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":6,"linearizedBaseContracts":[6],"name":"C","nodeType":"ContractDefinition","nodes":[{"body":{"id":4,"nodeType":"Block","src":"97:2:0","statements":[]},"functionSelector":"26121ff0","id":5,"implemented":true,"kind":"function","modifiers":[],"name":"f","nodeType":"FunctionDefinition","parameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"82:2:0"},"returnParameters":{"id":3,"nodeType":"ParameterList","parameters":[],"src":"97:0:0"},"scope":6,"src":"72:27:0","stateMutability":"pure","virtual":false,"visibility":"public"}],"scope":7,"src":"59:42:0"}],"src":"36:65:0"},"id":0}}}
|
||||
{"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"C":[6]},"id":7,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":6,"linearizedBaseContracts":[6],"name":"C","nameLocation":"68:1:0","nodeType":"ContractDefinition","nodes":[{"body":{"id":4,"nodeType":"Block","src":"97:2:0","statements":[]},"functionSelector":"26121ff0","id":5,"implemented":true,"kind":"function","modifiers":[],"name":"f","nameLocation":"81:1:0","nodeType":"FunctionDefinition","parameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"82:2:0"},"returnParameters":{"id":3,"nodeType":"ParameterList","parameters":[],"src":"97:0:0"},"scope":6,"src":"72:27:0","stateMutability":"pure","virtual":false,"visibility":"public"}],"scope":7,"src":"59:42:0"}],"src":"36:65:0"},"id":0}}}
|
||||
|
@ -179,15 +179,15 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
|
||||
TypePointer multiArray = TypeProvider::array(DataLocation::Storage, stringArray);
|
||||
BOOST_CHECK_EQUAL(multiArray->identifier(), "t_array$_t_array$_t_string_storage_$20_storage_$dyn_storage_ptr");
|
||||
|
||||
ContractDefinition c(++id, SourceLocation{}, make_shared<string>("MyContract$"), {}, {}, {}, ContractKind::Contract);
|
||||
ContractDefinition c(++id, SourceLocation{}, make_shared<string>("MyContract$"), SourceLocation{}, {}, {}, {}, ContractKind::Contract);
|
||||
BOOST_CHECK_EQUAL(c.type()->identifier(), "t_type$_t_contract$_MyContract$$$_$2_$");
|
||||
BOOST_CHECK_EQUAL(ContractType(c, true).identifier(), "t_super$_MyContract$$$_$2");
|
||||
|
||||
StructDefinition s(++id, {}, make_shared<string>("Struct"), {});
|
||||
StructDefinition s(++id, {}, make_shared<string>("Struct"), {}, {});
|
||||
s.annotation().recursive = false;
|
||||
BOOST_CHECK_EQUAL(s.type()->identifier(), "t_type$_t_struct$_Struct_$3_storage_ptr_$");
|
||||
|
||||
EnumDefinition e(++id, {}, make_shared<string>("Enum"), {});
|
||||
EnumDefinition e(++id, {}, make_shared<string>("Enum"), {}, {});
|
||||
BOOST_CHECK_EQUAL(e.type()->identifier(), "t_type$_t_enum$_Enum_$4_$");
|
||||
|
||||
TupleType t({e.type(), s.type(), stringArray, nullptr});
|
||||
@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
|
||||
// TypeType is tested with contract
|
||||
|
||||
auto emptyParams = make_shared<ParameterList>(++id, SourceLocation(), std::vector<ASTPointer<VariableDeclaration>>());
|
||||
ModifierDefinition mod(++id, SourceLocation{}, make_shared<string>("modif"), {}, emptyParams, {}, {}, {});
|
||||
ModifierDefinition mod(++id, SourceLocation{}, make_shared<string>("modif"), SourceLocation{}, {}, emptyParams, {}, {}, {});
|
||||
BOOST_CHECK_EQUAL(ModifierType(mod).identifier(), "t_modifier$__$");
|
||||
|
||||
SourceUnit su(++id, {}, {}, {});
|
||||
|
Loading…
Reference in New Issue
Block a user