Merge pull request #8998 from a3d4/partfix-5819-add-error-tags-to-declarationtypechecker

Add error IDs to DeclarationTypeChecker
This commit is contained in:
chriseth 2020-05-25 11:36:06 +02:00 committed by GitHub
commit 91aff43404
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 100 additions and 98 deletions

View File

@ -50,7 +50,8 @@ bool DeclarationTypeChecker::visit(ElementaryTypeName const& _typeName)
_typeName.annotation().type = TypeProvider::address(); _typeName.annotation().type = TypeProvider::address();
break; break;
default: default:
typeError( m_errorReporter.typeError(
2311_error,
_typeName.location(), _typeName.location(),
"Address types can only be payable or non-payable." "Address types can only be payable or non-payable."
); );
@ -102,7 +103,11 @@ bool DeclarationTypeChecker::visit(StructDefinition const& _struct)
auto visitor = [&](StructDefinition const& _struct, auto& _cycleDetector, size_t _depth) auto visitor = [&](StructDefinition const& _struct, auto& _cycleDetector, size_t _depth)
{ {
if (_depth >= 256) if (_depth >= 256)
fatalDeclarationError(_struct.location(), "Struct definition exhausts cyclic dependency validator."); m_errorReporter.fatalDeclarationError(
5651_error,
_struct.location(),
"Struct definition exhausts cyclic dependency validator."
);
for (ASTPointer<VariableDeclaration> const& member: _struct.members()) for (ASTPointer<VariableDeclaration> const& member: _struct.members())
{ {
@ -119,7 +124,7 @@ bool DeclarationTypeChecker::visit(StructDefinition const& _struct)
} }
}; };
if (util::CycleDetector<StructDefinition>(visitor).run(_struct) != nullptr) if (util::CycleDetector<StructDefinition>(visitor).run(_struct) != nullptr)
fatalTypeError(_struct.location(), "Recursive struct definition."); m_errorReporter.fatalTypeError(2046_error, _struct.location(), "Recursive struct definition.");
return false; return false;
} }
@ -145,9 +150,14 @@ void DeclarationTypeChecker::endVisit(UserDefinedTypeName const& _typeName)
else else
{ {
_typeName.annotation().type = TypeProvider::emptyTuple(); _typeName.annotation().type = TypeProvider::emptyTuple();
fatalTypeError(_typeName.location(), "Name has to refer to a struct, enum or contract."); m_errorReporter.fatalTypeError(
9755_error,
_typeName.location(),
"Name has to refer to a struct, enum or contract."
);
} }
} }
bool DeclarationTypeChecker::visit(FunctionTypeName const& _typeName) bool DeclarationTypeChecker::visit(FunctionTypeName const& _typeName)
{ {
if (_typeName.annotation().type) if (_typeName.annotation().type)
@ -165,18 +175,27 @@ bool DeclarationTypeChecker::visit(FunctionTypeName const& _typeName)
case Visibility::External: case Visibility::External:
break; break;
default: default:
fatalTypeError(_typeName.location(), "Invalid visibility, can only be \"external\" or \"internal\"."); m_errorReporter.fatalTypeError(
7653_error,
_typeName.location(),
"Invalid visibility, can only be \"external\" or \"internal\"."
);
return false; return false;
} }
if (_typeName.isPayable() && _typeName.visibility() != Visibility::External) if (_typeName.isPayable() && _typeName.visibility() != Visibility::External)
{ {
fatalTypeError(_typeName.location(), "Only external function types can be payable."); m_errorReporter.fatalTypeError(
6138_error,
_typeName.location(),
"Only external function types can be payable."
);
return false; return false;
} }
_typeName.annotation().type = TypeProvider::function(_typeName); _typeName.annotation().type = TypeProvider::function(_typeName);
return false; return false;
} }
void DeclarationTypeChecker::endVisit(Mapping const& _mapping) void DeclarationTypeChecker::endVisit(Mapping const& _mapping)
{ {
if (_mapping.annotation().type) if (_mapping.annotation().type)
@ -226,7 +245,11 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
return; return;
} }
if (baseType->storageBytes() == 0) if (baseType->storageBytes() == 0)
fatalTypeError(_typeName.baseType().location(), "Illegal base type of storage size zero for array."); m_errorReporter.fatalTypeError(
9390_error,
_typeName.baseType().location(),
"Illegal base type of storage size zero for array."
);
if (Expression const* length = _typeName.length()) if (Expression const* length = _typeName.length())
{ {
TypePointer& lengthTypeGeneric = length->annotation().type; TypePointer& lengthTypeGeneric = length->annotation().type;
@ -235,13 +258,17 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric); RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric);
u256 lengthValue = 0; u256 lengthValue = 0;
if (!lengthType || !lengthType->mobileType()) if (!lengthType || !lengthType->mobileType())
typeError(length->location(), "Invalid array length, expected integer literal or constant expression."); m_errorReporter.typeError(
8922_error,
length->location(),
"Invalid array length, expected integer literal or constant expression."
);
else if (lengthType->isZero()) else if (lengthType->isZero())
typeError(length->location(), "Array with zero length specified."); m_errorReporter.typeError(1220_error, length->location(), "Array with zero length specified.");
else if (lengthType->isFractional()) else if (lengthType->isFractional())
typeError(length->location(), "Array with fractional length specified."); m_errorReporter.typeError(4323_error, length->location(), "Array with fractional length specified.");
else if (lengthType->isNegative()) else if (lengthType->isNegative())
typeError(length->location(), "Array with negative length specified."); m_errorReporter.typeError(9308_error, length->location(), "Array with negative length specified.");
else else
lengthValue = lengthType->literalValue(nullptr); lengthValue = lengthType->literalValue(nullptr);
_typeName.annotation().type = TypeProvider::array(DataLocation::Storage, baseType, lengthValue); _typeName.annotation().type = TypeProvider::array(DataLocation::Storage, baseType, lengthValue);
@ -249,15 +276,24 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
else else
_typeName.annotation().type = TypeProvider::array(DataLocation::Storage, baseType); _typeName.annotation().type = TypeProvider::array(DataLocation::Storage, baseType);
} }
void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
{ {
if (_variable.annotation().type) if (_variable.annotation().type)
return; return;
if (_variable.isConstant() && !_variable.isStateVariable()) if (_variable.isConstant() && !_variable.isStateVariable())
m_errorReporter.declarationError(1788_error, _variable.location(), "The \"constant\" keyword can only be used for state variables."); m_errorReporter.declarationError(
1788_error,
_variable.location(),
"The \"constant\" keyword can only be used for state variables."
);
if (_variable.immutable() && !_variable.isStateVariable()) if (_variable.immutable() && !_variable.isStateVariable())
m_errorReporter.declarationError(8297_error, _variable.location(), "The \"immutable\" keyword can only be used for state variables."); m_errorReporter.declarationError(
8297_error,
_variable.location(),
"The \"immutable\" keyword can only be used for state variables."
);
if (!_variable.typeName()) if (!_variable.typeName())
{ {
@ -309,7 +345,7 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
errorString += " for variable"; errorString += " for variable";
} }
errorString += ", but " + locationToString(varLoc) + " was given."; errorString += ", but " + locationToString(varLoc) + " was given.";
typeError(_variable.location(), errorString); m_errorReporter.typeError(6160_error, _variable.location(), errorString);
solAssert(!allowedDataLocations.empty(), ""); solAssert(!allowedDataLocations.empty(), "");
varLoc = *allowedDataLocations.begin(); varLoc = *allowedDataLocations.begin();
@ -359,24 +395,9 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
} }
void DeclarationTypeChecker::typeError(SourceLocation const& _location, string const& _description)
{
m_errorReporter.typeError(2311_error, _location, _description);
}
void DeclarationTypeChecker::fatalTypeError(SourceLocation const& _location, string const& _description)
{
m_errorReporter.fatalTypeError(5651_error, _location, _description);
}
void DeclarationTypeChecker::fatalDeclarationError(SourceLocation const& _location, string const& _description)
{
m_errorReporter.fatalDeclarationError(2046_error, _location, _description);
}
bool DeclarationTypeChecker::check(ASTNode const& _node) bool DeclarationTypeChecker::check(ASTNode const& _node)
{ {
unsigned errorCount = m_errorReporter.errorCount(); auto watcher = m_errorReporter.errorWatcher();
_node.accept(*this); _node.accept(*this);
return m_errorReporter.errorCount() == errorCount; return watcher.ok();
} }

View File

@ -59,15 +59,6 @@ private:
void endVisit(VariableDeclaration const& _variable) override; void endVisit(VariableDeclaration const& _variable) override;
bool visit(StructDefinition const& _struct) override; bool visit(StructDefinition const& _struct) override;
/// Adds a new error to the list of errors.
void typeError(langutil::SourceLocation const& _location, std::string const& _description);
/// Adds a new error to the list of errors and throws to abort reference resolving.
void fatalTypeError(langutil::SourceLocation const& _location, std::string const& _description);
/// Adds a new error to the list of errors and throws to abort reference resolving.
void fatalDeclarationError(langutil::SourceLocation const& _location, std::string const& _description);
langutil::ErrorReporter& m_errorReporter; langutil::ErrorReporter& m_errorReporter;
langutil::EVMVersion m_evmVersion; langutil::EVMVersion m_evmVersion;
bool m_insideFunctionType = false; bool m_insideFunctionType = false;

View File

@ -68,14 +68,16 @@ bool DocStringAnalyser::visit(VariableDeclaration const& _variable)
parseDocStrings(_variable, _variable.annotation(), validPublicTags, "non-public state variables"); parseDocStrings(_variable, _variable.annotation(), validPublicTags, "non-public state variables");
if (_variable.annotation().docTags.count("notice") > 0) if (_variable.annotation().docTags.count("notice") > 0)
m_errorReporter.warning( m_errorReporter.warning(
9098_error, _variable.documentation()->location(), 7816_error, _variable.documentation()->location(),
"Documentation tag on non-public state variables will be disallowed in 0.7.0. You will need to use the @dev tag explicitly." "Documentation tag on non-public state variables will be disallowed in 0.7.0. "
"You will need to use the @dev tag explicitly."
); );
} }
if (_variable.annotation().docTags.count("title") > 0 || _variable.annotation().docTags.count("author") > 0) if (_variable.annotation().docTags.count("title") > 0 || _variable.annotation().docTags.count("author") > 0)
m_errorReporter.warning( m_errorReporter.warning(
4822_error, _variable.documentation()->location(), 8532_error, _variable.documentation()->location(),
"Documentation tag @title and @author is only allowed on contract definitions. It will be disallowed in 0.7.0." "Documentation tag @title and @author is only allowed on contract definitions. "
"It will be disallowed in 0.7.0."
); );
} }
return false; return false;
@ -110,7 +112,8 @@ void DocStringAnalyser::checkParameters(
auto paramRange = _annotation.docTags.equal_range("param"); auto paramRange = _annotation.docTags.equal_range("param");
for (auto i = paramRange.first; i != paramRange.second; ++i) for (auto i = paramRange.first; i != paramRange.second; ++i)
if (!validParams.count(i->second.paramName)) if (!validParams.count(i->second.paramName))
appendError( m_errorReporter.docstringParsingError(
3881_error,
_node.documentation()->location(), _node.documentation()->location(),
"Documented parameter \"" + "Documented parameter \"" +
i->second.paramName + i->second.paramName +
@ -159,7 +162,8 @@ void DocStringAnalyser::parseDocStrings(
for (auto const& docTag: _annotation.docTags) for (auto const& docTag: _annotation.docTags)
{ {
if (!_validTags.count(docTag.first)) if (!_validTags.count(docTag.first))
appendError( m_errorReporter.docstringParsingError(
6546_error,
_node.documentation()->location(), _node.documentation()->location(),
"Documentation tag @" + docTag.first + " not valid for " + _nodeName + "." "Documentation tag @" + docTag.first + " not valid for " + _nodeName + "."
); );
@ -170,12 +174,14 @@ void DocStringAnalyser::parseDocStrings(
if (auto* varDecl = dynamic_cast<VariableDeclaration const*>(&_node)) if (auto* varDecl = dynamic_cast<VariableDeclaration const*>(&_node))
{ {
if (!varDecl->isPublic()) if (!varDecl->isPublic())
appendError( m_errorReporter.docstringParsingError(
9440_error,
_node.documentation()->location(), _node.documentation()->location(),
"Documentation tag \"@" + docTag.first + "\" is only allowed on public state-variables." "Documentation tag \"@" + docTag.first + "\" is only allowed on public state-variables."
); );
if (returnTagsVisited > 1) if (returnTagsVisited > 1)
appendError( m_errorReporter.docstringParsingError(
5256_error,
_node.documentation()->location(), _node.documentation()->location(),
"Documentation tag \"@" + docTag.first + "\" is only allowed once on state-variables." "Documentation tag \"@" + docTag.first + "\" is only allowed once on state-variables."
); );
@ -186,7 +192,8 @@ void DocStringAnalyser::parseDocStrings(
string firstWord = content.substr(0, content.find_first_of(" \t")); string firstWord = content.substr(0, content.find_first_of(" \t"));
if (returnTagsVisited > function->returnParameters().size()) if (returnTagsVisited > function->returnParameters().size())
appendError( m_errorReporter.docstringParsingError(
2604_error,
_node.documentation()->location(), _node.documentation()->location(),
"Documentation tag \"@" + docTag.first + " " + docTag.second.content + "\"" + "Documentation tag \"@" + docTag.first + " " + docTag.second.content + "\"" +
" exceeds the number of return parameters." " exceeds the number of return parameters."
@ -195,7 +202,8 @@ void DocStringAnalyser::parseDocStrings(
{ {
auto parameter = function->returnParameters().at(returnTagsVisited - 1); auto parameter = function->returnParameters().at(returnTagsVisited - 1);
if (!parameter->name().empty() && parameter->name() != firstWord) if (!parameter->name().empty() && parameter->name() != firstWord)
appendError( m_errorReporter.docstringParsingError(
5856_error,
_node.documentation()->location(), _node.documentation()->location(),
"Documentation tag \"@" + docTag.first + " " + docTag.second.content + "\"" + "Documentation tag \"@" + docTag.first + " " + docTag.second.content + "\"" +
" does not contain the name of its return parameter." " does not contain the name of its return parameter."
@ -205,8 +213,3 @@ void DocStringAnalyser::parseDocStrings(
} }
} }
} }
void DocStringAnalyser::appendError(SourceLocation const& _location, string const& _description)
{
m_errorReporter.docstringParsingError(7816_error, _location, _description);
}

View File

@ -81,8 +81,6 @@ private:
std::string const& _nodeName std::string const& _nodeName
); );
void appendError(langutil::SourceLocation const& _location, std::string const& _description);
langutil::ErrorReporter& m_errorReporter; langutil::ErrorReporter& m_errorReporter;
}; };

View File

@ -119,7 +119,7 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
else else
errorMessage += " Did you mean " + std::move(suggestions) + "?"; errorMessage += " Did you mean " + std::move(suggestions) + "?";
} }
declarationError(_identifier.location(), errorMessage); m_errorReporter.declarationError(8051_error, _identifier.location(), errorMessage);
} }
else if (declarations.size() == 1) else if (declarations.size() == 1)
_identifier.annotation().referencedDeclaration = declarations.front(); _identifier.annotation().referencedDeclaration = declarations.front();
@ -157,7 +157,7 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath()); Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
if (!declaration) if (!declaration)
{ {
fatalDeclarationError(_typeName.location(), "Identifier not found or not unique."); m_errorReporter.fatalDeclarationError(7556_error, _typeName.location(), "Identifier not found or not unique.");
return; return;
} }
@ -209,14 +209,22 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
)); ));
if (realName.empty()) if (realName.empty())
{ {
declarationError(_identifier.location, "In variable names _slot and _offset can only be used as a suffix."); m_errorReporter.declarationError(
9553_error,
_identifier.location,
"In variable names _slot and _offset can only be used as a suffix."
);
return; return;
} }
declarations = m_resolver.nameFromCurrentScope(realName); declarations = m_resolver.nameFromCurrentScope(realName);
} }
if (declarations.size() > 1) if (declarations.size() > 1)
{ {
declarationError(_identifier.location, "Multiple matching identifiers. Resolving overloaded identifiers is not supported."); m_errorReporter.declarationError(
8827_error,
_identifier.location,
"Multiple matching identifiers. Resolving overloaded identifiers is not supported."
);
return; return;
} }
else if (declarations.size() == 0) else if (declarations.size() == 0)
@ -224,7 +232,11 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
if (auto var = dynamic_cast<VariableDeclaration const*>(declarations.front())) if (auto var = dynamic_cast<VariableDeclaration const*>(declarations.front()))
if (var->isLocalVariable() && m_yulInsideFunction) if (var->isLocalVariable() && m_yulInsideFunction)
{ {
declarationError(_identifier.location, "Cannot access local Solidity variables from inside an inline assembly function."); m_errorReporter.declarationError(
8477_error,
_identifier.location,
"Cannot access local Solidity variables from inside an inline assembly function."
);
return; return;
} }
@ -242,7 +254,11 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
string namePrefix = identifier.name.str().substr(0, identifier.name.str().find('.')); string namePrefix = identifier.name.str().substr(0, identifier.name.str().find('.'));
if (isSlot || isOffset) if (isSlot || isOffset)
declarationError(identifier.location, "In variable declarations _slot and _offset can not be used as a suffix."); m_errorReporter.declarationError(
8820_error,
identifier.location,
"In variable declarations _slot and _offset can not be used as a suffix."
);
else if ( else if (
auto declarations = m_resolver.nameFromCurrentScope(namePrefix); auto declarations = m_resolver.nameFromCurrentScope(namePrefix);
!declarations.empty() !declarations.empty()
@ -252,7 +268,8 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
for (auto const* decl: declarations) for (auto const* decl: declarations)
ssl.append("The shadowed declaration is here:", decl->location()); ssl.append("The shadowed declaration is here:", decl->location());
if (!ssl.infos.empty()) if (!ssl.infos.empty())
declarationError( m_errorReporter.declarationError(
6005_error,
identifier.location, identifier.location,
ssl, ssl,
namePrefix.size() < identifier.name.str().size() ? namePrefix.size() < identifier.name.str().size() ?
@ -266,19 +283,4 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
visit(*_varDecl.value); visit(*_varDecl.value);
} }
void ReferencesResolver::declarationError(SourceLocation const& _location, string const& _description)
{
m_errorReporter.declarationError(8532_error, _location, _description);
}
void ReferencesResolver::declarationError(SourceLocation const& _location, SecondarySourceLocation const& _ssl, string const& _description)
{
m_errorReporter.declarationError(3881_error, _location, _ssl, _description);
}
void ReferencesResolver::fatalDeclarationError(SourceLocation const& _location, string const& _description)
{
m_errorReporter.fatalDeclarationError(6546_error, _location, _description);
}
} }

View File

@ -88,15 +88,6 @@ private:
void operator()(yul::Identifier const& _identifier) override; void operator()(yul::Identifier const& _identifier) override;
void operator()(yul::VariableDeclaration const& _varDecl) override; void operator()(yul::VariableDeclaration const& _varDecl) override;
/// Adds a new error to the list of errors.
void declarationError(langutil::SourceLocation const& _location, std::string const& _description);
/// Adds a new error to the list of errors.
void declarationError(langutil::SourceLocation const& _location, langutil::SecondarySourceLocation const& _ssl, std::string const& _description);
/// Adds a new error to the list of errors and throws to abort reference resolving.
void fatalDeclarationError(langutil::SourceLocation const& _location, std::string const& _description);
langutil::ErrorReporter& m_errorReporter; langutil::ErrorReporter& m_errorReporter;
NameAndTypeResolver& m_resolver; NameAndTypeResolver& m_resolver;
langutil::EVMVersion m_evmVersion; langutil::EVMVersion m_evmVersion;

View File

@ -96,7 +96,10 @@ void DocStringParser::parse(string const& _docString, ErrorReporter& _errorRepor
auto tagNameEndPos = firstWhitespaceOrNewline(tagPos, end); auto tagNameEndPos = firstWhitespaceOrNewline(tagPos, end);
if (tagNameEndPos == end) if (tagNameEndPos == end)
{ {
appendError("End of tag " + string(tagPos, tagNameEndPos) + " not found"); m_errorReporter->docstringParsingError(
9222_error,
"End of tag " + string(tagPos, tagNameEndPos) + " not found"
);
break; break;
} }
@ -138,7 +141,7 @@ DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end)
auto nameStartPos = skipWhitespace(_pos, _end); auto nameStartPos = skipWhitespace(_pos, _end);
if (nameStartPos == _end) if (nameStartPos == _end)
{ {
appendError("No param name given"); m_errorReporter->docstringParsingError(3335_error, "No param name given");
return _end; return _end;
} }
auto nameEndPos = firstNonIdentifier(nameStartPos, _end); auto nameEndPos = firstNonIdentifier(nameStartPos, _end);
@ -149,7 +152,7 @@ DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end)
if (descStartPos == nlPos) if (descStartPos == nlPos)
{ {
appendError("No description given for param " + paramName); m_errorReporter->docstringParsingError(9942_error, "No description given for param " + paramName);
return _end; return _end;
} }
@ -189,8 +192,3 @@ void DocStringParser::newTag(string const& _tagName)
{ {
m_lastTag = &m_docTags.insert(make_pair(_tagName, DocTag()))->second; m_lastTag = &m_docTags.insert(make_pair(_tagName, DocTag()))->second;
} }
void DocStringParser::appendError(string const& _description)
{
m_errorReporter->docstringParsingError(9440_error, _description);
}

View File

@ -58,8 +58,6 @@ private:
/// Creates and inserts a new tag and adjusts m_lastTag. /// Creates and inserts a new tag and adjusts m_lastTag.
void newTag(std::string const& _tagName); void newTag(std::string const& _tagName);
void appendError(std::string const& _description);
/// Mapping tag name -> content. /// Mapping tag name -> content.
std::multimap<std::string, DocTag> m_docTags; std::multimap<std::string, DocTag> m_docTags;
DocTag* m_lastTag = nullptr; DocTag* m_lastTag = nullptr;