mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Make annotations `SetOnce
or
optional
` where feasible
This commit is contained in:
parent
d80a81b01b
commit
dd81d05559
@ -51,6 +51,8 @@ bool hasEqualNameAndParameters(T const& _a, B const& _b)
|
|||||||
|
|
||||||
bool ContractLevelChecker::check(ContractDefinition const& _contract)
|
bool ContractLevelChecker::check(ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
|
_contract.annotation().unimplementedDeclarations = std::vector<Declaration const*>();
|
||||||
|
|
||||||
checkDuplicateFunctions(_contract);
|
checkDuplicateFunctions(_contract);
|
||||||
checkDuplicateEvents(_contract);
|
checkDuplicateEvents(_contract);
|
||||||
m_overrideChecker.check(_contract);
|
m_overrideChecker.check(_contract);
|
||||||
@ -210,9 +212,10 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c
|
|||||||
// Set to not fully implemented if at least one flag is false.
|
// Set to not fully implemented if at least one flag is false.
|
||||||
// Note that `_contract.annotation().unimplementedDeclarations` has already been
|
// Note that `_contract.annotation().unimplementedDeclarations` has already been
|
||||||
// pre-filled by `checkBaseConstructorArguments`.
|
// pre-filled by `checkBaseConstructorArguments`.
|
||||||
|
//
|
||||||
for (auto const& proxy: proxies)
|
for (auto const& proxy: proxies)
|
||||||
if (proxy.unimplemented())
|
if (proxy.unimplemented())
|
||||||
_contract.annotation().unimplementedDeclarations.push_back(proxy.declaration());
|
_contract.annotation().unimplementedDeclarations->push_back(proxy.declaration());
|
||||||
|
|
||||||
if (_contract.abstract())
|
if (_contract.abstract())
|
||||||
{
|
{
|
||||||
@ -229,17 +232,17 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c
|
|||||||
if (
|
if (
|
||||||
_contract.contractKind() == ContractKind::Contract &&
|
_contract.contractKind() == ContractKind::Contract &&
|
||||||
!_contract.abstract() &&
|
!_contract.abstract() &&
|
||||||
!_contract.annotation().unimplementedDeclarations.empty()
|
!_contract.annotation().unimplementedDeclarations->empty()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
SecondarySourceLocation ssl;
|
SecondarySourceLocation ssl;
|
||||||
for (auto declaration: _contract.annotation().unimplementedDeclarations)
|
for (auto declaration: *_contract.annotation().unimplementedDeclarations)
|
||||||
ssl.append("Missing implementation: ", declaration->location());
|
ssl.append("Missing implementation: ", declaration->location());
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
3656_error,
|
3656_error,
|
||||||
_contract.location(),
|
_contract.location(),
|
||||||
ssl,
|
ssl,
|
||||||
"Contract \"" + _contract.annotation().canonicalName + "\" should be marked as abstract."
|
"Contract \"" + *_contract.annotation().canonicalName + "\" should be marked as abstract."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,7 +292,7 @@ void ContractLevelChecker::checkBaseConstructorArguments(ContractDefinition cons
|
|||||||
if (FunctionDefinition const* constructor = contract->constructor())
|
if (FunctionDefinition const* constructor = contract->constructor())
|
||||||
if (contract != &_contract && !constructor->parameters().empty())
|
if (contract != &_contract && !constructor->parameters().empty())
|
||||||
if (!_contract.annotation().baseConstructorArguments.count(constructor))
|
if (!_contract.annotation().baseConstructorArguments.count(constructor))
|
||||||
_contract.annotation().unimplementedDeclarations.push_back(constructor);
|
_contract.annotation().unimplementedDeclarations->push_back(constructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContractLevelChecker::annotateBaseConstructorArguments(
|
void ContractLevelChecker::annotateBaseConstructorArguments(
|
||||||
|
@ -167,7 +167,7 @@ void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _va
|
|||||||
|
|
||||||
// If this is not an ordinary assignment, we write and read at the same time.
|
// If this is not an ordinary assignment, we write and read at the same time.
|
||||||
bool write = _expression.annotation().willBeWrittenTo;
|
bool write = _expression.annotation().willBeWrittenTo;
|
||||||
bool read = !_expression.annotation().willBeWrittenTo || !_expression.annotation().lValueOfOrdinaryAssignment;
|
bool read = !_expression.annotation().willBeWrittenTo || !*_expression.annotation().lValueOfOrdinaryAssignment;
|
||||||
if (write)
|
if (write)
|
||||||
{
|
{
|
||||||
if (!m_currentConstructor)
|
if (!m_currentConstructor)
|
||||||
|
@ -74,7 +74,7 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So
|
|||||||
for (auto const& node: _sourceUnit.nodes())
|
for (auto const& node: _sourceUnit.nodes())
|
||||||
if (auto imp = dynamic_cast<ImportDirective const*>(node.get()))
|
if (auto imp = dynamic_cast<ImportDirective const*>(node.get()))
|
||||||
{
|
{
|
||||||
string const& path = imp->annotation().absolutePath;
|
string const& path = *imp->annotation().absolutePath;
|
||||||
if (!_sourceUnits.count(path))
|
if (!_sourceUnits.count(path))
|
||||||
{
|
{
|
||||||
m_errorReporter.declarationError(
|
m_errorReporter.declarationError(
|
||||||
|
@ -185,7 +185,7 @@ bool StaticAnalyzer::visit(Return const& _return)
|
|||||||
|
|
||||||
bool StaticAnalyzer::visit(ExpressionStatement const& _statement)
|
bool StaticAnalyzer::visit(ExpressionStatement const& _statement)
|
||||||
{
|
{
|
||||||
if (_statement.expression().annotation().isPure)
|
if (*_statement.expression().annotation().isPure)
|
||||||
m_errorReporter.warning(
|
m_errorReporter.warning(
|
||||||
6133_error,
|
6133_error,
|
||||||
_statement.location(),
|
_statement.location(),
|
||||||
@ -287,7 +287,7 @@ bool StaticAnalyzer::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
bool StaticAnalyzer::visit(BinaryOperation const& _operation)
|
bool StaticAnalyzer::visit(BinaryOperation const& _operation)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
_operation.rightExpression().annotation().isPure &&
|
*_operation.rightExpression().annotation().isPure &&
|
||||||
(_operation.getOperator() == Token::Div || _operation.getOperator() == Token::Mod)
|
(_operation.getOperator() == Token::Div || _operation.getOperator() == Token::Mod)
|
||||||
)
|
)
|
||||||
if (auto rhs = dynamic_cast<RationalNumberType const*>(
|
if (auto rhs = dynamic_cast<RationalNumberType const*>(
|
||||||
@ -312,7 +312,7 @@ bool StaticAnalyzer::visit(FunctionCall const& _functionCall)
|
|||||||
if (functionType->kind() == FunctionType::Kind::AddMod || functionType->kind() == FunctionType::Kind::MulMod)
|
if (functionType->kind() == FunctionType::Kind::AddMod || functionType->kind() == FunctionType::Kind::MulMod)
|
||||||
{
|
{
|
||||||
solAssert(_functionCall.arguments().size() == 3, "");
|
solAssert(_functionCall.arguments().size() == 3, "");
|
||||||
if (_functionCall.arguments()[2]->annotation().isPure)
|
if (*_functionCall.arguments()[2]->annotation().isPure)
|
||||||
if (auto lastArg = dynamic_cast<RationalNumberType const*>(
|
if (auto lastArg = dynamic_cast<RationalNumberType const*>(
|
||||||
ConstantEvaluator(m_errorReporter).evaluate(*(_functionCall.arguments())[2])
|
ConstantEvaluator(m_errorReporter).evaluate(*(_functionCall.arguments())[2])
|
||||||
))
|
))
|
||||||
|
@ -538,7 +538,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
|||||||
|
|
||||||
if (!_variable.value())
|
if (!_variable.value())
|
||||||
m_errorReporter.typeError(4266_error, _variable.location(), "Uninitialized \"constant\" variable.");
|
m_errorReporter.typeError(4266_error, _variable.location(), "Uninitialized \"constant\" variable.");
|
||||||
else if (!_variable.value()->annotation().isPure)
|
else if (!*_variable.value()->annotation().isPure)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
8349_error,
|
8349_error,
|
||||||
_variable.value()->location(),
|
_variable.value()->location(),
|
||||||
@ -1296,11 +1296,14 @@ bool TypeChecker::visit(Conditional const& _conditional)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_conditional.annotation().isConstant = false;
|
||||||
_conditional.annotation().type = commonType;
|
_conditional.annotation().type = commonType;
|
||||||
_conditional.annotation().isPure =
|
_conditional.annotation().isPure =
|
||||||
_conditional.condition().annotation().isPure &&
|
*_conditional.condition().annotation().isPure &&
|
||||||
_conditional.trueExpression().annotation().isPure &&
|
*_conditional.trueExpression().annotation().isPure &&
|
||||||
_conditional.falseExpression().annotation().isPure;
|
*_conditional.falseExpression().annotation().isPure;
|
||||||
|
|
||||||
|
_conditional.annotation().isLValue = false;
|
||||||
|
|
||||||
if (_conditional.annotation().willBeWrittenTo)
|
if (_conditional.annotation().willBeWrittenTo)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
@ -1354,6 +1357,9 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
|||||||
);
|
);
|
||||||
TypePointer t = type(_assignment.leftHandSide());
|
TypePointer t = type(_assignment.leftHandSide());
|
||||||
_assignment.annotation().type = t;
|
_assignment.annotation().type = t;
|
||||||
|
_assignment.annotation().isPure = false;
|
||||||
|
_assignment.annotation().isLValue = false;
|
||||||
|
_assignment.annotation().isConstant = false;
|
||||||
|
|
||||||
checkExpressionAssignment(*t, _assignment.leftHandSide());
|
checkExpressionAssignment(*t, _assignment.leftHandSide());
|
||||||
|
|
||||||
@ -1401,6 +1407,7 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
|||||||
|
|
||||||
bool TypeChecker::visit(TupleExpression const& _tuple)
|
bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||||
{
|
{
|
||||||
|
_tuple.annotation().isConstant = false;
|
||||||
vector<ASTPointer<Expression>> const& components = _tuple.components();
|
vector<ASTPointer<Expression>> const& components = _tuple.components();
|
||||||
TypePointers types;
|
TypePointers types;
|
||||||
|
|
||||||
@ -1413,7 +1420,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
|||||||
{
|
{
|
||||||
requireLValue(
|
requireLValue(
|
||||||
*component,
|
*component,
|
||||||
_tuple.annotation().lValueOfOrdinaryAssignment
|
*_tuple.annotation().lValueOfOrdinaryAssignment
|
||||||
);
|
);
|
||||||
types.push_back(type(*component));
|
types.push_back(type(*component));
|
||||||
}
|
}
|
||||||
@ -1425,6 +1432,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
|||||||
_tuple.annotation().type = TypeProvider::tuple(move(types));
|
_tuple.annotation().type = TypeProvider::tuple(move(types));
|
||||||
// If some of the components are not LValues, the error is reported above.
|
// If some of the components are not LValues, the error is reported above.
|
||||||
_tuple.annotation().isLValue = true;
|
_tuple.annotation().isLValue = true;
|
||||||
|
_tuple.annotation().isPure = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1464,7 +1472,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
|||||||
else if (inlineArrayType)
|
else if (inlineArrayType)
|
||||||
inlineArrayType = Type::commonType(inlineArrayType, types[i]);
|
inlineArrayType = Type::commonType(inlineArrayType, types[i]);
|
||||||
}
|
}
|
||||||
if (!components[i]->annotation().isPure)
|
if (!*components[i]->annotation().isPure)
|
||||||
isPure = false;
|
isPure = false;
|
||||||
}
|
}
|
||||||
_tuple.annotation().isPure = isPure;
|
_tuple.annotation().isPure = isPure;
|
||||||
@ -1495,6 +1503,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
|||||||
_tuple.annotation().type = TypeProvider::tuple(move(types));
|
_tuple.annotation().type = TypeProvider::tuple(move(types));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_tuple.annotation().isLValue = false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1522,7 +1531,9 @@ bool TypeChecker::visit(UnaryOperation const& _operation)
|
|||||||
t = subExprType;
|
t = subExprType;
|
||||||
}
|
}
|
||||||
_operation.annotation().type = t;
|
_operation.annotation().type = t;
|
||||||
_operation.annotation().isPure = !modifying && _operation.subExpression().annotation().isPure;
|
_operation.annotation().isConstant = false;
|
||||||
|
_operation.annotation().isPure = !modifying && *_operation.subExpression().annotation().isPure;
|
||||||
|
_operation.annotation().isLValue = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1553,8 +1564,10 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
|
|||||||
TypeProvider::boolean() :
|
TypeProvider::boolean() :
|
||||||
commonType;
|
commonType;
|
||||||
_operation.annotation().isPure =
|
_operation.annotation().isPure =
|
||||||
_operation.leftExpression().annotation().isPure &&
|
*_operation.leftExpression().annotation().isPure &&
|
||||||
_operation.rightExpression().annotation().isPure;
|
*_operation.rightExpression().annotation().isPure;
|
||||||
|
_operation.annotation().isLValue = false;
|
||||||
|
_operation.annotation().isConstant = false;
|
||||||
|
|
||||||
if (_operation.getOperator() == Token::Exp || _operation.getOperator() == Token::SHL)
|
if (_operation.getOperator() == Token::Exp || _operation.getOperator() == Token::SHL)
|
||||||
{
|
{
|
||||||
@ -2174,7 +2187,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
for (ASTPointer<Expression const> const& argument: arguments)
|
for (ASTPointer<Expression const> const& argument: arguments)
|
||||||
{
|
{
|
||||||
argument->accept(*this);
|
argument->accept(*this);
|
||||||
if (!argument->annotation().isPure)
|
if (!*argument->annotation().isPure)
|
||||||
argumentsArePure = false;
|
argumentsArePure = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2197,6 +2210,9 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
// Determine function call kind and function type for this FunctionCall node
|
// Determine function call kind and function type for this FunctionCall node
|
||||||
FunctionCallAnnotation& funcCallAnno = _functionCall.annotation();
|
FunctionCallAnnotation& funcCallAnno = _functionCall.annotation();
|
||||||
FunctionTypePointer functionType = nullptr;
|
FunctionTypePointer functionType = nullptr;
|
||||||
|
funcCallAnno.isConstant = false;
|
||||||
|
|
||||||
|
bool isLValue = false;
|
||||||
|
|
||||||
// Determine and assign function call kind, lvalue, purity and function type for this FunctionCall node
|
// Determine and assign function call kind, lvalue, purity and function type for this FunctionCall node
|
||||||
switch (expressionType->category())
|
switch (expressionType->category())
|
||||||
@ -2208,7 +2224,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
// Purity for function calls also depends upon the callee and its FunctionType
|
// Purity for function calls also depends upon the callee and its FunctionType
|
||||||
funcCallAnno.isPure =
|
funcCallAnno.isPure =
|
||||||
argumentsArePure &&
|
argumentsArePure &&
|
||||||
_functionCall.expression().annotation().isPure &&
|
*_functionCall.expression().annotation().isPure &&
|
||||||
functionType &&
|
functionType &&
|
||||||
functionType->isPure();
|
functionType->isPure();
|
||||||
|
|
||||||
@ -2216,7 +2232,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
functionType->kind() == FunctionType::Kind::ArrayPush ||
|
functionType->kind() == FunctionType::Kind::ArrayPush ||
|
||||||
functionType->kind() == FunctionType::Kind::ByteArrayPush
|
functionType->kind() == FunctionType::Kind::ByteArrayPush
|
||||||
)
|
)
|
||||||
funcCallAnno.isLValue = functionType->parameterTypes().empty();
|
isLValue = functionType->parameterTypes().empty();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2236,13 +2252,11 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
);
|
);
|
||||||
functionType = dynamic_cast<StructType const&>(*actualType).constructorType();
|
functionType = dynamic_cast<StructType const&>(*actualType).constructorType();
|
||||||
funcCallAnno.kind = FunctionCallKind::StructConstructorCall;
|
funcCallAnno.kind = FunctionCallKind::StructConstructorCall;
|
||||||
funcCallAnno.isPure = argumentsArePure;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
funcCallAnno.kind = FunctionCallKind::TypeConversion;
|
funcCallAnno.kind = FunctionCallKind::TypeConversion;
|
||||||
funcCallAnno.isPure = argumentsArePure;
|
|
||||||
}
|
funcCallAnno.isPure = argumentsArePure;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2255,6 +2269,8 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
funcCallAnno.isLValue = isLValue;
|
||||||
|
|
||||||
// Determine return types
|
// Determine return types
|
||||||
switch (*funcCallAnno.kind)
|
switch (*funcCallAnno.kind)
|
||||||
{
|
{
|
||||||
@ -2325,6 +2341,9 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions)
|
|||||||
|
|
||||||
_functionCallOptions.expression().accept(*this);
|
_functionCallOptions.expression().accept(*this);
|
||||||
|
|
||||||
|
_functionCallOptions.annotation().isPure = false;
|
||||||
|
_functionCallOptions.annotation().isConstant = false;
|
||||||
|
|
||||||
auto expressionFunctionType = dynamic_cast<FunctionType const*>(type(_functionCallOptions.expression()));
|
auto expressionFunctionType = dynamic_cast<FunctionType const*>(type(_functionCallOptions.expression()));
|
||||||
if (!expressionFunctionType)
|
if (!expressionFunctionType)
|
||||||
{
|
{
|
||||||
@ -2455,6 +2474,8 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
|||||||
TypePointer type = _newExpression.typeName().annotation().type;
|
TypePointer type = _newExpression.typeName().annotation().type;
|
||||||
solAssert(!!type, "Type name not resolved.");
|
solAssert(!!type, "Type name not resolved.");
|
||||||
|
|
||||||
|
_newExpression.annotation().isConstant = false;
|
||||||
|
|
||||||
if (auto contractName = dynamic_cast<UserDefinedTypeName const*>(&_newExpression.typeName()))
|
if (auto contractName = dynamic_cast<UserDefinedTypeName const*>(&_newExpression.typeName()))
|
||||||
{
|
{
|
||||||
auto contract = dynamic_cast<ContractDefinition const*>(&dereference(*contractName));
|
auto contract = dynamic_cast<ContractDefinition const*>(&dereference(*contractName));
|
||||||
@ -2485,6 +2506,7 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_newExpression.annotation().type = FunctionType::newExpressionType(*contract);
|
_newExpression.annotation().type = FunctionType::newExpressionType(*contract);
|
||||||
|
_newExpression.annotation().isPure = false;
|
||||||
}
|
}
|
||||||
else if (type->category() == Type::Category::Array)
|
else if (type->category() == Type::Category::Array)
|
||||||
{
|
{
|
||||||
@ -2541,6 +2563,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
|
|
||||||
auto& annotation = _memberAccess.annotation();
|
auto& annotation = _memberAccess.annotation();
|
||||||
|
|
||||||
|
annotation.isConstant = false;
|
||||||
|
|
||||||
if (possibleMembers.empty())
|
if (possibleMembers.empty())
|
||||||
{
|
{
|
||||||
if (initialMemberCount == 0 && !dynamic_cast<ArraySliceType const*>(exprType))
|
if (initialMemberCount == 0 && !dynamic_cast<ArraySliceType const*>(exprType))
|
||||||
@ -2673,11 +2697,16 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
functionType &&
|
functionType &&
|
||||||
functionType->kind() == FunctionType::Kind::Declaration
|
functionType->kind() == FunctionType::Kind::Declaration
|
||||||
)
|
)
|
||||||
annotation.isPure = _memberAccess.expression().annotation().isPure;
|
annotation.isPure = *_memberAccess.expression().annotation().isPure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (exprType->category() == Type::Category::Module)
|
else if (exprType->category() == Type::Category::Module)
|
||||||
annotation.isPure = _memberAccess.expression().annotation().isPure;
|
{
|
||||||
|
annotation.isPure = *_memberAccess.expression().annotation().isPure;
|
||||||
|
annotation.isLValue = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
annotation.isLValue = false;
|
||||||
|
|
||||||
// TODO some members might be pure, but for example `address(0x123).balance` is not pure
|
// TODO some members might be pure, but for example `address(0x123).balance` is not pure
|
||||||
// although every subexpression is, so leaving this limited for now.
|
// although every subexpression is, so leaving this limited for now.
|
||||||
@ -2693,11 +2722,14 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
)
|
)
|
||||||
if (auto const* parentAccess = dynamic_cast<MemberAccess const*>(&_memberAccess.expression()))
|
if (auto const* parentAccess = dynamic_cast<MemberAccess const*>(&_memberAccess.expression()))
|
||||||
{
|
{
|
||||||
annotation.isPure = parentAccess->expression().annotation().isPure;
|
bool isPure = *parentAccess->expression().annotation().isPure;
|
||||||
if (auto const* exprInt = dynamic_cast<Identifier const*>(&parentAccess->expression()))
|
if (auto const* exprInt = dynamic_cast<Identifier const*>(&parentAccess->expression()))
|
||||||
if (exprInt->name() == "this" || exprInt->name() == "super")
|
if (exprInt->name() == "this" || exprInt->name() == "super")
|
||||||
annotation.isPure = true;
|
isPure = true;
|
||||||
|
|
||||||
|
annotation.isPure = isPure;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto magicType = dynamic_cast<MagicType const*>(exprType))
|
if (auto magicType = dynamic_cast<MagicType const*>(exprType))
|
||||||
{
|
{
|
||||||
if (magicType->kind() == MagicType::Kind::ABI)
|
if (magicType->kind() == MagicType::Kind::ABI)
|
||||||
@ -2745,16 +2777,20 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
annotation.isPure = true;
|
annotation.isPure = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!annotation.isPure.set())
|
||||||
|
annotation.isPure = false;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeChecker::visit(IndexAccess const& _access)
|
bool TypeChecker::visit(IndexAccess const& _access)
|
||||||
{
|
{
|
||||||
|
_access.annotation().isConstant = false;
|
||||||
_access.baseExpression().accept(*this);
|
_access.baseExpression().accept(*this);
|
||||||
TypePointer baseType = type(_access.baseExpression());
|
TypePointer baseType = type(_access.baseExpression());
|
||||||
TypePointer resultType = nullptr;
|
TypePointer resultType = nullptr;
|
||||||
bool isLValue = false;
|
bool isLValue = false;
|
||||||
bool isPure = _access.baseExpression().annotation().isPure;
|
bool isPure = *_access.baseExpression().annotation().isPure;
|
||||||
Expression const* index = _access.indexExpression();
|
Expression const* index = _access.indexExpression();
|
||||||
switch (baseType->category())
|
switch (baseType->category())
|
||||||
{
|
{
|
||||||
@ -2856,7 +2892,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
|||||||
}
|
}
|
||||||
_access.annotation().type = resultType;
|
_access.annotation().type = resultType;
|
||||||
_access.annotation().isLValue = isLValue;
|
_access.annotation().isLValue = isLValue;
|
||||||
if (index && !index->annotation().isPure)
|
if (index && !*index->annotation().isPure)
|
||||||
isPure = false;
|
isPure = false;
|
||||||
_access.annotation().isPure = isPure;
|
_access.annotation().isPure = isPure;
|
||||||
|
|
||||||
@ -2865,21 +2901,22 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
|||||||
|
|
||||||
bool TypeChecker::visit(IndexRangeAccess const& _access)
|
bool TypeChecker::visit(IndexRangeAccess const& _access)
|
||||||
{
|
{
|
||||||
|
_access.annotation().isConstant = false;
|
||||||
_access.baseExpression().accept(*this);
|
_access.baseExpression().accept(*this);
|
||||||
|
|
||||||
bool isLValue = false; // TODO: set this correctly when implementing slices for memory and storage arrays
|
bool isLValue = false; // TODO: set this correctly when implementing slices for memory and storage arrays
|
||||||
bool isPure = _access.baseExpression().annotation().isPure;
|
bool isPure = *_access.baseExpression().annotation().isPure;
|
||||||
|
|
||||||
if (Expression const* start = _access.startExpression())
|
if (Expression const* start = _access.startExpression())
|
||||||
{
|
{
|
||||||
expectType(*start, *TypeProvider::uint256());
|
expectType(*start, *TypeProvider::uint256());
|
||||||
if (!start->annotation().isPure)
|
if (!*start->annotation().isPure)
|
||||||
isPure = false;
|
isPure = false;
|
||||||
}
|
}
|
||||||
if (Expression const* end = _access.endExpression())
|
if (Expression const* end = _access.endExpression())
|
||||||
{
|
{
|
||||||
expectType(*end, *TypeProvider::uint256());
|
expectType(*end, *TypeProvider::uint256());
|
||||||
if (!end->annotation().isPure)
|
if (!*end->annotation().isPure)
|
||||||
isPure = false;
|
isPure = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3022,20 +3059,22 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
|||||||
!!annotation.referencedDeclaration,
|
!!annotation.referencedDeclaration,
|
||||||
"Referenced declaration is null after overload resolution."
|
"Referenced declaration is null after overload resolution."
|
||||||
);
|
);
|
||||||
|
bool isConstant = false;
|
||||||
annotation.isLValue = annotation.referencedDeclaration->isLValue();
|
annotation.isLValue = annotation.referencedDeclaration->isLValue();
|
||||||
annotation.type = annotation.referencedDeclaration->type();
|
annotation.type = annotation.referencedDeclaration->type();
|
||||||
solAssert(annotation.type, "Declaration referenced before type could be determined.");
|
solAssert(annotation.type, "Declaration referenced before type could be determined.");
|
||||||
if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(annotation.referencedDeclaration))
|
if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(annotation.referencedDeclaration))
|
||||||
annotation.isPure = annotation.isConstant = variableDeclaration->isConstant();
|
annotation.isPure = isConstant = variableDeclaration->isConstant();
|
||||||
else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration))
|
else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration))
|
||||||
{
|
annotation.isPure = dynamic_cast<FunctionType const*>(annotation.type);
|
||||||
if (dynamic_cast<FunctionType const*>(annotation.type))
|
|
||||||
annotation.isPure = true;
|
|
||||||
}
|
|
||||||
else if (dynamic_cast<TypeType const*>(annotation.type))
|
else if (dynamic_cast<TypeType const*>(annotation.type))
|
||||||
annotation.isPure = true;
|
annotation.isPure = true;
|
||||||
else if (dynamic_cast<ModuleType const*>(annotation.type))
|
else if (dynamic_cast<ModuleType const*>(annotation.type))
|
||||||
annotation.isPure = true;
|
annotation.isPure = true;
|
||||||
|
else
|
||||||
|
annotation.isPure = false;
|
||||||
|
|
||||||
|
annotation.isConstant = isConstant;
|
||||||
|
|
||||||
// Check for deprecated function names.
|
// Check for deprecated function names.
|
||||||
// The check is done here for the case without an actual function call.
|
// The check is done here for the case without an actual function call.
|
||||||
@ -3076,6 +3115,8 @@ void TypeChecker::endVisit(ElementaryTypeNameExpression const& _expr)
|
|||||||
{
|
{
|
||||||
_expr.annotation().type = TypeProvider::typeType(TypeProvider::fromElementaryTypeName(_expr.type().typeName(), _expr.type().stateMutability()));
|
_expr.annotation().type = TypeProvider::typeType(TypeProvider::fromElementaryTypeName(_expr.type().typeName(), _expr.type().stateMutability()));
|
||||||
_expr.annotation().isPure = true;
|
_expr.annotation().isPure = true;
|
||||||
|
_expr.annotation().isLValue = false;
|
||||||
|
_expr.annotation().isConstant = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeChecker::endVisit(Literal const& _literal)
|
void TypeChecker::endVisit(Literal const& _literal)
|
||||||
@ -3131,6 +3172,8 @@ void TypeChecker::endVisit(Literal const& _literal)
|
|||||||
m_errorReporter.fatalTypeError(2826_error, _literal.location(), "Invalid literal value.");
|
m_errorReporter.fatalTypeError(2826_error, _literal.location(), "Invalid literal value.");
|
||||||
|
|
||||||
_literal.annotation().isPure = true;
|
_literal.annotation().isPure = true;
|
||||||
|
_literal.annotation().isLValue = false;
|
||||||
|
_literal.annotation().isConstant = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||||
@ -3215,11 +3258,11 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss
|
|||||||
_expression.annotation().lValueOfOrdinaryAssignment = _ordinaryAssignment;
|
_expression.annotation().lValueOfOrdinaryAssignment = _ordinaryAssignment;
|
||||||
_expression.accept(*this);
|
_expression.accept(*this);
|
||||||
|
|
||||||
if (_expression.annotation().isLValue)
|
if (*_expression.annotation().isLValue)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
|
auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
|
||||||
if (_expression.annotation().isConstant)
|
if (*_expression.annotation().isConstant)
|
||||||
return { 6520_error, "Cannot assign to a constant variable." };
|
return { 6520_error, "Cannot assign to a constant variable." };
|
||||||
|
|
||||||
if (auto indexAccess = dynamic_cast<IndexAccess const*>(&_expression))
|
if (auto indexAccess = dynamic_cast<IndexAccess const*>(&_expression))
|
||||||
|
@ -492,7 +492,7 @@ CallableDeclaration const* Scopable::functionOrModifierDefinition() const
|
|||||||
|
|
||||||
string Scopable::sourceUnitName() const
|
string Scopable::sourceUnitName() const
|
||||||
{
|
{
|
||||||
return sourceUnit().annotation().path;
|
return *sourceUnit().annotation().path;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclarationAnnotation& Declaration::annotation() const
|
DeclarationAnnotation& Declaration::annotation() const
|
||||||
|
@ -47,6 +47,7 @@ namespace solidity::frontend
|
|||||||
|
|
||||||
class Type;
|
class Type;
|
||||||
using TypePointer = Type const*;
|
using TypePointer = Type const*;
|
||||||
|
using namespace util;
|
||||||
|
|
||||||
struct ASTAnnotation
|
struct ASTAnnotation
|
||||||
{
|
{
|
||||||
@ -88,9 +89,9 @@ struct StructurallyDocumentedAnnotation
|
|||||||
struct SourceUnitAnnotation: ASTAnnotation
|
struct SourceUnitAnnotation: ASTAnnotation
|
||||||
{
|
{
|
||||||
/// The "absolute" (in the compiler sense) path of this source unit.
|
/// The "absolute" (in the compiler sense) path of this source unit.
|
||||||
std::string path;
|
SetOnce<std::string> path;
|
||||||
/// The exported symbols (all global symbols).
|
/// The exported symbols (all global symbols).
|
||||||
std::map<ASTString, std::vector<Declaration const*>> exportedSymbols;
|
SetOnce<std::map<ASTString, std::vector<Declaration const*>>> exportedSymbols;
|
||||||
/// Experimental features.
|
/// Experimental features.
|
||||||
std::set<ExperimentalFeature> experimentalFeatures;
|
std::set<ExperimentalFeature> experimentalFeatures;
|
||||||
};
|
};
|
||||||
@ -122,7 +123,7 @@ struct DeclarationAnnotation: ASTAnnotation, ScopableAnnotation
|
|||||||
struct ImportAnnotation: DeclarationAnnotation
|
struct ImportAnnotation: DeclarationAnnotation
|
||||||
{
|
{
|
||||||
/// The absolute path of the source unit to import.
|
/// The absolute path of the source unit to import.
|
||||||
std::string absolutePath;
|
SetOnce<std::string> absolutePath;
|
||||||
/// The actual source unit.
|
/// The actual source unit.
|
||||||
SourceUnit const* sourceUnit = nullptr;
|
SourceUnit const* sourceUnit = nullptr;
|
||||||
};
|
};
|
||||||
@ -130,7 +131,7 @@ struct ImportAnnotation: DeclarationAnnotation
|
|||||||
struct TypeDeclarationAnnotation: DeclarationAnnotation
|
struct TypeDeclarationAnnotation: DeclarationAnnotation
|
||||||
{
|
{
|
||||||
/// The name of this type, prefixed by proper namespaces if globally accessible.
|
/// The name of this type, prefixed by proper namespaces if globally accessible.
|
||||||
std::string canonicalName;
|
SetOnce<std::string> canonicalName;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StructDeclarationAnnotation: TypeDeclarationAnnotation
|
struct StructDeclarationAnnotation: TypeDeclarationAnnotation
|
||||||
@ -149,7 +150,7 @@ struct StructDeclarationAnnotation: TypeDeclarationAnnotation
|
|||||||
struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocumentedAnnotation
|
struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocumentedAnnotation
|
||||||
{
|
{
|
||||||
/// List of functions and modifiers without a body. Can also contain functions from base classes.
|
/// List of functions and modifiers without a body. Can also contain functions from base classes.
|
||||||
std::vector<Declaration const*> unimplementedDeclarations;
|
std::optional<std::vector<Declaration const*>> unimplementedDeclarations;
|
||||||
/// List of all (direct and indirect) base contracts in order from derived to
|
/// List of all (direct and indirect) base contracts in order from derived to
|
||||||
/// base, including the contract itself.
|
/// base, including the contract itself.
|
||||||
std::vector<ContractDefinition const*> linearizedBaseContracts;
|
std::vector<ContractDefinition const*> linearizedBaseContracts;
|
||||||
@ -243,16 +244,16 @@ struct ExpressionAnnotation: ASTAnnotation
|
|||||||
/// Inferred type of the expression.
|
/// Inferred type of the expression.
|
||||||
TypePointer type = nullptr;
|
TypePointer type = nullptr;
|
||||||
/// Whether the expression is a constant variable
|
/// Whether the expression is a constant variable
|
||||||
bool isConstant = false;
|
SetOnce<bool> isConstant;
|
||||||
/// Whether the expression is pure, i.e. compile-time constant.
|
/// Whether the expression is pure, i.e. compile-time constant.
|
||||||
bool isPure = false;
|
SetOnce<bool> isPure;
|
||||||
/// Whether it is an LValue (i.e. something that can be assigned to).
|
/// Whether it is an LValue (i.e. something that can be assigned to).
|
||||||
bool isLValue = false;
|
SetOnce<bool> isLValue;
|
||||||
/// Whether the expression is used in a context where the LValue is actually required.
|
/// Whether the expression is used in a context where the LValue is actually required.
|
||||||
bool willBeWrittenTo = false;
|
bool willBeWrittenTo = false;
|
||||||
/// Whether the expression is an lvalue that is only assigned.
|
/// Whether the expression is an lvalue that is only assigned.
|
||||||
/// Would be false for --, ++, delete, +=, -=, ....
|
/// Would be false for --, ++, delete, +=, -=, ....
|
||||||
bool lValueOfOrdinaryAssignment = false;
|
SetOnce<bool> lValueOfOrdinaryAssignment;
|
||||||
|
|
||||||
/// Types and - if given - names of arguments if the expr. is a function
|
/// Types and - if given - names of arguments if the expr. is a function
|
||||||
/// that is called, used for overload resolution
|
/// that is called, used for overload resolution
|
||||||
|
@ -39,10 +39,33 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity::langutil;
|
using namespace solidity::langutil;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename V, template<typename> typename C>
|
||||||
|
void addIfSet(std::vector<pair<string, Json::Value>>& _attributes, string const& _name, C<V> const& _value)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<C<V>, solidity::util::SetOnce<V>>)
|
||||||
|
{
|
||||||
|
if (!_value.set())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<C<V>, optional<V>>)
|
||||||
|
{
|
||||||
|
if (!_value.has_value())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_attributes.emplace_back(_name, *_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace solidity::frontend
|
namespace solidity::frontend
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -181,12 +204,14 @@ void ASTJsonConverter::appendExpressionAttributes(
|
|||||||
{
|
{
|
||||||
std::vector<pair<string, Json::Value>> exprAttributes = {
|
std::vector<pair<string, Json::Value>> exprAttributes = {
|
||||||
make_pair("typeDescriptions", typePointerToJson(_annotation.type)),
|
make_pair("typeDescriptions", typePointerToJson(_annotation.type)),
|
||||||
make_pair("isConstant", _annotation.isConstant),
|
|
||||||
make_pair("isPure", _annotation.isPure),
|
|
||||||
make_pair("isLValue", _annotation.isLValue),
|
|
||||||
make_pair("lValueRequested", _annotation.willBeWrittenTo),
|
make_pair("lValueRequested", _annotation.willBeWrittenTo),
|
||||||
make_pair("argumentTypes", typePointerToJson(_annotation.arguments))
|
make_pair("argumentTypes", typePointerToJson(_annotation.arguments))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
addIfSet(exprAttributes, "isLValue", _annotation.isLValue);
|
||||||
|
addIfSet(exprAttributes, "isPure", _annotation.isPure);
|
||||||
|
addIfSet(exprAttributes, "isConstant", _annotation.isConstant);
|
||||||
|
|
||||||
_attributes += exprAttributes;
|
_attributes += exprAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,23 +239,27 @@ Json::Value ASTJsonConverter::toJson(ASTNode const& _node)
|
|||||||
|
|
||||||
bool ASTJsonConverter::visit(SourceUnit const& _node)
|
bool ASTJsonConverter::visit(SourceUnit const& _node)
|
||||||
{
|
{
|
||||||
Json::Value exportedSymbols = Json::objectValue;
|
std::vector<pair<string, Json::Value>> attributes = {
|
||||||
for (auto const& sym: _node.annotation().exportedSymbols)
|
make_pair("license", _node.licenseString() ? Json::Value(*_node.licenseString()) : Json::nullValue),
|
||||||
|
make_pair("nodes", toJson(_node.nodes()))
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_node.annotation().exportedSymbols.set())
|
||||||
{
|
{
|
||||||
exportedSymbols[sym.first] = Json::arrayValue;
|
Json::Value exportedSymbols = Json::objectValue;
|
||||||
for (Declaration const* overload: sym.second)
|
for (auto const& sym: *_node.annotation().exportedSymbols)
|
||||||
exportedSymbols[sym.first].append(nodeId(*overload));
|
|
||||||
}
|
|
||||||
setJsonNode(
|
|
||||||
_node,
|
|
||||||
"SourceUnit",
|
|
||||||
{
|
{
|
||||||
make_pair("absolutePath", _node.annotation().path),
|
exportedSymbols[sym.first] = Json::arrayValue;
|
||||||
make_pair("exportedSymbols", move(exportedSymbols)),
|
for (Declaration const* overload: sym.second)
|
||||||
make_pair("license", _node.licenseString() ? Json::Value(*_node.licenseString()) : Json::nullValue),
|
exportedSymbols[sym.first].append(nodeId(*overload));
|
||||||
make_pair("nodes", toJson(_node.nodes()))
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
attributes.emplace_back("exportedSymbols", exportedSymbols);
|
||||||
|
};
|
||||||
|
|
||||||
|
addIfSet(attributes, "absolutePath", _node.annotation().path);
|
||||||
|
|
||||||
|
setJsonNode(_node, "SourceUnit", std::move(attributes));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,10 +278,12 @@ bool ASTJsonConverter::visit(ImportDirective const& _node)
|
|||||||
{
|
{
|
||||||
std::vector<pair<string, Json::Value>> attributes = {
|
std::vector<pair<string, Json::Value>> attributes = {
|
||||||
make_pair("file", _node.path()),
|
make_pair("file", _node.path()),
|
||||||
make_pair("absolutePath", _node.annotation().absolutePath),
|
|
||||||
make_pair(m_legacy ? "SourceUnit" : "sourceUnit", nodeId(*_node.annotation().sourceUnit)),
|
make_pair(m_legacy ? "SourceUnit" : "sourceUnit", nodeId(*_node.annotation().sourceUnit)),
|
||||||
make_pair("scope", idOrNull(_node.scope()))
|
make_pair("scope", idOrNull(_node.scope()))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
addIfSet(attributes, "absolutePath", _node.annotation().absolutePath);
|
||||||
|
|
||||||
attributes.emplace_back("unitAlias", _node.name());
|
attributes.emplace_back("unitAlias", _node.name());
|
||||||
Json::Value symbolAliases(Json::arrayValue);
|
Json::Value symbolAliases(Json::arrayValue);
|
||||||
for (auto const& symbolAlias: _node.symbolAliases())
|
for (auto const& symbolAlias: _node.symbolAliases())
|
||||||
@ -270,18 +301,23 @@ bool ASTJsonConverter::visit(ImportDirective const& _node)
|
|||||||
|
|
||||||
bool ASTJsonConverter::visit(ContractDefinition const& _node)
|
bool ASTJsonConverter::visit(ContractDefinition const& _node)
|
||||||
{
|
{
|
||||||
setJsonNode(_node, "ContractDefinition", {
|
std::vector<pair<string, Json::Value>> attributes = {
|
||||||
make_pair("name", _node.name()),
|
make_pair("name", _node.name()),
|
||||||
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
||||||
make_pair("contractKind", contractKind(_node.contractKind())),
|
make_pair("contractKind", contractKind(_node.contractKind())),
|
||||||
make_pair("abstract", _node.abstract()),
|
make_pair("abstract", _node.abstract()),
|
||||||
make_pair("fullyImplemented", _node.annotation().unimplementedDeclarations.empty()),
|
|
||||||
make_pair("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)),
|
|
||||||
make_pair("baseContracts", toJson(_node.baseContracts())),
|
make_pair("baseContracts", toJson(_node.baseContracts())),
|
||||||
make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies, true)),
|
make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies, true)),
|
||||||
make_pair("nodes", toJson(_node.subNodes())),
|
make_pair("nodes", toJson(_node.subNodes())),
|
||||||
make_pair("scope", idOrNull(_node.scope()))
|
make_pair("scope", idOrNull(_node.scope()))
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (_node.annotation().unimplementedDeclarations.has_value())
|
||||||
|
attributes.emplace_back("fullyImplemented", _node.annotation().unimplementedDeclarations->empty());
|
||||||
|
if (!_node.annotation().linearizedBaseContracts.empty())
|
||||||
|
attributes.emplace_back("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts));
|
||||||
|
|
||||||
|
setJsonNode(_node, "ContractDefinition", std::move(attributes));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,23 +341,31 @@ bool ASTJsonConverter::visit(UsingForDirective const& _node)
|
|||||||
|
|
||||||
bool ASTJsonConverter::visit(StructDefinition const& _node)
|
bool ASTJsonConverter::visit(StructDefinition const& _node)
|
||||||
{
|
{
|
||||||
setJsonNode(_node, "StructDefinition", {
|
std::vector<pair<string, Json::Value>> attributes = {
|
||||||
make_pair("name", _node.name()),
|
make_pair("name", _node.name()),
|
||||||
make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
|
make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
|
||||||
make_pair("canonicalName", _node.annotation().canonicalName),
|
|
||||||
make_pair("members", toJson(_node.members())),
|
make_pair("members", toJson(_node.members())),
|
||||||
make_pair("scope", idOrNull(_node.scope()))
|
make_pair("scope", idOrNull(_node.scope()))
|
||||||
});
|
};
|
||||||
|
|
||||||
|
addIfSet(attributes,"canonicalName", _node.annotation().canonicalName);
|
||||||
|
|
||||||
|
setJsonNode(_node, "StructDefinition", std::move(attributes));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(EnumDefinition const& _node)
|
bool ASTJsonConverter::visit(EnumDefinition const& _node)
|
||||||
{
|
{
|
||||||
setJsonNode(_node, "EnumDefinition", {
|
std::vector<pair<string, Json::Value>> attributes = {
|
||||||
make_pair("name", _node.name()),
|
make_pair("name", _node.name()),
|
||||||
make_pair("canonicalName", _node.annotation().canonicalName),
|
|
||||||
make_pair("members", toJson(_node.members()))
|
make_pair("members", toJson(_node.members()))
|
||||||
});
|
};
|
||||||
|
|
||||||
|
addIfSet(attributes,"canonicalName", _node.annotation().canonicalName);
|
||||||
|
|
||||||
|
setJsonNode(_node, "EnumDefinition", std::move(attributes));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2109,7 +2109,7 @@ string ContractType::toString(bool) const
|
|||||||
|
|
||||||
string ContractType::canonicalName() const
|
string ContractType::canonicalName() const
|
||||||
{
|
{
|
||||||
return m_contract.annotation().canonicalName;
|
return *m_contract.annotation().canonicalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberList::MemberMap ContractType::nativeMembers(ASTNode const*) const
|
MemberList::MemberMap ContractType::nativeMembers(ASTNode const*) const
|
||||||
@ -2360,7 +2360,7 @@ bool StructType::containsNestedMapping() const
|
|||||||
|
|
||||||
string StructType::toString(bool _short) const
|
string StructType::toString(bool _short) const
|
||||||
{
|
{
|
||||||
string ret = "struct " + m_struct.annotation().canonicalName;
|
string ret = "struct " + *m_struct.annotation().canonicalName;
|
||||||
if (!_short)
|
if (!_short)
|
||||||
ret += " " + stringForReferencePart();
|
ret += " " + stringForReferencePart();
|
||||||
return ret;
|
return ret;
|
||||||
@ -2539,7 +2539,7 @@ string StructType::signatureInExternalFunction(bool _structsByName) const
|
|||||||
|
|
||||||
string StructType::canonicalName() const
|
string StructType::canonicalName() const
|
||||||
{
|
{
|
||||||
return m_struct.annotation().canonicalName;
|
return *m_struct.annotation().canonicalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionTypePointer StructType::constructorType() const
|
FunctionTypePointer StructType::constructorType() const
|
||||||
@ -2646,12 +2646,12 @@ unsigned EnumType::storageBytes() const
|
|||||||
|
|
||||||
string EnumType::toString(bool) const
|
string EnumType::toString(bool) const
|
||||||
{
|
{
|
||||||
return string("enum ") + m_enum.annotation().canonicalName;
|
return string("enum ") + *m_enum.annotation().canonicalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
string EnumType::canonicalName() const
|
string EnumType::canonicalName() const
|
||||||
{
|
{
|
||||||
return m_enum.annotation().canonicalName;
|
return *m_enum.annotation().canonicalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t EnumType::numberOfMembers() const
|
size_t EnumType::numberOfMembers() const
|
||||||
@ -3124,7 +3124,7 @@ string FunctionType::toString(bool _short) const
|
|||||||
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(m_declaration);
|
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(m_declaration);
|
||||||
solAssert(functionDefinition, "");
|
solAssert(functionDefinition, "");
|
||||||
if (auto const* contract = dynamic_cast<ContractDefinition const*>(functionDefinition->scope()))
|
if (auto const* contract = dynamic_cast<ContractDefinition const*>(functionDefinition->scope()))
|
||||||
name += contract->annotation().canonicalName + ".";
|
name += *contract->annotation().canonicalName + ".";
|
||||||
name += functionDefinition->name();
|
name += functionDefinition->name();
|
||||||
}
|
}
|
||||||
name += '(';
|
name += '(';
|
||||||
@ -3915,7 +3915,7 @@ bool ModuleType::operator==(Type const& _other) const
|
|||||||
MemberList::MemberMap ModuleType::nativeMembers(ASTNode const*) const
|
MemberList::MemberMap ModuleType::nativeMembers(ASTNode const*) const
|
||||||
{
|
{
|
||||||
MemberList::MemberMap symbols;
|
MemberList::MemberMap symbols;
|
||||||
for (auto const& symbolName: m_sourceUnit.annotation().exportedSymbols)
|
for (auto const& symbolName: *m_sourceUnit.annotation().exportedSymbols)
|
||||||
for (Declaration const* symbol: symbolName.second)
|
for (Declaration const* symbol: symbolName.second)
|
||||||
symbols.emplace_back(symbolName.first, symbol->type(), symbol);
|
symbols.emplace_back(symbolName.first, symbol->type(), symbol);
|
||||||
return symbols;
|
return symbols;
|
||||||
@ -3923,7 +3923,7 @@ MemberList::MemberMap ModuleType::nativeMembers(ASTNode const*) const
|
|||||||
|
|
||||||
string ModuleType::toString(bool) const
|
string ModuleType::toString(bool) const
|
||||||
{
|
{
|
||||||
return string("module \"") + m_sourceUnit.annotation().path + string("\"");
|
return string("module \"") + *m_sourceUnit.annotation().path + string("\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
string MagicType::richIdentifier() const
|
string MagicType::richIdentifier() const
|
||||||
|
@ -779,7 +779,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
solAssert(function.parameterTypes().size() == 1, "");
|
solAssert(function.parameterTypes().size() == 1, "");
|
||||||
if (m_context.revertStrings() == RevertStrings::Strip)
|
if (m_context.revertStrings() == RevertStrings::Strip)
|
||||||
{
|
{
|
||||||
if (!arguments.front()->annotation().isPure)
|
if (!*arguments.front()->annotation().isPure)
|
||||||
{
|
{
|
||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
utils().popStackElement(*arguments.front()->annotation().type);
|
utils().popStackElement(*arguments.front()->annotation().type);
|
||||||
@ -1078,7 +1078,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
solAssert(function.kind() == FunctionType::Kind::Require, "");
|
solAssert(function.kind() == FunctionType::Kind::Require, "");
|
||||||
if (m_context.revertStrings() == RevertStrings::Strip)
|
if (m_context.revertStrings() == RevertStrings::Strip)
|
||||||
{
|
{
|
||||||
if (!arguments.at(1)->annotation().isPure)
|
if (!*arguments.at(1)->annotation().isPure)
|
||||||
{
|
{
|
||||||
arguments.at(1)->accept(*this);
|
arguments.at(1)->accept(*this);
|
||||||
utils().popStackElement(*arguments.at(1)->annotation().type);
|
utils().popStackElement(*arguments.at(1)->annotation().type);
|
||||||
|
@ -1097,7 +1097,7 @@ void CompilerStack::resolveImports()
|
|||||||
for (ASTPointer<ASTNode> const& node: _source->ast->nodes())
|
for (ASTPointer<ASTNode> const& node: _source->ast->nodes())
|
||||||
if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
|
if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
|
||||||
{
|
{
|
||||||
string const& path = import->annotation().absolutePath;
|
string const& path = *import->annotation().absolutePath;
|
||||||
solAssert(m_sources.count(path), "");
|
solAssert(m_sources.count(path), "");
|
||||||
import->annotation().sourceUnit = m_sources[path].ast.get();
|
import->annotation().sourceUnit = m_sources[path].ast.get();
|
||||||
toposort(&m_sources[path]);
|
toposort(&m_sources[path]);
|
||||||
@ -1295,9 +1295,9 @@ string CompilerStack::createMetadata(Contract const& _contract) const
|
|||||||
|
|
||||||
/// All the source files (including self), which should be included in the metadata.
|
/// All the source files (including self), which should be included in the metadata.
|
||||||
set<string> referencedSources;
|
set<string> referencedSources;
|
||||||
referencedSources.insert(_contract.contract->sourceUnit().annotation().path);
|
referencedSources.insert(*_contract.contract->sourceUnit().annotation().path);
|
||||||
for (auto const sourceUnit: _contract.contract->sourceUnit().referencedSourceUnits(true))
|
for (auto const sourceUnit: _contract.contract->sourceUnit().referencedSourceUnits(true))
|
||||||
referencedSources.insert(sourceUnit->annotation().path);
|
referencedSources.insert(*sourceUnit->annotation().path);
|
||||||
|
|
||||||
meta["sources"] = Json::objectValue;
|
meta["sources"] = Json::objectValue;
|
||||||
for (auto const& s: m_sources)
|
for (auto const& s: m_sources)
|
||||||
@ -1363,7 +1363,7 @@ string CompilerStack::createMetadata(Contract const& _contract) const
|
|||||||
|
|
||||||
meta["settings"]["evmVersion"] = m_evmVersion.name();
|
meta["settings"]["evmVersion"] = m_evmVersion.name();
|
||||||
meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
|
meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
|
||||||
_contract.contract->annotation().canonicalName;
|
*_contract.contract->annotation().canonicalName;
|
||||||
|
|
||||||
meta["settings"]["remappings"] = Json::arrayValue;
|
meta["settings"]["remappings"] = Json::arrayValue;
|
||||||
set<string> remappings;
|
set<string> remappings;
|
||||||
|
@ -79,6 +79,8 @@ public:
|
|||||||
/// @throws BadSetOnceAccess when the stored value has not yet been set
|
/// @throws BadSetOnceAccess when the stored value has not yet been set
|
||||||
T const* operator->() const { return std::addressof(**this); }
|
T const* operator->() const { return std::addressof(**this); }
|
||||||
|
|
||||||
|
/// @return true if a value was assigned
|
||||||
|
bool set() const { return m_value.has_value(); }
|
||||||
private:
|
private:
|
||||||
std::optional<T> m_value = std::nullopt;
|
std::optional<T> m_value = std::nullopt;
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"baseContracts": [],
|
"baseContracts": [],
|
||||||
"contractDependencies": [],
|
"contractDependencies": [],
|
||||||
"contractKind": "contract",
|
"contractKind": "contract",
|
||||||
"fullyImplemented": true,
|
|
||||||
"id": 8,
|
"id": 8,
|
||||||
"linearizedBaseContracts":
|
"linearizedBaseContracts":
|
||||||
[
|
[
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
null
|
null
|
||||||
],
|
],
|
||||||
"contractKind": "contract",
|
"contractKind": "contract",
|
||||||
"fullyImplemented": true,
|
|
||||||
"linearizedBaseContracts":
|
"linearizedBaseContracts":
|
||||||
[
|
[
|
||||||
8
|
8
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"baseContracts": [],
|
"baseContracts": [],
|
||||||
"contractDependencies": [],
|
"contractDependencies": [],
|
||||||
"contractKind": "contract",
|
"contractKind": "contract",
|
||||||
"fullyImplemented": true,
|
|
||||||
"id": 6,
|
"id": 6,
|
||||||
"linearizedBaseContracts":
|
"linearizedBaseContracts":
|
||||||
[
|
[
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
null
|
null
|
||||||
],
|
],
|
||||||
"contractKind": "contract",
|
"contractKind": "contract",
|
||||||
"fullyImplemented": true,
|
|
||||||
"linearizedBaseContracts":
|
"linearizedBaseContracts":
|
||||||
[
|
[
|
||||||
6
|
6
|
||||||
|
@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(function_no_implementation)
|
|||||||
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
|
||||||
ContractDefinition* contract = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
ContractDefinition* contract = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||||
BOOST_REQUIRE(contract);
|
BOOST_REQUIRE(contract);
|
||||||
BOOST_CHECK(!contract->annotation().unimplementedDeclarations.empty());
|
BOOST_CHECK(!contract->annotation().unimplementedDeclarations->empty());
|
||||||
BOOST_CHECK(!contract->definedFunctions()[0]->isImplemented());
|
BOOST_CHECK(!contract->definedFunctions()[0]->isImplemented());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,10 +68,10 @@ BOOST_AUTO_TEST_CASE(abstract_contract)
|
|||||||
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||||
BOOST_REQUIRE(base);
|
BOOST_REQUIRE(base);
|
||||||
BOOST_CHECK(!base->annotation().unimplementedDeclarations.empty());
|
BOOST_CHECK(!base->annotation().unimplementedDeclarations->empty());
|
||||||
BOOST_CHECK(!base->definedFunctions()[0]->isImplemented());
|
BOOST_CHECK(!base->definedFunctions()[0]->isImplemented());
|
||||||
BOOST_REQUIRE(derived);
|
BOOST_REQUIRE(derived);
|
||||||
BOOST_CHECK(derived->annotation().unimplementedDeclarations.empty());
|
BOOST_CHECK(derived->annotation().unimplementedDeclarations->empty());
|
||||||
BOOST_CHECK(derived->definedFunctions()[0]->isImplemented());
|
BOOST_CHECK(derived->definedFunctions()[0]->isImplemented());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,9 +87,9 @@ BOOST_AUTO_TEST_CASE(abstract_contract_with_overload)
|
|||||||
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[1].get());
|
||||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||||
BOOST_REQUIRE(base);
|
BOOST_REQUIRE(base);
|
||||||
BOOST_CHECK(!base->annotation().unimplementedDeclarations.empty());
|
BOOST_CHECK(!base->annotation().unimplementedDeclarations->empty());
|
||||||
BOOST_REQUIRE(derived);
|
BOOST_REQUIRE(derived);
|
||||||
BOOST_CHECK(!derived->annotation().unimplementedDeclarations.empty());
|
BOOST_CHECK(!derived->annotation().unimplementedDeclarations->empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor)
|
BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor)
|
||||||
@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor)
|
|||||||
BOOST_CHECK_EQUAL(nodes.size(), 3);
|
BOOST_CHECK_EQUAL(nodes.size(), 3);
|
||||||
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
|
||||||
BOOST_REQUIRE(derived);
|
BOOST_REQUIRE(derived);
|
||||||
BOOST_CHECK(!derived->annotation().unimplementedDeclarations.empty());
|
BOOST_CHECK(!derived->annotation().unimplementedDeclarations->empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(function_canonical_signature)
|
BOOST_AUTO_TEST_CASE(function_canonical_signature)
|
||||||
|
@ -100,7 +100,7 @@ inline string appendVirtual(FunctionDefinition const& _function)
|
|||||||
|
|
||||||
void AbstractContract::endVisit(ContractDefinition const& _contract)
|
void AbstractContract::endVisit(ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
bool isFullyImplemented = _contract.annotation().unimplementedDeclarations.empty();
|
bool isFullyImplemented = _contract.annotation().unimplementedDeclarations->empty();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isFullyImplemented &&
|
!isFullyImplemented &&
|
||||||
|
Loading…
Reference in New Issue
Block a user