Merge remote-tracking branch 'origin/develop' into breaking

This commit is contained in:
chriseth
2020-06-30 18:56:51 +02:00
50 changed files with 701 additions and 40 deletions
@@ -32,6 +32,33 @@ using namespace solidity;
using namespace solidity::langutil;
using namespace solidity::frontend;
namespace
{
void copyMissingTags(StructurallyDocumentedAnnotation& _target, set<CallableDeclaration const*> const& _baseFunctions)
{
if (_baseFunctions.size() != 1)
return;
auto& sourceDoc = dynamic_cast<StructurallyDocumentedAnnotation const&>((*_baseFunctions.begin())->annotation());
set<string> existingTags;
for (auto const& iterator: _target.docTags)
existingTags.insert(iterator.first);
for (auto const& [tag, content]: sourceDoc.docTags)
if (tag != "inheritdoc" && !existingTags.count(tag))
_target.docTags.emplace(tag, content);
}
bool parameterNamesEqual(CallableDeclaration const& _a, CallableDeclaration const& _b)
{
return boost::range::equal(_a.parameters(), _b.parameters(), [](auto const& pa, auto const& pb) { return pa->name() == pb->name(); });
}
}
bool DocStringAnalyser::analyseDocStrings(SourceUnit const& _sourceUnit)
{
auto errorWatcher = m_errorReporter.errorWatcher();
@@ -65,7 +92,24 @@ bool DocStringAnalyser::visit(VariableDeclaration const& _variable)
if (_variable.isPublic())
parseDocStrings(_variable, _variable.annotation(), validPublicTags, "public state variables");
else
{
parseDocStrings(_variable, _variable.annotation(), validNonPublicTags, "non-public state variables");
if (_variable.annotation().docTags.count("notice") > 0)
m_errorReporter.warning(
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."
);
}
if (_variable.annotation().docTags.count("title") > 0 || _variable.annotation().docTags.count("author") > 0)
m_errorReporter.warning(
8532_error, _variable.documentation()->location(),
"Documentation tag @title and @author is only allowed on contract definitions. "
"It will be disallowed in 0.7.0."
);
if (_variable.annotation().docTags.empty())
copyMissingTags(_variable.annotation(), _variable.annotation().baseFunctions);
}
return false;
}
@@ -129,6 +173,20 @@ void DocStringAnalyser::handleCallable(
static set<string> const validTags = set<string>{"author", "dev", "notice", "return", "param"};
parseDocStrings(_node, _annotation, validTags, "functions");
checkParameters(_callable, _node, _annotation);
if (
_annotation.docTags.empty() &&
_callable.annotation().baseFunctions.size() == 1 &&
parameterNamesEqual(_callable, **_callable.annotation().baseFunctions.begin())
)
copyMissingTags(_annotation, _callable.annotation().baseFunctions);
if (_node.documentation() && _annotation.docTags.count("author") > 0)
m_errorReporter.warning(
9843_error, _node.documentation()->location(),
"Documentation tag @author is only allowed on contract definitions. "
"It will be disallowed in 0.7.0."
);
}
void DocStringAnalyser::parseDocStrings(
+1
View File
@@ -2084,6 +2084,7 @@ public:
{
None = static_cast<int>(Token::Illegal),
Wei = static_cast<int>(Token::SubWei),
Gwei = static_cast<int>(Token::SubGwei),
Szabo = static_cast<int>(Token::SubSzabo),
Finney = static_cast<int>(Token::SubFinney),
Ether = static_cast<int>(Token::SubEther),
+2
View File
@@ -1002,6 +1002,8 @@ Literal::SubDenomination ASTJsonImporter::subdenomination(Json::Value const& _no
if (subDenStr == "wei")
return Literal::SubDenomination::Wei;
else if (subDenStr == "gwei")
return Literal::SubDenomination::Gwei;
else if (subDenStr == "szabo")
return Literal::SubDenomination::Szabo;
else if (subDenStr == "finney")
+3
View File
@@ -889,6 +889,9 @@ tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal
case Literal::SubDenomination::Wei:
case Literal::SubDenomination::Second:
break;
case Literal::SubDenomination::Gwei:
value *= bigint("1000000000");
break;
case Literal::SubDenomination::Szabo:
value *= bigint("1000000000000");
break;
+5 -5
View File
@@ -307,11 +307,6 @@ bool CompilerStack::analyze()
if (source->ast && !syntaxChecker.checkSyntax(*source->ast))
noErrors = false;
DocStringAnalyser docStringAnalyser(m_errorReporter);
for (Source const* source: m_sourceOrder)
if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast))
noErrors = false;
m_globalContext = make_shared<GlobalContext>();
// We need to keep the same resolver during the whole process.
NameAndTypeResolver resolver(*m_globalContext, m_evmVersion, m_errorReporter);
@@ -367,6 +362,11 @@ bool CompilerStack::analyze()
if (!contractLevelChecker.check(*contract))
noErrors = false;
DocStringAnalyser docStringAnalyser(m_errorReporter);
for (Source const* source: m_sourceOrder)
if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast))
noErrors = false;
// New we run full type checks that go down to the expression level. This
// cannot be done earlier, because we need cross-contract types and information
// about whether a contract is abstract for the `new` expression.
+18
View File
@@ -36,6 +36,7 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
{
Json::Value doc;
Json::Value methods(Json::objectValue);
Json::Value events(Json::objectValue);
doc["version"] = Json::Value(c_natspecVersion);
doc["kind"] = Json::Value("user");
@@ -84,7 +85,17 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
}
}
}
for (auto const& event: _contractDef.events())
{
string value = extractDoc(event->annotation().docTags, "notice");
if (!value.empty())
events[event->functionType(true)->externalSignature()]["notice"] = value;
}
doc["methods"] = methods;
if (!events.empty())
doc["events"] = events;
return doc;
}
@@ -145,9 +156,16 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef)
stateVariables[varDecl->name()]["return"] = extractDoc(varDecl->annotation().docTags, "return");
}
Json::Value events(Json::objectValue);
for (auto const& event: _contractDef.events())
if (auto devDoc = devDocumentation(event->annotation().docTags); !devDoc.empty())
events[event->functionType(true)->externalSignature()] = devDoc;
doc["methods"] = methods;
if (!stateVariables.empty())
doc["stateVariables"] = stateVariables;
if (!events.empty())
doc["events"] = events;
return doc;
}
+7 -2
View File
@@ -1825,11 +1825,16 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());
break;
case Token::Number:
if (TokenTraits::isEtherSubdenomination(m_scanner->peekNextToken()))
if (
(m_scanner->peekNextToken() == Token::Identifier && m_scanner->peekLiteral() == "gwei") ||
TokenTraits::isEtherSubdenomination(m_scanner->peekNextToken())
)
{
ASTPointer<ASTString> literal = getLiteralAndAdvance();
nodeFactory.markEndPosition();
Literal::SubDenomination subdenomination = static_cast<Literal::SubDenomination>(m_scanner->currentToken());
Token actualToken = m_scanner->currentToken() == Token::Identifier ? Token::SubGwei : m_scanner->currentToken();
Literal::SubDenomination subdenomination = static_cast<Literal::SubDenomination>(actualToken);
m_scanner->next();
expression = nodeFactory.createNode<Literal>(token, literal, subdenomination);
}