From 86495dfc57dde9b825ffd8c219ea809446e978f9 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 19 Nov 2015 18:02:04 +0100 Subject: Make members context-sensitive. --- libsolidity/analysis/NameAndTypeResolver.cpp | 8 +++----- libsolidity/analysis/ReferencesResolver.cpp | 4 ---- libsolidity/analysis/ReferencesResolver.h | 3 --- libsolidity/analysis/TypeChecker.cpp | 16 ++++++++------- libsolidity/analysis/TypeChecker.h | 2 ++ libsolidity/ast/AST.cpp | 18 ++++++++--------- libsolidity/ast/AST.h | 20 +++++++++---------- libsolidity/ast/ASTAnnotations.h | 3 --- libsolidity/ast/Types.cpp | 28 +++++++++++++------------- libsolidity/ast/Types.h | 30 ++++++++++++++++------------ libsolidity/codegen/CompilerUtils.cpp | 4 ++-- libsolidity/codegen/ExpressionCompiler.cpp | 8 ++------ libsolidity/codegen/LValue.cpp | 4 ++-- libsolidity/interface/InterfaceHandler.cpp | 2 +- 14 files changed, 71 insertions(+), 79 deletions(-) diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index fa894456..a2397d9e 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -64,7 +64,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) { m_currentScope = &m_scopes[nullptr]; - ReferencesResolver resolver(m_errors, *this, &_contract, nullptr); + ReferencesResolver resolver(m_errors, *this, nullptr); bool success = true; for (ASTPointer const& baseContract: _contract.baseContracts()) if (!resolver.resolve(*baseContract)) @@ -100,7 +100,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) for (ASTPointer const& modifier: _contract.functionModifiers()) { m_currentScope = &m_scopes[modifier.get()]; - ReferencesResolver resolver(m_errors, *this, &_contract, nullptr); + ReferencesResolver resolver(m_errors, *this, nullptr); if (!resolver.resolve(*modifier)) success = false; } @@ -111,7 +111,6 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) if (!ReferencesResolver( m_errors, *this, - &_contract, function->returnParameterList().get() ).resolve(*function)) success = false; @@ -126,7 +125,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) for (ASTPointer const& modifier: _contract.functionModifiers()) { m_currentScope = &m_scopes[modifier.get()]; - ReferencesResolver resolver(m_errors, *this, &_contract, nullptr, true); + ReferencesResolver resolver(m_errors, *this, nullptr, true); if (!resolver.resolve(*modifier)) success = false; } @@ -137,7 +136,6 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) if (!ReferencesResolver( m_errors, *this, - &_contract, function->returnParameterList().get(), true ).resolve(*function)) diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index f0afc4f9..2207fd80 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -50,7 +50,6 @@ bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName) _typeName.annotation().referencedDeclaration = declaration; - _typeName.annotation().contractScope = m_currentContract; return true; } @@ -73,10 +72,7 @@ bool ReferencesResolver::visit(Identifier const& _identifier) if (declarations.empty()) fatalDeclarationError(_identifier.location(), "Undeclared identifier."); else if (declarations.size() == 1) - { _identifier.annotation().referencedDeclaration = declarations.front(); - _identifier.annotation().contractScope = m_currentContract; - } else _identifier.annotation().overloadedDeclarations = m_resolver.cleanedDeclarations(_identifier, declarations); diff --git a/libsolidity/analysis/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h index 62104611..870312f1 100644 --- a/libsolidity/analysis/ReferencesResolver.h +++ b/libsolidity/analysis/ReferencesResolver.h @@ -45,13 +45,11 @@ public: ReferencesResolver( ErrorList& _errors, NameAndTypeResolver& _resolver, - ContractDefinition const* _currentContract, ParameterList const* _returnParameters, bool _resolveInsideCode = false ): m_errors(_errors), m_resolver(_resolver), - m_currentContract(_currentContract), m_returnParameters(_returnParameters), m_resolveInsideCode(_resolveInsideCode) {} @@ -83,7 +81,6 @@ private: ErrorList& m_errors; NameAndTypeResolver& m_resolver; - ContractDefinition const* m_currentContract; ParameterList const* m_returnParameters; bool const m_resolveInsideCode; bool m_errorOccurred = false; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 42fdad91..2dc357bb 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -60,6 +60,8 @@ TypePointer const& TypeChecker::type(VariableDeclaration const& _variable) const bool TypeChecker::visit(ContractDefinition const& _contract) { + m_scope = &_contract; + // We force our own visiting order here. ASTNode::listAccept(_contract.definedStructs(), *this); ASTNode::listAccept(_contract.baseContracts(), *this); @@ -1057,13 +1059,13 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) if (!contract->annotation().isFullyImplemented) typeError(_newExpression.location(), "Trying to create an instance of an abstract contract."); - auto scopeContract = contractName->annotation().contractScope; - scopeContract->annotation().contractDependencies.insert(contract); + solAssert(!!m_scope, ""); + m_scope->annotation().contractDependencies.insert(contract); solAssert( !contract->annotation().linearizedBaseContracts.empty(), "Linearized base contracts not yet available." ); - if (contractDependenciesAreCyclic(*scopeContract)) + if (contractDependenciesAreCyclic(*m_scope)) typeError( _newExpression.location(), "Circular reference for contract creation (cannot create instance of derived or same contract)." @@ -1112,7 +1114,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) // Retrieve the types of the arguments if this is used to call a function. auto const& argumentTypes = _memberAccess.annotation().argumentTypes; - MemberList::MemberMap possibleMembers = exprType->members().membersByName(memberName); + MemberList::MemberMap possibleMembers = exprType->members(m_scope).membersByName(memberName); if (possibleMembers.size() > 1 && argumentTypes) { // do overload resolution @@ -1131,7 +1133,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) DataLocation::Storage, exprType ); - if (!storageType->members().membersByName(memberName).empty()) + if (!storageType->members(m_scope).membersByName(memberName).empty()) fatalTypeError( _memberAccess.location(), "Member \"" + memberName + "\" is not available in " + @@ -1258,7 +1260,7 @@ bool TypeChecker::visit(Identifier const& _identifier) for (Declaration const* declaration: annotation.overloadedDeclarations) { - TypePointer function = declaration->type(_identifier.annotation().contractScope); + TypePointer function = declaration->type(); solAssert(!!function, "Requested type not present."); auto const* functionType = dynamic_cast(function.get()); if (functionType && functionType->canTakeArguments(*annotation.argumentTypes)) @@ -1277,7 +1279,7 @@ bool TypeChecker::visit(Identifier const& _identifier) "Referenced declaration is null after overload resolution." ); annotation.isLValue = annotation.referencedDeclaration->isLValue(); - annotation.type = annotation.referencedDeclaration->type(_identifier.annotation().contractScope); + annotation.type = annotation.referencedDeclaration->type(); if (!annotation.type) fatalTypeError(_identifier.location(), "Declaration referenced before type could be determined."); return false; diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 2295bc22..9563d4a9 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -117,6 +117,8 @@ private: /// Runs type checks on @a _expression to infer its type and then checks that it is an LValue. void requireLValue(Expression const& _expression); + ContractDefinition const* m_scope = nullptr; + ErrorList& m_errors; }; diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 41a4d182..7ceab752 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -188,9 +188,9 @@ vector const& ContractDefinition::inheritableMembers() const return *m_inheritableMembers; } -TypePointer ContractDefinition::type(ContractDefinition const* m_currentContract) const +TypePointer ContractDefinition::type() const { - return make_shared(make_shared(*this), m_currentContract); + return make_shared(make_shared(*this)); } ContractDefinitionAnnotation& ContractDefinition::annotation() const @@ -207,7 +207,7 @@ TypeNameAnnotation& TypeName::annotation() const return static_cast(*m_annotation); } -TypePointer StructDefinition::type(ContractDefinition const*) const +TypePointer StructDefinition::type() const { return make_shared(make_shared(*this)); } @@ -219,14 +219,14 @@ TypeDeclarationAnnotation& StructDefinition::annotation() const return static_cast(*m_annotation); } -TypePointer EnumValue::type(ContractDefinition const*) const +TypePointer EnumValue::type() const { auto parentDef = dynamic_cast(scope()); solAssert(parentDef, "Enclosing Scope of EnumValue was not set"); return make_shared(*parentDef); } -TypePointer EnumDefinition::type(ContractDefinition const*) const +TypePointer EnumDefinition::type() const { return make_shared(make_shared(*this)); } @@ -238,7 +238,7 @@ TypeDeclarationAnnotation& EnumDefinition::annotation() const return static_cast(*m_annotation); } -TypePointer FunctionDefinition::type(ContractDefinition const*) const +TypePointer FunctionDefinition::type() const { return make_shared(*this); } @@ -255,7 +255,7 @@ FunctionDefinitionAnnotation& FunctionDefinition::annotation() const return static_cast(*m_annotation); } -TypePointer ModifierDefinition::type(ContractDefinition const*) const +TypePointer ModifierDefinition::type() const { return make_shared(*this); } @@ -267,7 +267,7 @@ ModifierDefinitionAnnotation& ModifierDefinition::annotation() const return static_cast(*m_annotation); } -TypePointer EventDefinition::type(ContractDefinition const*) const +TypePointer EventDefinition::type() const { return make_shared(*this); } @@ -324,7 +324,7 @@ bool VariableDeclaration::canHaveAutoType() const return (!!callable && !isCallableParameter()); } -TypePointer VariableDeclaration::type(ContractDefinition const*) const +TypePointer VariableDeclaration::type() const { return annotation().type; } diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index e2ed1853..11c4fef6 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -168,7 +168,7 @@ public: /// The current contract has to be given since this context can change the type, especially of /// contract types. /// This can only be called once types of variable declarations have already been resolved. - virtual TypePointer type(ContractDefinition const* m_currentContract = nullptr) const = 0; + virtual TypePointer type() const = 0; protected: virtual Visibility defaultVisibility() const { return Visibility::Public; } @@ -290,7 +290,7 @@ public: std::string const& devDocumentation() const; void setDevDocumentation(std::string const& _devDocumentation); - virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual TypePointer type() const override; virtual ContractDefinitionAnnotation& annotation() const override; @@ -350,7 +350,7 @@ public: std::vector> const& members() const { return m_members; } - virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual TypePointer type() const override; virtual TypeDeclarationAnnotation& annotation() const override; @@ -372,7 +372,7 @@ public: std::vector> const& members() const { return m_members; } - virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual TypePointer type() const override; virtual TypeDeclarationAnnotation& annotation() const override; @@ -392,7 +392,7 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual TypePointer type() const override; }; /** @@ -490,7 +490,7 @@ public: /// arguments separated by commas all enclosed in parentheses without any spaces. std::string externalSignature() const; - virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual TypePointer type() const override; virtual FunctionDefinitionAnnotation& annotation() const override; @@ -551,7 +551,7 @@ public: bool isConstant() const { return m_isConstant; } Location referenceLocation() const { return m_location; } - virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual TypePointer type() const override; virtual VariableDeclarationAnnotation& annotation() const override; @@ -593,7 +593,7 @@ public: Block const& body() const { return *m_body; } - virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual TypePointer type() const override; virtual ModifierDefinitionAnnotation& annotation() const override; @@ -649,7 +649,7 @@ public: bool isAnonymous() const { return m_anonymous; } - virtual TypePointer type(ContractDefinition const* m_currentContract) const override; + virtual TypePointer type() const override; virtual EventDefinitionAnnotation& annotation() const override; @@ -675,7 +675,7 @@ public: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("MagicVariableDeclaration used inside real AST.")); } - virtual TypePointer type(ContractDefinition const*) const override { return m_type; } + virtual TypePointer type() const override { return m_type; } private: std::shared_ptr m_type; diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index b9667302..4e0187cf 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -138,9 +138,6 @@ struct ExpressionAnnotation: ASTAnnotation struct IdentifierAnnotation: ExpressionAnnotation { - /// Stores a reference to the current contract. - /// This is needed because types of base contracts change depending on the context. - ContractDefinition const* contractScope = nullptr; /// Referenced declaration, set at latest during overload resolution stage. Declaration const* referencedDeclaration = nullptr; /// List of possible declarations it could refer to. diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index cb97eae8..85e1fd49 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -858,7 +858,7 @@ string ArrayType::canonicalName(bool _addDataLocation) const return ret; } -MemberList const& ArrayType::members() const +MemberList const& ArrayType::members(ContractDefinition const*) const { if (!m_members) { @@ -956,7 +956,7 @@ string ContractType::canonicalName(bool) const return m_contract.annotation().canonicalName; } -MemberList const& ContractType::members() const +MemberList const& ContractType::members(ContractDefinition const*) const { // We need to lazy-initialize it because of recursive references. if (!m_members) @@ -1064,7 +1064,7 @@ bool StructType::operator==(Type const& _other) const unsigned StructType::calldataEncodedSize(bool _padded) const { unsigned size = 0; - for (auto const& member: members()) + for (auto const& member: members(nullptr)) if (!member.type->canLiveOutsideStorage()) return 0; else @@ -1080,7 +1080,7 @@ unsigned StructType::calldataEncodedSize(bool _padded) const u256 StructType::memorySize() const { u256 size; - for (auto const& member: members()) + for (auto const& member: members(nullptr)) if (member.type->canLiveOutsideStorage()) size += member.type->memoryHeadSize(); return size; @@ -1088,7 +1088,7 @@ u256 StructType::memorySize() const u256 StructType::storageSize() const { - return max(1, members().storageSize()); + return max(1, members(nullptr).storageSize()); } string StructType::toString(bool _short) const @@ -1099,7 +1099,7 @@ string StructType::toString(bool _short) const return ret; } -MemberList const& StructType::members() const +MemberList const& StructType::members(ContractDefinition const*) const { // We need to lazy-initialize it because of recursive references. if (!m_members) @@ -1149,7 +1149,7 @@ FunctionTypePointer StructType::constructorType() const { TypePointers paramTypes; strings paramNames; - for (auto const& member: members()) + for (auto const& member: members(nullptr)) { if (!member.type->canLiveOutsideStorage()) continue; @@ -1167,7 +1167,7 @@ FunctionTypePointer StructType::constructorType() const pair const& StructType::storageOffsetsOfMember(string const& _name) const { - auto const* offsets = members().memberStorageOffset(_name); + auto const* offsets = members(nullptr).memberStorageOffset(_name); solAssert(offsets, "Storage offset of non-existing member requested."); return *offsets; } @@ -1175,7 +1175,7 @@ pair const& StructType::storageOffsetsOfMember(string const& _na u256 StructType::memoryOffsetOfMember(string const& _name) const { u256 offset; - for (auto const& member: members()) + for (auto const& member: members(nullptr)) if (member.name == _name) return offset; else @@ -1395,7 +1395,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): vector retParamNames; if (auto structType = dynamic_cast(returnType.get())) { - for (auto const& member: structType->members()) + for (auto const& member: structType->members(nullptr)) if (member.type->category() != Category::Mapping) { if (auto arrayType = dynamic_cast(member.type.get())) @@ -1533,7 +1533,7 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const return make_shared(paramTypes, retParamTypes, m_parameterNames, m_returnParameterNames, m_location, m_arbitraryParameters); } -MemberList const& FunctionType::members() const +MemberList const& FunctionType::members(ContractDefinition const*) const { switch (m_location) { @@ -1784,7 +1784,7 @@ unsigned TypeType::sizeOnStack() const return 0; } -MemberList const& TypeType::members() const +MemberList const& TypeType::members(ContractDefinition const* _currentScope) const { // We need to lazy-initialize it because of recursive references. if (!m_members) @@ -1800,9 +1800,9 @@ MemberList const& TypeType::members() const it.second->asMemberFunction(true), // use callcode &it.second->declaration() )); - else if (m_currentContract != nullptr) + else if (_currentScope != nullptr) { - auto const& currentBases = m_currentContract->annotation().linearizedBaseContracts; + auto const& currentBases = _currentScope->annotation().linearizedBaseContracts; if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end()) // We are accessing the type of a base contract, so add all public and protected // members. Note that this does not add inherited functions on purpose. diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 63207a51..0769ba39 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -217,9 +217,13 @@ public: } /// Returns the list of all members of this type. Default implementation: no members. - virtual MemberList const& members() const { return EmptyMemberList; } + /// @param _currentScope scope in which the members are accessed. + virtual MemberList const& members(ContractDefinition const* /*_currentScope*/) const { return EmptyMemberList; } /// Convenience method, returns the type of the given named member or an empty pointer if no such member exists. - TypePointer memberType(std::string const& _name) const { return members().memberType(_name); } + TypePointer memberType(std::string const& _name, ContractDefinition const* _currentScope = nullptr) const + { + return members(_currentScope).memberType(_name); + } virtual std::string toString(bool _short) const = 0; std::string toString() const { return toString(false); } @@ -277,7 +281,10 @@ public: virtual unsigned storageBytes() const override { return m_bits / 8; } virtual bool isValueType() const override { return true; } - virtual MemberList const& members() const override { return isAddress() ? AddressMemberList : EmptyMemberList; } + virtual MemberList const& members(ContractDefinition const* /*_currentScope*/) const override + { + return isAddress() ? AddressMemberList : EmptyMemberList; + } virtual std::string toString(bool _short) const override; @@ -510,7 +517,7 @@ public: virtual unsigned sizeOnStack() const override; virtual std::string toString(bool _short) const override; virtual std::string canonicalName(bool _addDataLocation) const override; - virtual MemberList const& members() const override; + virtual MemberList const& members(ContractDefinition const* _currentScope) const override; virtual TypePointer encodingType() const override; virtual TypePointer decodingType() const override; virtual TypePointer interfaceType(bool _inLibrary) const override; @@ -563,7 +570,7 @@ public: virtual std::string toString(bool _short) const override; virtual std::string canonicalName(bool _addDataLocation) const override; - virtual MemberList const& members() const override; + virtual MemberList const& members(ContractDefinition const* _currentScope) const override; virtual TypePointer encodingType() const override { return std::make_shared(160, IntegerType::Modifier::Address); @@ -616,7 +623,7 @@ public: virtual bool canLiveOutsideStorage() const override { return true; } virtual std::string toString(bool _short) const override; - virtual MemberList const& members() const override; + virtual MemberList const& members(ContractDefinition const* _currentScope) const override; virtual TypePointer encodingType() const override { return location() == DataLocation::Storage ? std::make_shared(256) : TypePointer(); @@ -810,7 +817,7 @@ public: virtual u256 storageSize() const override; virtual bool canLiveOutsideStorage() const override { return false; } virtual unsigned sizeOnStack() const override; - virtual MemberList const& members() const override; + virtual MemberList const& members(ContractDefinition const* _currentScope) const override; /// @returns TypePointer of a new FunctionType object. All input/return parameters are an /// appropriate external types (i.e. the interfaceType()s) of input/return parameters of @@ -918,8 +925,7 @@ class TypeType: public Type { public: virtual Category category() const override { return Category::TypeType; } - explicit TypeType(TypePointer const& _actualType, ContractDefinition const* _currentContract = nullptr): - m_actualType(_actualType), m_currentContract(_currentContract) {} + explicit TypeType(TypePointer const& _actualType): m_actualType(_actualType) {} TypePointer const& actualType() const { return m_actualType; } virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } @@ -929,12 +935,10 @@ public: virtual bool canLiveOutsideStorage() const override { return false; } virtual unsigned sizeOnStack() const override; virtual std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; } - virtual MemberList const& members() const override; + virtual MemberList const& members(ContractDefinition const* _currentScope) const override; private: TypePointer m_actualType; - /// Context in which this type is used (influences visibility etc.), can be nullptr. - ContractDefinition const* m_currentContract; /// List of member types, will be lazy-initialized because of recursive references. mutable std::unique_ptr m_members; }; @@ -983,7 +987,7 @@ public: virtual bool canBeStored() const override { return false; } virtual bool canLiveOutsideStorage() const override { return true; } virtual unsigned sizeOnStack() const override { return 0; } - virtual MemberList const& members() const override { return m_members; } + virtual MemberList const& members(ContractDefinition const*) const override { return m_members; } virtual std::string toString(bool _short) const override; diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 357013e6..b57f5b29 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -542,7 +542,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp allocateMemory(); m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2; // stack: - for (auto const& member: typeOnStack.members()) + for (auto const& member: typeOnStack.members(nullptr)) { if (!member.type->canLiveOutsideStorage()) continue; @@ -642,7 +642,7 @@ void CompilerUtils::pushZeroValue(Type const& _type) m_context << eth::Instruction::DUP1; if (auto structType = dynamic_cast(&_type)) - for (auto const& member: structType->members()) + for (auto const& member: structType->members(nullptr)) { pushZeroValue(*member.type); storeInMemoryDynamic(*member.type); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index c94c988b..6c288ae7 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -888,10 +888,6 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) case Type::Category::TypeType: { TypeType const& type = dynamic_cast(*_memberAccess.expression().annotation().type); - solAssert( - !type.members().membersByName(_memberAccess.memberName()).empty(), - "Invalid member access to " + type.toString(false) - ); if (dynamic_cast(type.actualType().get())) { @@ -1043,11 +1039,11 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) Declaration const* declaration = _identifier.annotation().referencedDeclaration; if (MagicVariableDeclaration const* magicVar = dynamic_cast(declaration)) { - switch (magicVar->type(_identifier.annotation().contractScope)->category()) + switch (magicVar->type()->category()) { case Type::Category::Contract: // "this" or "super" - if (!dynamic_cast(*magicVar->type(_identifier.annotation().contractScope)).isSuper()) + if (!dynamic_cast(*magicVar->type()).isSuper()) m_context << eth::Instruction::ADDRESS; break; case Type::Category::Integer: diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 864f28d0..fdef6937 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -273,7 +273,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc "Struct assignment with conversion." ); solAssert(sourceType.location() != DataLocation::CallData, "Structs in calldata not supported."); - for (auto const& member: structType.members()) + for (auto const& member: structType.members(nullptr)) { // assign each member that is not a mapping TypePointer const& memberType = member.type; @@ -336,7 +336,7 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const // @todo this can be improved: use StorageItem for non-value types, and just store 0 in // all slots that contain value types later. auto const& structType = dynamic_cast(*m_dataType); - for (auto const& member: structType.members()) + for (auto const& member: structType.members(nullptr)) { // zero each member that is not a mapping TypePointer const& memberType = member.type; diff --git a/libsolidity/interface/InterfaceHandler.cpp b/libsolidity/interface/InterfaceHandler.cpp index 30cd9724..e254137f 100644 --- a/libsolidity/interface/InterfaceHandler.cpp +++ b/libsolidity/interface/InterfaceHandler.cpp @@ -120,7 +120,7 @@ string InterfaceHandler::ABISolidityInterface(ContractDefinition const& _contrac { ret += "struct " + stru->name() + "{"; for (ASTPointer const& _member: stru->members()) - ret += _member->type(nullptr)->canonicalName(false) + " " + _member->name() + ";"; + ret += _member->type()->canonicalName(false) + " " + _member->name() + ";"; ret += "}"; } for (auto const& enu: _contractDef.definedEnums()) -- cgit v1.2.3 From b47d5932528357939ee29758a8b8027c90bdb1e5 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 23 Nov 2015 23:57:17 +0100 Subject: Do not store elements of a contract by AST node type. --- libsolidity/analysis/NameAndTypeResolver.cpp | 38 +++---------- libsolidity/analysis/ReferencesResolver.cpp | 2 +- libsolidity/analysis/ReferencesResolver.h | 2 +- libsolidity/analysis/TypeChecker.cpp | 32 +++++------ libsolidity/ast/AST.cpp | 84 +++++++++++++++++++++++----- libsolidity/ast/AST.h | 46 ++++++--------- libsolidity/ast/AST_accept.h | 14 +---- libsolidity/ast/Types.cpp | 8 +-- libsolidity/codegen/Compiler.cpp | 2 +- libsolidity/codegen/CompilerContext.cpp | 6 +- libsolidity/formal/Why3Translator.cpp | 15 ++--- libsolidity/formal/Why3Translator.h | 2 +- libsolidity/parsing/Parser.cpp | 26 +++------ test/libsolidity/SolidityParser.cpp | 16 +++--- 14 files changed, 141 insertions(+), 152 deletions(-) diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index a2397d9e..612989e1 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -84,35 +84,11 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) importInheritedScope(*base); } - for (ASTPointer const& structDef: _contract.definedStructs()) - if (!resolver.resolve(*structDef)) - success = false; - for (ASTPointer const& enumDef: _contract.definedEnums()) - if (!resolver.resolve(*enumDef)) - success = false; - for (ASTPointer const& variable: _contract.stateVariables()) - if (!resolver.resolve(*variable)) - success = false; - for (ASTPointer const& event: _contract.events()) - if (!resolver.resolve(*event)) - success = false; // these can contain code, only resolve parameters for now - for (ASTPointer const& modifier: _contract.functionModifiers()) + for (ASTPointer const& node: _contract.subNodes()) { - m_currentScope = &m_scopes[modifier.get()]; - ReferencesResolver resolver(m_errors, *this, nullptr); - if (!resolver.resolve(*modifier)) - success = false; - } - - for (ASTPointer const& function: _contract.definedFunctions()) - { - m_currentScope = &m_scopes[function.get()]; - if (!ReferencesResolver( - m_errors, - *this, - function->returnParameterList().get() - ).resolve(*function)) + m_currentScope = &m_scopes[m_scopes.count(node.get()) ? node.get() : &_contract]; + if (!resolver.resolve(*node)) success = false; } @@ -122,17 +98,17 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) m_currentScope = &m_scopes[&_contract]; // now resolve references inside the code - for (ASTPointer const& modifier: _contract.functionModifiers()) + for (ModifierDefinition const* modifier: _contract.functionModifiers()) { - m_currentScope = &m_scopes[modifier.get()]; + m_currentScope = &m_scopes[modifier]; ReferencesResolver resolver(m_errors, *this, nullptr, true); if (!resolver.resolve(*modifier)) success = false; } - for (ASTPointer const& function: _contract.definedFunctions()) + for (FunctionDefinition const* function: _contract.definedFunctions()) { - m_currentScope = &m_scopes[function.get()]; + m_currentScope = &m_scopes[function]; if (!ReferencesResolver( m_errors, *this, diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 2207fd80..e5b1c52b 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -53,7 +53,7 @@ bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName) return true; } -bool ReferencesResolver::resolve(ASTNode& _root) +bool ReferencesResolver::resolve(ASTNode const& _root) { try { diff --git a/libsolidity/analysis/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h index 870312f1..6f5ced8c 100644 --- a/libsolidity/analysis/ReferencesResolver.h +++ b/libsolidity/analysis/ReferencesResolver.h @@ -55,7 +55,7 @@ public: {} /// @returns true if no errors during resolving - bool resolve(ASTNode& _root); + bool resolve(ASTNode const& _root); private: virtual bool visit(Block const&) override { return m_resolveInsideCode; } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 2dc357bb..1d2d0258 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -63,6 +63,7 @@ bool TypeChecker::visit(ContractDefinition const& _contract) m_scope = &_contract; // We force our own visiting order here. + //@TODO structs will be visited again below, but it is probably fine. ASTNode::listAccept(_contract.definedStructs(), *this); ASTNode::listAccept(_contract.baseContracts(), *this); @@ -76,7 +77,7 @@ bool TypeChecker::visit(ContractDefinition const& _contract) typeError(function->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor."); FunctionDefinition const* fallbackFunction = nullptr; - for (ASTPointer const& function: _contract.definedFunctions()) + for (FunctionDefinition const* function: _contract.definedFunctions()) { if (function->name().empty()) { @@ -88,7 +89,7 @@ bool TypeChecker::visit(ContractDefinition const& _contract) } else { - fallbackFunction = function.get(); + fallbackFunction = function; if (!fallbackFunction->parameters().empty()) typeError(fallbackFunction->parameterList().location(), "Fallback function cannot take parameters."); } @@ -97,10 +98,7 @@ bool TypeChecker::visit(ContractDefinition const& _contract) _contract.annotation().isFullyImplemented = false; } - ASTNode::listAccept(_contract.stateVariables(), *this); - ASTNode::listAccept(_contract.events(), *this); - ASTNode::listAccept(_contract.functionModifiers(), *this); - ASTNode::listAccept(_contract.definedFunctions(), *this); + ASTNode::listAccept(_contract.subNodes(), *this); checkContractExternalTypeClashes(_contract); // check for hash collisions in function signatures @@ -127,8 +125,8 @@ void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _con /// Checks that two functions with the same name defined in this contract have different /// argument types and that there is at most one constructor. map> functions; - for (ASTPointer const& function: _contract.definedFunctions()) - functions[function->name()].push_back(function.get()); + for (FunctionDefinition const* function: _contract.definedFunctions()) + functions[function->name()].push_back(function); // Constructor if (functions[_contract.name()].size() > 1) @@ -172,7 +170,7 @@ void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _cont // Search from base to derived for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts)) - for (ASTPointer const& function: contract->definedFunctions()) + for (FunctionDefinition const* function: contract->definedFunctions()) { auto& overloads = functions[function->name()]; FunctionTypePointer funType = make_shared(*function); @@ -248,7 +246,7 @@ void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contr // We search from derived to base, so the stored item causes the error. for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts) { - for (ASTPointer const& function: contract->definedFunctions()) + for (FunctionDefinition const* function: contract->definedFunctions()) { if (function->isConstructor()) continue; // constructors can neither be overridden nor override anything @@ -269,14 +267,14 @@ void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contr ) typeError(overriding->location(), "Override changes extended function signature."); } - functions[name].push_back(function.get()); + functions[name].push_back(function); } - for (ASTPointer const& modifier: contract->functionModifiers()) + for (ModifierDefinition const* modifier: contract->functionModifiers()) { string const& name = modifier->name(); ModifierDefinition const*& override = modifiers[name]; if (!override) - override = modifier.get(); + override = modifier; else if (ModifierType(*override) != ModifierType(*modifier)) typeError(override->location(), "Override changes modifier signature."); if (!functions[name].empty()) @@ -290,20 +288,20 @@ void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _co map>> externalDeclarations; for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts) { - for (ASTPointer const& f: contract->definedFunctions()) + for (FunctionDefinition const* f: contract->definedFunctions()) if (f->isPartOfExternalInterface()) { auto functionType = make_shared(*f); externalDeclarations[functionType->externalSignature()].push_back( - make_pair(f.get(), functionType) + make_pair(f, functionType) ); } - for (ASTPointer const& v: contract->stateVariables()) + for (VariableDeclaration const* v: contract->stateVariables()) if (v->isPartOfExternalInterface()) { auto functionType = make_shared(*v); externalDeclarations[functionType->externalSignature()].push_back( - make_pair(v.get(), functionType) + make_pair(v, functionType) ); } } diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 7ceab752..65535388 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -74,29 +74,83 @@ map, FunctionTypePointer> ContractDefinition::interfaceFunctions() FunctionDefinition const* ContractDefinition::constructor() const { - for (ASTPointer const& f: m_definedFunctions) + for (FunctionDefinition const* f: definedFunctions()) if (f->isConstructor()) - return f.get(); + return f; return nullptr; } FunctionDefinition const* ContractDefinition::fallbackFunction() const { for (ContractDefinition const* contract: annotation().linearizedBaseContracts) - for (ASTPointer const& f: contract->definedFunctions()) + for (FunctionDefinition const* f: contract->definedFunctions()) if (f->name().empty()) - return f.get(); + return f; return nullptr; } -vector> const& ContractDefinition::interfaceEvents() const +vector ContractDefinition::definedStructs() const +{ + vector ret; + for (auto const& node: m_subNodes) + if (auto v = dynamic_cast(node.get())) + ret.push_back(v); + return ret; +} + +vector ContractDefinition::definedEnums() const +{ + vector ret; + for (auto const& node: m_subNodes) + if (auto v = dynamic_cast(node.get())) + ret.push_back(v); + return ret; +} + +vector ContractDefinition::stateVariables() const +{ + vector ret; + for (auto const& node: m_subNodes) + if (auto v = dynamic_cast(node.get())) + ret.push_back(v); + return ret; +} + +vector ContractDefinition::functionModifiers() const +{ + vector ret; + for (auto const& node: m_subNodes) + if (auto v = dynamic_cast(node.get())) + ret.push_back(v); + return ret; +} + +vector ContractDefinition::definedFunctions() const +{ + vector ret; + for (auto const& node: m_subNodes) + if (auto v = dynamic_cast(node.get())) + ret.push_back(v); + return ret; +} + +vector ContractDefinition::events() const +{ + vector ret; + for (auto const& node: m_subNodes) + if (auto v = dynamic_cast(node.get())) + ret.push_back(v); + return ret; +} + +vector const& ContractDefinition::interfaceEvents() const { if (!m_interfaceEvents) { set eventsSeen; - m_interfaceEvents.reset(new vector>()); + m_interfaceEvents.reset(new vector()); for (ContractDefinition const* contract: annotation().linearizedBaseContracts) - for (ASTPointer const& e: contract->events()) + for (EventDefinition const* e: contract->events()) if (eventsSeen.count(e->name()) == 0) { eventsSeen.insert(e->name()); @@ -116,10 +170,10 @@ vector, FunctionTypePointer>> const& ContractDefinition::inter for (ContractDefinition const* contract: annotation().linearizedBaseContracts) { vector functions; - for (ASTPointer const& f: contract->definedFunctions()) + for (FunctionDefinition const* f: contract->definedFunctions()) if (f->isPartOfExternalInterface()) functions.push_back(make_shared(*f, false)); - for (ASTPointer const& v: contract->stateVariables()) + for (VariableDeclaration const* v: contract->stateVariables()) if (v->isPartOfExternalInterface()) functions.push_back(make_shared(*v)); for (FunctionTypePointer const& fun: functions) @@ -176,14 +230,14 @@ vector const& ContractDefinition::inheritableMembers() const } }; - for (ASTPointer const& f: definedFunctions()) - addInheritableMember(f.get()); + for (FunctionDefinition const* f: definedFunctions()) + addInheritableMember(f); - for (ASTPointer const& v: stateVariables()) - addInheritableMember(v.get()); + for (VariableDeclaration const* v: stateVariables()) + addInheritableMember(v); - for (ASTPointer const& s: definedStructs()) - addInheritableMember(s.get()); + for (StructDefinition const* s: definedStructs()) + addInheritableMember(s); } return *m_inheritableMembers; } diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 11c4fef6..ab872750 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -58,15 +58,15 @@ public: virtual void accept(ASTVisitor& _visitor) = 0; virtual void accept(ASTConstVisitor& _visitor) const = 0; template - static void listAccept(std::vector>& _list, ASTVisitor& _visitor) + static void listAccept(std::vector const& _list, ASTVisitor& _visitor) { - for (ASTPointer& element: _list) + for (T const& element: _list) element->accept(_visitor); } template - static void listAccept(std::vector> const& _list, ASTConstVisitor& _visitor) + static void listAccept(std::vector const& _list, ASTConstVisitor& _visitor) { - for (ASTPointer const& element: _list) + for (T const& element: _list) element->accept(_visitor); } @@ -238,23 +238,13 @@ public: ASTPointer const& _name, ASTPointer const& _documentation, std::vector> const& _baseContracts, - std::vector> const& _definedStructs, - std::vector> const& _definedEnums, - std::vector> const& _stateVariables, - std::vector> const& _definedFunctions, - std::vector> const& _functionModifiers, - std::vector> const& _events, + std::vector> const& _subNodes, bool _isLibrary ): Declaration(_location, _name), Documented(_documentation), m_baseContracts(_baseContracts), - m_definedStructs(_definedStructs), - m_definedEnums(_definedEnums), - m_stateVariables(_stateVariables), - m_definedFunctions(_definedFunctions), - m_functionModifiers(_functionModifiers), - m_events(_events), + m_subNodes(_subNodes), m_isLibrary(_isLibrary) {} @@ -262,13 +252,14 @@ public: virtual void accept(ASTConstVisitor& _visitor) const override; std::vector> const& baseContracts() const { return m_baseContracts; } - std::vector> const& definedStructs() const { return m_definedStructs; } - std::vector> const& definedEnums() const { return m_definedEnums; } - std::vector> const& stateVariables() const { return m_stateVariables; } - std::vector> const& functionModifiers() const { return m_functionModifiers; } - std::vector> const& definedFunctions() const { return m_definedFunctions; } - std::vector> const& events() const { return m_events; } - std::vector> const& interfaceEvents() const; + std::vector> const& subNodes() const { return m_subNodes; } + std::vector definedStructs() const; + std::vector definedEnums() const; + std::vector stateVariables() const; + std::vector functionModifiers() const; + std::vector definedFunctions() const; + std::vector events() const; + std::vector const& interfaceEvents() const; bool isLibrary() const { return m_isLibrary; } /// @returns a map of canonical function signatures to FunctionDefinitions @@ -296,12 +287,7 @@ public: private: std::vector> m_baseContracts; - std::vector> m_definedStructs; - std::vector> m_definedEnums; - std::vector> m_stateVariables; - std::vector> m_definedFunctions; - std::vector> m_functionModifiers; - std::vector> m_events; + std::vector> m_subNodes; bool m_isLibrary; // parsed Natspec documentation of the contract. @@ -310,7 +296,7 @@ private: std::vector m_linearizedBaseContracts; mutable std::unique_ptr, FunctionTypePointer>>> m_interfaceFunctionList; - mutable std::unique_ptr>> m_interfaceEvents; + mutable std::unique_ptr> m_interfaceEvents; mutable std::unique_ptr> m_inheritableMembers; }; diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h index 99d1bf6a..f65595b8 100644 --- a/libsolidity/ast/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -62,12 +62,7 @@ void ContractDefinition::accept(ASTVisitor& _visitor) if (_visitor.visit(*this)) { listAccept(m_baseContracts, _visitor); - listAccept(m_definedStructs, _visitor); - listAccept(m_definedEnums, _visitor); - listAccept(m_stateVariables, _visitor); - listAccept(m_events, _visitor); - listAccept(m_functionModifiers, _visitor); - listAccept(m_definedFunctions, _visitor); + listAccept(m_subNodes, _visitor); } _visitor.endVisit(*this); } @@ -77,12 +72,7 @@ void ContractDefinition::accept(ASTConstVisitor& _visitor) const if (_visitor.visit(*this)) { listAccept(m_baseContracts, _visitor); - listAccept(m_definedStructs, _visitor); - listAccept(m_definedEnums, _visitor); - listAccept(m_stateVariables, _visitor); - listAccept(m_events, _visitor); - listAccept(m_functionModifiers, _visitor); - listAccept(m_definedFunctions, _visitor); + listAccept(m_subNodes, _visitor); } _visitor.endVisit(*this); } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 85e1fd49..a4da5b13 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -970,7 +970,7 @@ MemberList const& ContractType::members(ContractDefinition const*) const { // add the most derived of all functions which are visible in derived contracts for (ContractDefinition const* base: m_contract.annotation().linearizedBaseContracts) - for (ASTPointer const& function: base->definedFunctions()) + for (FunctionDefinition const* function: base->definedFunctions()) { if (!function->isVisibleInDerivedContracts()) continue; @@ -991,7 +991,7 @@ MemberList const& ContractType::members(ContractDefinition const*) const members.push_back(MemberList::Member( function->name(), functionType, - function.get() + function )); } } @@ -1024,9 +1024,9 @@ vector> ContractType::stateVar { vector variables; for (ContractDefinition const* contract: boost::adaptors::reverse(m_contract.annotation().linearizedBaseContracts)) - for (ASTPointer const& variable: contract->stateVariables()) + for (VariableDeclaration const* variable: contract->stateVariables()) if (!variable->isConstant()) - variables.push_back(variable.get()); + variables.push_back(variable); TypePointers types; for (auto variable: variables) types.push_back(variable->annotation().type); diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index 055e607f..f1d95980 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -385,7 +385,7 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract) void Compiler::initializeStateVariables(ContractDefinition const& _contract) { - for (ASTPointer const& variable: _contract.stateVariables()) + for (VariableDeclaration const* variable: _contract.stateVariables()) if (variable->value() && !variable->isConstant()) ExpressionCompiler(m_context, m_optimize).appendStateVariableInitialization(*variable); } diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 00b9d87c..9e2405cc 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -133,9 +133,9 @@ ModifierDefinition const& CompilerContext::functionModifier(string const& _name) { solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); for (ContractDefinition const* contract: m_inheritanceHierarchy) - for (ASTPointer const& modifier: contract->functionModifiers()) + for (ModifierDefinition const* modifier: contract->functionModifiers()) if (modifier->name() == _name) - return *modifier.get(); + return *modifier; BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function modifier " + _name + " not found.")); } @@ -195,7 +195,7 @@ eth::AssemblyItem CompilerContext::virtualFunctionEntryLabel( FunctionType functionType(_function); auto it = _searchStart; for (; it != m_inheritanceHierarchy.end(); ++it) - for (ASTPointer const& function: (*it)->definedFunctions()) + for (FunctionDefinition const* function: (*it)->definedFunctions()) if ( function->name() == name && !function->isConstructor() && diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp index fe3729d4..5028e2c3 100644 --- a/libsolidity/formal/Why3Translator.cpp +++ b/libsolidity/formal/Why3Translator.cpp @@ -145,8 +145,8 @@ bool Why3Translator::visit(ContractDefinition const& _contract) addLine("type state = {"); indent(); - m_stateVariables = &_contract.stateVariables(); - for (auto const& variable: _contract.stateVariables()) + m_stateVariables = _contract.stateVariables(); + for (VariableDeclaration const* variable: m_stateVariables) { string varType = toFormalType(*variable->annotation().type); if (varType.empty()) @@ -174,7 +174,7 @@ bool Why3Translator::visit(ContractDefinition const& _contract) void Why3Translator::endVisit(ContractDefinition const& _contract) { - m_stateVariables = nullptr; + m_stateVariables.clear(); addSourceFromDocStrings(_contract.annotation()); unindent(); addLine("end"); @@ -600,17 +600,12 @@ bool Why3Translator::visit(Literal const& _literal) bool Why3Translator::isStateVariable(VariableDeclaration const* _var) const { - solAssert(!!m_stateVariables, ""); - for (auto const& var: *m_stateVariables) - if (var.get() == _var) - return true; - return false; + return contains(m_stateVariables, _var); } bool Why3Translator::isStateVariable(string const& _name) const { - solAssert(!!m_stateVariables, ""); - for (auto const& var: *m_stateVariables) + for (auto const& var: m_stateVariables) if (var->name() == _name) return true; return false; diff --git a/libsolidity/formal/Why3Translator.h b/libsolidity/formal/Why3Translator.h index e5c298b4..f4315a7a 100644 --- a/libsolidity/formal/Why3Translator.h +++ b/libsolidity/formal/Why3Translator.h @@ -117,7 +117,7 @@ private: bool m_seenContract = false; bool m_errorOccured = false; - std::vector> const* m_stateVariables = nullptr; + std::vector m_stateVariables; std::map m_localVariables; struct Line diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 2d4ca43e..9272eb4b 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -132,12 +132,6 @@ ASTPointer Parser::parseContractDefinition(bool _isLibrary) expectToken(_isLibrary ? Token::Library : Token::Contract); ASTPointer name = expectIdentifierToken(); vector> baseContracts; - vector> structs; - vector> enums; - vector> stateVariables; - vector> functions; - vector> modifiers; - vector> events; if (m_scanner->currentToken() == Token::Is) do { @@ -145,6 +139,7 @@ ASTPointer Parser::parseContractDefinition(bool _isLibrary) baseContracts.push_back(parseInheritanceSpecifier()); } while (m_scanner->currentToken() == Token::Comma); + vector> subNodes; expectToken(Token::LBrace); while (true) { @@ -152,11 +147,11 @@ ASTPointer Parser::parseContractDefinition(bool _isLibrary) if (currentTokenValue == Token::RBrace) break; else if (currentTokenValue == Token::Function) - functions.push_back(parseFunctionDefinition(name.get())); + subNodes.push_back(parseFunctionDefinition(name.get())); else if (currentTokenValue == Token::Struct) - structs.push_back(parseStructDefinition()); + subNodes.push_back(parseStructDefinition()); else if (currentTokenValue == Token::Enum) - enums.push_back(parseEnumDefinition()); + subNodes.push_back(parseEnumDefinition()); else if ( currentTokenValue == Token::Identifier || currentTokenValue == Token::Mapping || @@ -166,13 +161,13 @@ ASTPointer Parser::parseContractDefinition(bool _isLibrary) VarDeclParserOptions options; options.isStateVariable = true; options.allowInitialValue = true; - stateVariables.push_back(parseVariableDeclaration(options)); + subNodes.push_back(parseVariableDeclaration(options)); expectToken(Token::Semicolon); } else if (currentTokenValue == Token::Modifier) - modifiers.push_back(parseModifierDefinition()); + subNodes.push_back(parseModifierDefinition()); else if (currentTokenValue == Token::Event) - events.push_back(parseEventDefinition()); + subNodes.push_back(parseEventDefinition()); else fatalParserError(std::string("Function, variable, struct or modifier declaration expected.")); } @@ -182,12 +177,7 @@ ASTPointer Parser::parseContractDefinition(bool _isLibrary) name, docString, baseContracts, - structs, - enums, - stateVariables, - functions, - modifiers, - events, + subNodes, _isLibrary ); } diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index beb71942..b494a1aa 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -73,7 +73,7 @@ bool successParse(std::string const& _source) } void checkFunctionNatspec( - ASTPointer _function, + FunctionDefinition const* _function, std::string const& _expectedDoc ) { @@ -193,7 +193,7 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation) BOOST_CHECK(successParse(text)); ErrorList e; ASTPointer contract = parseText(text, e); - ASTPointer function; + FunctionDefinition const* function = nullptr; ErrorList errors; auto functions = parseText(text, errors)->definedFunctions(); @@ -204,7 +204,7 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation) BOOST_AUTO_TEST_CASE(function_normal_comments) { ASTPointer contract; - ASTPointer function; + FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " uint256 stateVar;\n" " // We won't see this comment\n" @@ -221,7 +221,7 @@ BOOST_AUTO_TEST_CASE(function_normal_comments) BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) { ASTPointer contract; - ASTPointer function; + FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " uint256 stateVar;\n" " /// This is test function 1\n" @@ -254,7 +254,7 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) BOOST_AUTO_TEST_CASE(multiline_function_documentation) { ASTPointer contract; - ASTPointer function; + FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " uint256 stateVar;\n" " /// This is a test function\n" @@ -272,7 +272,7 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) { ASTPointer contract; - ASTPointer function; + FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " /// fun1 description\n" " function fun1(uint256 a) {\n" @@ -301,7 +301,7 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature) { ASTPointer contract; - ASTPointer function; + FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " uint256 stateVar;\n" " function ///I am in the wrong place \n" @@ -325,7 +325,7 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature) BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature) { ASTPointer contract; - ASTPointer function; + FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " uint256 stateVar;\n" " function fun1(uint256 a) {\n" -- cgit v1.2.3 From 2e4f4e3363586f3557bd36547d05a303d287015b Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 24 Nov 2015 00:20:37 +0100 Subject: Fix smart pointer lifetime issue in tests. --- test/libsolidity/SolidityParser.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index b494a1aa..7451397e 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -191,19 +191,17 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation) " function functionName(bytes32 input) returns (bytes32 out) {}\n" "}\n"; BOOST_CHECK(successParse(text)); - ErrorList e; - ASTPointer contract = parseText(text, e); + ErrorList errors; + ASTPointer contract = parseText(text, errors); FunctionDefinition const* function = nullptr; + auto functions = contract->definedFunctions(); - ErrorList errors; - auto functions = parseText(text, errors)->definedFunctions(); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function"); checkFunctionNatspec(function, "This is a test function"); } BOOST_AUTO_TEST_CASE(function_normal_comments) { - ASTPointer contract; FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " uint256 stateVar;\n" @@ -212,7 +210,8 @@ BOOST_AUTO_TEST_CASE(function_normal_comments) "}\n"; BOOST_CHECK(successParse(text)); ErrorList errors; - auto functions = parseText(text, errors)->definedFunctions(); + ASTPointer contract = parseText(text, errors); + auto functions = contract->definedFunctions(); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function"); BOOST_CHECK_MESSAGE(function->documentation() == nullptr, "Should not have gotten a Natspecc comment for this function"); @@ -220,7 +219,6 @@ BOOST_AUTO_TEST_CASE(function_normal_comments) BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) { - ASTPointer contract; FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " uint256 stateVar;\n" @@ -235,7 +233,8 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) "}\n"; BOOST_CHECK(successParse(text)); ErrorList errors; - auto functions = parseText(text, errors)->definedFunctions(); + ASTPointer contract = parseText(text, errors); + auto functions = contract->definedFunctions(); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function"); checkFunctionNatspec(function, "This is test function 1"); @@ -253,7 +252,6 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) BOOST_AUTO_TEST_CASE(multiline_function_documentation) { - ASTPointer contract; FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " uint256 stateVar;\n" @@ -263,7 +261,8 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) "}\n"; BOOST_CHECK(successParse(text)); ErrorList errors; - auto functions = parseText(text, errors)->definedFunctions(); + ASTPointer contract = parseText(text, errors); + auto functions = contract->definedFunctions(); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function"); checkFunctionNatspec(function, "This is a test function\n" " and it has 2 lines"); @@ -271,7 +270,6 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) { - ASTPointer contract; FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " /// fun1 description\n" @@ -288,7 +286,8 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) "}\n"; BOOST_CHECK(successParse(text)); ErrorList errors; - auto functions = parseText(text, errors)->definedFunctions(); + ASTPointer contract = parseText(text, errors); + auto functions = contract->definedFunctions(); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function"); checkFunctionNatspec(function, "fun1 description"); @@ -300,7 +299,6 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature) { - ASTPointer contract; FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " uint256 stateVar;\n" @@ -315,7 +313,8 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature) "}\n"; BOOST_CHECK(successParse(text)); ErrorList errors; - auto functions = parseText(text, errors)->definedFunctions(); + ASTPointer contract = parseText(text, errors); + auto functions = contract->definedFunctions(); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function"); BOOST_CHECK_MESSAGE(!function->documentation(), @@ -324,7 +323,6 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature) BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature) { - ASTPointer contract; FunctionDefinition const* function = nullptr; char const* text = "contract test {\n" " uint256 stateVar;\n" @@ -339,7 +337,8 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature) "}\n"; BOOST_CHECK(successParse(text)); ErrorList errors; - auto functions = parseText(text, errors)->definedFunctions(); + ASTPointer contract = parseText(text, errors); + auto functions = contract->definedFunctions(); ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function"); BOOST_CHECK_MESSAGE(!function->documentation(), -- cgit v1.2.3 From cc2df5f9f2726f92bebe95e2a94afb6ba32c785c Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 24 Nov 2015 17:08:13 +0100 Subject: Invalidate cached members if scope changes. --- libsolidity/ast/Types.cpp | 3 ++- libsolidity/ast/Types.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index a4da5b13..96f44571 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1787,7 +1787,7 @@ unsigned TypeType::sizeOnStack() const MemberList const& TypeType::members(ContractDefinition const* _currentScope) const { // We need to lazy-initialize it because of recursive references. - if (!m_members) + if (!m_members || m_cachedScope != _currentScope) { MemberList::MemberMap members; if (m_actualType->category() == Category::Contract) @@ -1818,6 +1818,7 @@ MemberList const& TypeType::members(ContractDefinition const* _currentScope) con members.push_back(MemberList::Member(enumValue->name(), enumType)); } m_members.reset(new MemberList(members)); + m_cachedScope = _currentScope; } return *m_members; } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 0769ba39..f841a1be 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -941,6 +941,7 @@ private: TypePointer m_actualType; /// List of member types, will be lazy-initialized because of recursive references. mutable std::unique_ptr m_members; + mutable ContractDefinition const* m_cachedScope = nullptr; }; -- cgit v1.2.3 From 4aaa150674d5970f651ab3e95e5b0e2daac0e7e0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 26 Nov 2015 17:28:44 +0100 Subject: Convert filter to template function. --- libsolidity/ast/AST.cpp | 54 ------------------------------------------------- libsolidity/ast/AST.h | 26 ++++++++++++++++++------ 2 files changed, 20 insertions(+), 60 deletions(-) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 65535388..6006d441 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -89,60 +89,6 @@ FunctionDefinition const* ContractDefinition::fallbackFunction() const return nullptr; } -vector ContractDefinition::definedStructs() const -{ - vector ret; - for (auto const& node: m_subNodes) - if (auto v = dynamic_cast(node.get())) - ret.push_back(v); - return ret; -} - -vector ContractDefinition::definedEnums() const -{ - vector ret; - for (auto const& node: m_subNodes) - if (auto v = dynamic_cast(node.get())) - ret.push_back(v); - return ret; -} - -vector ContractDefinition::stateVariables() const -{ - vector ret; - for (auto const& node: m_subNodes) - if (auto v = dynamic_cast(node.get())) - ret.push_back(v); - return ret; -} - -vector ContractDefinition::functionModifiers() const -{ - vector ret; - for (auto const& node: m_subNodes) - if (auto v = dynamic_cast(node.get())) - ret.push_back(v); - return ret; -} - -vector ContractDefinition::definedFunctions() const -{ - vector ret; - for (auto const& node: m_subNodes) - if (auto v = dynamic_cast(node.get())) - ret.push_back(v); - return ret; -} - -vector ContractDefinition::events() const -{ - vector ret; - for (auto const& node: m_subNodes) - if (auto v = dynamic_cast(node.get())) - ret.push_back(v); - return ret; -} - vector const& ContractDefinition::interfaceEvents() const { if (!m_interfaceEvents) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index ab872750..a28d9f4f 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -70,6 +70,10 @@ public: element->accept(_visitor); } + /// @returns a copy of the vector containing only the nodes which derive from T. + template + static std::vector<_T const*> filteredNodes(std::vector> const& _nodes); + /// Returns the source code location of this node. SourceLocation const& location() const { return m_location; } @@ -95,6 +99,16 @@ private: SourceLocation m_location; }; +template +std::vector<_T const*> ASTNode::filteredNodes(std::vector> const& _nodes) +{ + std::vector<_T const*> ret; + for (auto const& n: _nodes) + if (auto const* nt = dynamic_cast<_T const*>(n.get())) + ret.push_back(nt); + return ret; +} + /** * Source unit containing import directives and contract definitions. */ @@ -253,12 +267,12 @@ public: std::vector> const& baseContracts() const { return m_baseContracts; } std::vector> const& subNodes() const { return m_subNodes; } - std::vector definedStructs() const; - std::vector definedEnums() const; - std::vector stateVariables() const; - std::vector functionModifiers() const; - std::vector definedFunctions() const; - std::vector events() const; + std::vector definedStructs() const { return filteredNodes(m_subNodes); } + std::vector definedEnums() const { return filteredNodes(m_subNodes); } + std::vector stateVariables() const { return filteredNodes(m_subNodes); } + std::vector functionModifiers() const { return filteredNodes(m_subNodes); } + std::vector definedFunctions() const { return filteredNodes(m_subNodes); } + std::vector events() const { return filteredNodes(m_subNodes); } std::vector const& interfaceEvents() const; bool isLibrary() const { return m_isLibrary; } -- cgit v1.2.3