diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/DeclarationContainer.cpp | 13 | ||||
-rw-r--r-- | libsolidity/analysis/NameAndTypeResolver.cpp | 54 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 19 | ||||
-rw-r--r-- | libsolidity/ast/AST.cpp | 72 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 13 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 42 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 31 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.h | 5 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 6 |
9 files changed, 220 insertions, 35 deletions
diff --git a/libsolidity/analysis/DeclarationContainer.cpp b/libsolidity/analysis/DeclarationContainer.cpp index 1599b83a..f8c12c5b 100644 --- a/libsolidity/analysis/DeclarationContainer.cpp +++ b/libsolidity/analysis/DeclarationContainer.cpp @@ -44,10 +44,19 @@ Declaration const* DeclarationContainer::conflictingDeclaration( if (dynamic_cast<FunctionDefinition const*>(&_declaration)) { - // check that all other declarations with the same name are functions + // check that all other declarations with the same name are functions or a public state variable for (Declaration const* declaration: declarations) - if (!dynamic_cast<FunctionDefinition const*>(declaration)) + { + if (dynamic_cast<FunctionDefinition const*>(declaration)) + continue; + if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(declaration)) + { + if (variableDeclaration->isStateVariable() && !variableDeclaration->isConstant() && variableDeclaration->isPublic()) + continue; return declaration; + } + return declaration; + } } else if (declarations.size() == 1 && declarations.front() == &_declaration) return nullptr; diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 2a33a501..08323243 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -260,10 +260,16 @@ vector<Declaration const*> NameAndTypeResolver::cleanedDeclarations( for (auto it = _declarations.begin(); it != _declarations.end(); ++it) { solAssert(*it, ""); - // the declaration is functionDefinition while declarations > 1 - FunctionDefinition const& functionDefinition = dynamic_cast<FunctionDefinition const&>(**it); - FunctionType functionType(functionDefinition); - for (auto parameter: functionType.parameterTypes() + functionType.returnParameterTypes()) + // the declaration is functionDefinition or a VariableDeclaration while declarations > 1 + solAssert(dynamic_cast<FunctionDefinition const*>(*it) || dynamic_cast<VariableDeclaration const*>(*it), + "Found overloading involving something not a function or a variable"); + + shared_ptr<FunctionType const> functionType { (*it)->functionType(false) }; + if (!functionType) + functionType = (*it)->functionType(true); + solAssert(functionType, "failed to determine the function type of the overloaded"); + + for (auto parameter: functionType->parameterTypes() + functionType->returnParameterTypes()) if (!parameter) reportFatalDeclarationError(_identifier.location(), "Function type can not be used in this context"); @@ -272,8 +278,10 @@ vector<Declaration const*> NameAndTypeResolver::cleanedDeclarations( uniqueFunctions.end(), [&](Declaration const* d) { - FunctionType newFunctionType(dynamic_cast<FunctionDefinition const&>(*d)); - return functionType.hasEqualArgumentTypes(newFunctionType); + shared_ptr<FunctionType const> newFunctionType { d->functionType(false) }; + if (!newFunctionType) + newFunctionType = d->functionType(true); + return newFunctionType && functionType->hasEqualArgumentTypes(*newFunctionType); } )) uniqueFunctions.push_back(*it); @@ -289,7 +297,39 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base) for (auto const& declaration: nameAndDeclaration.second) // Import if it was declared in the base, is not the constructor and is visible in derived classes if (declaration->scope() == &_base && declaration->isVisibleInDerivedContracts()) - m_currentScope->registerDeclaration(*declaration); + if (!m_currentScope->registerDeclaration(*declaration)) + { + SourceLocation firstDeclarationLocation; + SourceLocation secondDeclarationLocation; + Declaration const* conflictingDeclaration = m_currentScope->conflictingDeclaration(*declaration); + solAssert(conflictingDeclaration, ""); + + // Usual shadowing is not an error + if (dynamic_cast<VariableDeclaration const*>(declaration) && dynamic_cast<VariableDeclaration const*>(conflictingDeclaration)) + continue; + + // Usual shadowing is not an error + if (dynamic_cast<ModifierDefinition const*>(declaration) && dynamic_cast<ModifierDefinition const*>(conflictingDeclaration)) + continue; + + if (declaration->location().start < conflictingDeclaration->location().start) + { + firstDeclarationLocation = declaration->location(); + secondDeclarationLocation = conflictingDeclaration->location(); + } + else + { + firstDeclarationLocation = conflictingDeclaration->location(); + secondDeclarationLocation = declaration->location(); + } + + reportDeclarationError( + secondDeclarationLocation, + "Identifier already declared.", + firstDeclarationLocation, + "The previous declaration is here:" + ); + } } void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index e414e27c..67c8ac17 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1500,8 +1500,23 @@ bool TypeChecker::visit(Identifier const& _identifier) if (!annotation.referencedDeclaration) { if (!annotation.argumentTypes) - fatalTypeError(_identifier.location(), "Unable to determine overloaded type."); - if (annotation.overloadedDeclarations.empty()) + { + // The identifier should be a public state variable shadowing other functions + vector<Declaration const*> candidates; + + for (Declaration const* declaration: annotation.overloadedDeclarations) + { + if (VariableDeclaration const* variableDeclaration = dynamic_cast<decltype(variableDeclaration)>(declaration)) + candidates.push_back(declaration); + } + if (candidates.empty()) + fatalTypeError(_identifier.location(), "No matching declaration found after variable lookup."); + else if (candidates.size() == 1) + annotation.referencedDeclaration = candidates.front(); + else + fatalTypeError(_identifier.location(), "No unique declaration found after variable lookup."); + } + else if (annotation.overloadedDeclarations.empty()) fatalTypeError(_identifier.location(), "No candidates for overload resolution found."); else if (annotation.overloadedDeclarations.size() == 1) annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin(); diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 3cd1dfbe..6f7a64dc 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -217,6 +217,9 @@ vector<Declaration const*> const& ContractDefinition::inheritableMembers() const for (EnumDefinition const* e: definedEnums()) addInheritableMember(e); + + for (EventDefinition const* e: events()) + addInheritableMember(e); } return *m_inheritableMembers; } @@ -271,6 +274,45 @@ TypeDeclarationAnnotation& EnumDefinition::annotation() const return static_cast<TypeDeclarationAnnotation&>(*m_annotation); } +shared_ptr<FunctionType> FunctionDefinition::functionType(bool _internal) const +{ + if (_internal) + { + switch (visibility()) + { + case Declaration::Visibility::Default: + solAssert(false, "visibility() should not return Default"); + case Declaration::Visibility::Private: + case Declaration::Visibility::Internal: + case Declaration::Visibility::Public: + return make_shared<FunctionType>(*this, _internal); + case Declaration::Visibility::External: + return {}; + default: + solAssert(false, "visibility() should not return a Visibility"); + } + } + else + { + switch (visibility()) + { + case Declaration::Visibility::Default: + solAssert(false, "visibility() should not return Default"); + case Declaration::Visibility::Private: + case Declaration::Visibility::Internal: + return {}; + case Declaration::Visibility::Public: + case Declaration::Visibility::External: + return make_shared<FunctionType>(*this, _internal); + default: + solAssert(false, "visibility() should not return a Visibility"); + } + } + + // To make the compiler happy + return {}; +} + TypePointer FunctionDefinition::type() const { return make_shared<FunctionType>(*this); @@ -305,6 +347,14 @@ TypePointer EventDefinition::type() const return make_shared<FunctionType>(*this); } +std::shared_ptr<FunctionType> EventDefinition::functionType(bool _internal) const +{ + if (_internal) + return make_shared<FunctionType>(*this); + else + return {}; +} + EventDefinitionAnnotation& EventDefinition::annotation() const { if (!m_annotation) @@ -362,6 +412,28 @@ TypePointer VariableDeclaration::type() const return annotation().type; } +shared_ptr<FunctionType> VariableDeclaration::functionType(bool _internal) const +{ + if (_internal) + return {}; + switch (visibility()) + { + case Declaration::Visibility::Default: + solAssert(false, "visibility() should not return Default"); + case Declaration::Visibility::Private: + case Declaration::Visibility::Internal: + return {}; + case Declaration::Visibility::Public: + case Declaration::Visibility::External: + return make_shared<FunctionType>(*this); + default: + solAssert(false, "visibility() should not return a Visibility"); + } + + // To make the compiler happy + return {}; +} + VariableDeclarationAnnotation& VariableDeclaration::annotation() const { if (!m_annotation) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index ab4be1ea..2d092408 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -171,6 +171,10 @@ public: /// This can only be called once types of variable declarations have already been resolved. virtual TypePointer type() const = 0; + /// @param _internal false indicates external interface is concerned, true indicates internal interface is concerned. + /// @returns null when it is not accessible as a function. + virtual std::shared_ptr<FunctionType> functionType(bool /*_internal*/) const { return {}; } + protected: virtual Visibility defaultVisibility() const { return Visibility::Public; } @@ -581,6 +585,10 @@ public: virtual TypePointer type() const override; + /// @param _internal false indicates external interface is concerned, true indicates internal interface is concerned. + /// @returns null when it is not accessible as a function. + virtual std::shared_ptr<FunctionType> functionType(bool /*_internal*/) const override; + virtual FunctionDefinitionAnnotation& annotation() const override; private: @@ -643,6 +651,10 @@ public: virtual TypePointer type() const override; + /// @param _internal false indicates external interface is concerned, true indicates internal interface is concerned. + /// @returns null when it is not accessible as a function. + virtual std::shared_ptr<FunctionType> functionType(bool /*_internal*/) const override; + virtual VariableDeclarationAnnotation& annotation() const override; protected: @@ -740,6 +752,7 @@ public: bool isAnonymous() const { return m_anonymous; } virtual TypePointer type() const override; + virtual std::shared_ptr<FunctionType> functionType(bool /*_internal*/) const override; virtual EventDefinitionAnnotation& annotation() const override; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index a7fb8408..3922da88 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -908,19 +908,43 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) solAssert(_memberAccess.annotation().type, "_memberAccess has no type"); if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get())) { - if (funType->location() != FunctionType::Location::Internal) - { - _memberAccess.expression().accept(*this); - m_context << funType->externalIdentifier(); - } - else + switch (funType->location()) { + case FunctionType::Location::Internal: // We do not visit the expression here on purpose, because in the case of an // internal library function call, this would push the library address forcing // us to link against it although we actually do not need it. - auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration); - solAssert(!!function, "Function not found in member access"); - utils().pushCombinedFunctionEntryLabel(*function); + if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration)) + utils().pushCombinedFunctionEntryLabel(*function); + else + solAssert(false, "Function not found in member access"); + break; + case FunctionType::Location::Event: + if (!dynamic_cast<EventDefinition const*>(_memberAccess.annotation().referencedDeclaration)) + solAssert(false, "event not found"); + // no-op, because the parent node will do the job + break; + case FunctionType::Location::External: + case FunctionType::Location::Creation: + case FunctionType::Location::DelegateCall: + case FunctionType::Location::CallCode: + case FunctionType::Location::Send: + case FunctionType::Location::Bare: + case FunctionType::Location::BareCallCode: + case FunctionType::Location::BareDelegateCall: + _memberAccess.expression().accept(*this); + m_context << funType->externalIdentifier(); + break; + case FunctionType::Location::Log0: + case FunctionType::Location::Log1: + case FunctionType::Location::Log2: + case FunctionType::Location::Log3: + case FunctionType::Location::Log4: + case FunctionType::Location::ECRecover: + case FunctionType::Location::SHA256: + case FunctionType::Location::RIPEMD160: + default: + solAssert(false, "unsupported member function"); } } else if (dynamic_cast<TypeType const*>(_memberAccess.annotation().type.get())) diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 4095844f..a31df584 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -509,23 +509,32 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context }; size_t longestPrefix = 0; - string longestPrefixTarget; + size_t longestContext = 0; + string bestMatchTarget; + for (auto const& redir: m_remappings) { - // Skip if we already have a closer match. - if (longestPrefix > 0 && redir.prefix.length() <= longestPrefix) + string context = sanitizePath(redir.context); + string prefix = sanitizePath(redir.prefix); + + // Skip if current context is closer + if (context.length() < longestContext) continue; // Skip if redir.context is not a prefix of _context - if (!isPrefixOf(redir.context, _context)) + if (!isPrefixOf(context, _context)) + continue; + // Skip if we already have a closer prefix match. + if (prefix.length() < longestPrefix && context.length() == longestContext) continue; // Skip if the prefix does not match. - if (!isPrefixOf(redir.prefix, _path)) + if (!isPrefixOf(prefix, _path)) continue; - longestPrefix = redir.prefix.length(); - longestPrefixTarget = redir.target; + longestContext = context.length(); + longestPrefix = prefix.length(); + bestMatchTarget = sanitizePath(redir.target); } - string path = longestPrefixTarget; + string path = bestMatchTarget; path.append(_path.begin() + longestPrefix, _path.end()); return path; } @@ -593,11 +602,11 @@ bool CompilerStack::checkLibraryNameClashes() string CompilerStack::absolutePath(string const& _path, string const& _reference) const { - // Anything that does not start with `.` is an absolute path. - if (_path.empty() || _path.front() != '.') - return _path; using path = boost::filesystem::path; path p(_path); + // Anything that does not start with `.` is an absolute path. + if (p.begin() == p.end() || (*p.begin() != "." && *p.begin() != "..")) + return _path; path result(_reference); result.remove_filename(); for (path::iterator it = p.begin(); it != p.end(); ++it) diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index f98a457a..d49a8df1 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -29,6 +29,7 @@ #include <vector> #include <functional> #include <boost/noncopyable.hpp> +#include <boost/filesystem.hpp> #include <json/json.h> #include <libdevcore/Common.h> #include <libdevcore/FixedHash.h> @@ -234,12 +235,14 @@ private: bool checkLibraryNameClashes(); /// @returns the absolute path corresponding to @a _path relative to @a _reference. std::string absolutePath(std::string const& _path, std::string const& _reference) const; + /// Helper function to return path converted strings. + std::string sanitizePath(std::string const& _path) const { return boost::filesystem::path(_path).generic_string(); } + /// Compile a single contract and put the result in @a _compiledContracts. void compileContract( ContractDefinition const& _contract, std::map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts ); - void link(); Contract const& contract(std::string const& _contractName = "") const; diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index f02a4a45..e26e2908 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -1153,9 +1153,9 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression( else if (m_scanner->currentToken() == Token::New) { expectToken(Token::New); - ASTPointer<TypeName> contractName(parseTypeName(false)); - nodeFactory.setEndPositionFromNode(contractName); - expression = nodeFactory.createNode<NewExpression>(contractName); + ASTPointer<TypeName> typeName(parseTypeName(false)); + nodeFactory.setEndPositionFromNode(typeName); + expression = nodeFactory.createNode<NewExpression>(typeName); } else expression = parsePrimaryExpression(); |