From 27df07c4cee3a3c31d4d854162812552f7fd5550 Mon Sep 17 00:00:00 2001 From: wechman Date: Fri, 23 Sep 2022 13:35:38 +0200 Subject: [PATCH 1/3] TypeChecker: Minor simplifications for operators and `using for` --- libsolidity/analysis/TypeChecker.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 0e2cc6c34..2e81c6231 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1751,7 +1751,9 @@ bool TypeChecker::visit(UnaryOperation const& _operation) else _operation.annotation().type = result.get(); _operation.annotation().isConstant = false; - _operation.annotation().isPure = !modifying && *_operation.subExpression().annotation().isPure; + _operation.annotation().isPure = + !modifying && + *_operation.subExpression().annotation().isPure; _operation.annotation().isLValue = false; return false; @@ -3750,8 +3752,9 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor) solAssert(m_errorReporter.hasErrors()); return; } - solAssert(_usingFor.typeName()->annotation().type); - if (Declaration const* typeDefinition = _usingFor.typeName()->annotation().type->typeDefinition()) + Type const* usingForType = _usingFor.typeName()->annotation().type; + solAssert(usingForType); + if (Declaration const* typeDefinition = usingForType->typeDefinition()) { if (typeDefinition->scope() != m_currentSourceUnit) m_errorReporter.typeError( @@ -3785,10 +3788,12 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor) return; } - solAssert(_usingFor.typeName()->annotation().type); + Type const* usingForType = _usingFor.typeName()->annotation().type; + solAssert(usingForType); + Type const* normalizedType = TypeProvider::withLocationIfReference( DataLocation::Storage, - _usingFor.typeName()->annotation().type + usingForType ); solAssert(normalizedType); @@ -3824,7 +3829,7 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor) "The function \"{}\" cannot be bound to the type \"{}\" because the type cannot " "be implicitly converted to the first argument of the function (\"{}\"){}", joinHumanReadable(path->path(), "."), - _usingFor.typeName()->annotation().type->toString(true /* withoutDataLocation */), + usingForType->toString(true /* withoutDataLocation */), functionType->selfType()->humanReadableName(), result.message().empty() ? "." : ": " + result.message() ) From edb4bfa3985f29e42d97e85b559619ecd9d9411a Mon Sep 17 00:00:00 2001 From: wechman Date: Tue, 12 Jul 2022 12:00:23 +0200 Subject: [PATCH 2/3] ViewPureChecker: Extract reportFunctionCallMutability() helper from endVisit(FunctionCall) --- libsolidity/analysis/ViewPureChecker.cpp | 17 ++++++++++++----- libsolidity/analysis/ViewPureChecker.h | 2 ++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 7483af892..076430e13 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -323,16 +323,23 @@ ViewPureChecker::MutabilityAndLocation const& ViewPureChecker::modifierMutabilit return m_inferredMutability.at(&_modifier); } +void ViewPureChecker::reportFunctionCallMutability(StateMutability _mutability, langutil::SourceLocation const& _location) +{ + // We only require "nonpayable" to call a payable function. + if (_mutability == StateMutability::Payable) + _mutability = StateMutability::NonPayable; + reportMutability(_mutability, _location); +} + void ViewPureChecker::endVisit(FunctionCall const& _functionCall) { if (*_functionCall.annotation().kind != FunctionCallKind::FunctionCall) return; - StateMutability mutability = dynamic_cast(*_functionCall.expression().annotation().type).stateMutability(); - // We only require "nonpayable" to call a payble function. - if (mutability == StateMutability::Payable) - mutability = StateMutability::NonPayable; - reportMutability(mutability, _functionCall.location()); + reportFunctionCallMutability( + dynamic_cast(*_functionCall.expression().annotation().type).stateMutability(), + _functionCall.location() + ); } bool ViewPureChecker::visit(MemberAccess const& _memberAccess) diff --git a/libsolidity/analysis/ViewPureChecker.h b/libsolidity/analysis/ViewPureChecker.h index b0abe8fd8..6ba1384ce 100644 --- a/libsolidity/analysis/ViewPureChecker.h +++ b/libsolidity/analysis/ViewPureChecker.h @@ -73,6 +73,8 @@ private: std::optional const& _nestedLocation = {} ); + void reportFunctionCallMutability(StateMutability _mutability, langutil::SourceLocation const& _location); + /// Determines the mutability of modifier if not already cached. MutabilityAndLocation const& modifierMutability(ModifierDefinition const& _modifier); From 261e819df746ef650724f592f054d675c1da22a4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 1 Dec 2021 16:22:50 +0100 Subject: [PATCH 3/3] Type: Extract `usingForDirectivesForType()` helper --- libsolidity/ast/Types.cpp | 52 ++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 9c0179eda..5980f9366 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -337,7 +338,10 @@ Type const* Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c return encodingType; } -MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _scope) +namespace +{ + +vector usingForDirectivesForType(Type const& _type, ASTNode const& _scope) { vector usingForDirectives; SourceUnit const* sourceUnit = dynamic_cast(&_scope); @@ -362,6 +366,25 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _sc if (auto refType = dynamic_cast(&_type)) typeLocation = refType->location(); + return usingForDirectives | ranges::views::filter([&](UsingForDirective const* _directive) -> bool { + // Convert both types to pointers for comparison to see if the `using for` directive applies. + // Note that at this point we don't yet know if the functions are actually usable with the type. + // `_type` may not be convertible to the function parameter type. + return + !_directive->typeName() || + *TypeProvider::withLocationIfReference(typeLocation, &_type, true) == + *TypeProvider::withLocationIfReference( + typeLocation, + _directive->typeName()->annotation().type, + true + ); + }) | ranges::to>; +} + +} + +MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _scope) +{ MemberList::MemberMap members; set> seenFunctions; @@ -381,27 +404,11 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _sc members.emplace_back(&_function, asBoundFunction, *_name); }; - for (UsingForDirective const* ufd: usingForDirectives) - { - // Convert both types to pointers for comparison to see if the `using for` - // directive applies. - // Further down, we check more detailed for each function if `_type` is - // convertible to the function parameter type. - if ( - ufd->typeName() && - *TypeProvider::withLocationIfReference(typeLocation, &_type, true) != - *TypeProvider::withLocationIfReference( - typeLocation, - ufd->typeName()->annotation().type, - true - ) - ) - continue; - - for (auto const& pathPointer: ufd->functionsOrLibrary()) + for (UsingForDirective const* ufd: usingForDirectivesForType(_type, _scope)) + for (auto const& identifierPath: ufd->functionsOrLibrary()) { - solAssert(pathPointer); - Declaration const* declaration = pathPointer->annotation().referencedDeclaration; + solAssert(identifierPath); + Declaration const* declaration = identifierPath->annotation().referencedDeclaration; solAssert(declaration); if (ContractDefinition const* library = dynamic_cast(declaration)) @@ -417,10 +424,9 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _sc else addFunction( dynamic_cast(*declaration), - pathPointer->path().back() + identifierPath->path().back() ); } - } return members; }