mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user