aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/analysis
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-12-15 18:43:59 +0800
committerchriseth <c@ethdev.com>2015-12-15 18:43:59 +0800
commit591a4f1ff44af20fce9bafebf0fa0607e2bdfcc0 (patch)
tree282c36887814420e2fa86e132587ec9f192f30ad /libsolidity/analysis
parent98684cca9035c754adcdc99fd196716cb7802efd (diff)
parent53da78e6091d9bb0229b4a54a0042e23487550db (diff)
downloaddexon-solidity-591a4f1ff44af20fce9bafebf0fa0607e2bdfcc0.tar.gz
dexon-solidity-591a4f1ff44af20fce9bafebf0fa0607e2bdfcc0.tar.zst
dexon-solidity-591a4f1ff44af20fce9bafebf0fa0607e2bdfcc0.zip
Merge pull request #288 from chriseth/import_contexts
Do not clutter importee when importing.
Diffstat (limited to 'libsolidity/analysis')
-rw-r--r--libsolidity/analysis/DeclarationContainer.cpp38
-rw-r--r--libsolidity/analysis/DeclarationContainer.h13
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.cpp93
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.h27
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp10
5 files changed, 123 insertions, 58 deletions
diff --git a/libsolidity/analysis/DeclarationContainer.cpp b/libsolidity/analysis/DeclarationContainer.cpp
index 7339ad5d..ac56562e 100644
--- a/libsolidity/analysis/DeclarationContainer.cpp
+++ b/libsolidity/analysis/DeclarationContainer.cpp
@@ -28,15 +28,19 @@ using namespace std;
using namespace dev;
using namespace dev::solidity;
-Declaration const* DeclarationContainer::conflictingDeclaration(Declaration const& _declaration) const
+Declaration const* DeclarationContainer::conflictingDeclaration(
+ Declaration const& _declaration,
+ ASTString const* _name
+) const
{
- ASTString const& declarationName(_declaration.name());
- solAssert(!declarationName.empty(), "");
+ if (!_name)
+ _name = &_declaration.name();
+ solAssert(!_name->empty(), "");
vector<Declaration const*> declarations;
- if (m_declarations.count(declarationName))
- declarations += m_declarations.at(declarationName);
- if (m_invisibleDeclarations.count(declarationName))
- declarations += m_invisibleDeclarations.at(declarationName);
+ if (m_declarations.count(*_name))
+ declarations += m_declarations.at(*_name);
+ if (m_invisibleDeclarations.count(*_name))
+ declarations += m_invisibleDeclarations.at(*_name);
if (dynamic_cast<FunctionDefinition const*>(&_declaration))
{
@@ -51,25 +55,31 @@ Declaration const* DeclarationContainer::conflictingDeclaration(Declaration cons
return nullptr;
}
-bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _invisible, bool _update)
+bool DeclarationContainer::registerDeclaration(
+ Declaration const& _declaration,
+ ASTString const* _name,
+ bool _invisible,
+ bool _update
+)
{
- ASTString const& declarationName(_declaration.name());
- if (declarationName.empty())
+ if (!_name)
+ _name = &_declaration.name();
+ if (_name->empty())
return true;
if (_update)
{
solAssert(!dynamic_cast<FunctionDefinition const*>(&_declaration), "Attempt to update function definition.");
- m_declarations.erase(declarationName);
- m_invisibleDeclarations.erase(declarationName);
+ m_declarations.erase(*_name);
+ m_invisibleDeclarations.erase(*_name);
}
else if (conflictingDeclaration(_declaration))
return false;
if (_invisible)
- m_invisibleDeclarations[declarationName].push_back(&_declaration);
+ m_invisibleDeclarations[*_name].push_back(&_declaration);
else
- m_declarations[declarationName].push_back(&_declaration);
+ m_declarations[*_name].push_back(&_declaration);
return true;
}
diff --git a/libsolidity/analysis/DeclarationContainer.h b/libsolidity/analysis/DeclarationContainer.h
index 064724d1..5862f7a5 100644
--- a/libsolidity/analysis/DeclarationContainer.h
+++ b/libsolidity/analysis/DeclarationContainer.h
@@ -41,23 +41,24 @@ class DeclarationContainer
{
public:
explicit DeclarationContainer(
- Declaration const* _enclosingDeclaration = nullptr,
+ ASTNode const* _enclosingNode = nullptr,
DeclarationContainer const* _enclosingContainer = nullptr
):
- m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {}
+ m_enclosingNode(_enclosingNode), m_enclosingContainer(_enclosingContainer) {}
/// Registers the declaration in the scope unless its name is already declared or the name is empty.
+ /// @param _name the name to register, if nullptr the intrinsic name of @a _declaration is used.
/// @param _invisible if true, registers the declaration, reports name clashes but does not return it in @a resolveName
/// @param _update if true, replaces a potential declaration that is already present
/// @returns false if the name was already declared.
- bool registerDeclaration(Declaration const& _declaration, bool _invisible = false, bool _update = false);
+ bool registerDeclaration(Declaration const& _declaration, ASTString const* _name = nullptr, bool _invisible = false, bool _update = false);
std::vector<Declaration const*> resolveName(ASTString const& _name, bool _recursive = false) const;
- Declaration const* enclosingDeclaration() const { return m_enclosingDeclaration; }
+ ASTNode const* enclosingNode() const { return m_enclosingNode; }
std::map<ASTString, std::vector<Declaration const*>> const& declarations() const { return m_declarations; }
/// @returns whether declaration is valid, and if not also returns previous declaration.
- Declaration const* conflictingDeclaration(Declaration const& _declaration) const;
+ Declaration const* conflictingDeclaration(Declaration const& _declaration, ASTString const* _name = nullptr) const;
private:
- Declaration const* m_enclosingDeclaration;
+ ASTNode const* m_enclosingNode;
DeclarationContainer const* m_enclosingContainer;
std::map<ASTString, std::vector<Declaration const*>> m_declarations;
std::map<ASTString, std::vector<Declaration const*>> m_invisibleDeclarations;
diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp
index 612989e1..efdb1953 100644
--- a/libsolidity/analysis/NameAndTypeResolver.cpp
+++ b/libsolidity/analysis/NameAndTypeResolver.cpp
@@ -38,12 +38,18 @@ NameAndTypeResolver::NameAndTypeResolver(
) :
m_errors(_errors)
{
+ if (!m_scopes[nullptr])
+ m_scopes[nullptr].reset(new DeclarationContainer());
for (Declaration const* declaration: _globals)
- m_scopes[nullptr].registerDeclaration(*declaration);
+ m_scopes[nullptr]->registerDeclaration(*declaration);
}
bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit)
{
+ solAssert(!m_scopes[&_sourceUnit], "");
+ m_scopes[&_sourceUnit].reset(new DeclarationContainer(nullptr, m_scopes[nullptr].get()));
+ m_currentScope = m_scopes[&_sourceUnit].get();
+
// The helper registers all declarations in m_scopes as a side-effect of its construction.
try
{
@@ -58,11 +64,43 @@ bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit)
return true;
}
+bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, SourceUnit const*> const& _sourceUnits)
+{
+ DeclarationContainer& target = *m_scopes.at(&_sourceUnit);
+ bool error = false;
+ for (auto const& node: _sourceUnit.nodes())
+ if (auto imp = dynamic_cast<ImportDirective const*>(node.get()))
+ {
+ string const& path = imp->annotation().absolutePath;
+ if (!_sourceUnits.count(path))
+ {
+ reportDeclarationError( node->location(),
+ "Import \"" +
+ path +
+ "\" (referenced as \"" +
+ imp->identifier() +
+ "\") not found."
+ );
+ error = true;
+ }
+ else
+ {
+ auto scope = m_scopes.find(_sourceUnits.at(path));
+ solAssert(scope != end(m_scopes), "");
+ for (auto const& nameAndDeclaration: scope->second->declarations())
+ for (auto const& declaration: nameAndDeclaration.second)
+ target.registerDeclaration(*declaration, &nameAndDeclaration.first);
+ }
+ }
+ return !error;
+}
+
bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
{
try
{
- m_currentScope = &m_scopes[nullptr];
+ m_currentScope = m_scopes[_contract.scope()].get();
+ solAssert(!!m_currentScope, "");
ReferencesResolver resolver(m_errors, *this, nullptr);
bool success = true;
@@ -70,12 +108,12 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
if (!resolver.resolve(*baseContract))
success = false;
- m_currentScope = &m_scopes[&_contract];
+ m_currentScope = m_scopes[&_contract].get();
if (success)
{
linearizeBaseContracts(_contract);
- std::vector<ContractDefinition const*> properBases(
+ vector<ContractDefinition const*> properBases(
++_contract.annotation().linearizedBaseContracts.begin(),
_contract.annotation().linearizedBaseContracts.end()
);
@@ -87,7 +125,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
// these can contain code, only resolve parameters for now
for (ASTPointer<ASTNode> const& node: _contract.subNodes())
{
- m_currentScope = &m_scopes[m_scopes.count(node.get()) ? node.get() : &_contract];
+ m_currentScope = m_scopes[m_scopes.count(node.get()) ? node.get() : &_contract].get();
if (!resolver.resolve(*node))
success = false;
}
@@ -95,12 +133,12 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
if (!success)
return false;
- m_currentScope = &m_scopes[&_contract];
+ m_currentScope = m_scopes[&_contract].get();
// now resolve references inside the code
for (ModifierDefinition const* modifier: _contract.functionModifiers())
{
- m_currentScope = &m_scopes[modifier];
+ m_currentScope = m_scopes[modifier].get();
ReferencesResolver resolver(m_errors, *this, nullptr, true);
if (!resolver.resolve(*modifier))
success = false;
@@ -108,7 +146,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
for (FunctionDefinition const* function: _contract.definedFunctions())
{
- m_currentScope = &m_scopes[function];
+ m_currentScope = m_scopes[function].get();
if (!ReferencesResolver(
m_errors,
*this,
@@ -133,7 +171,7 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
{
try
{
- m_scopes[nullptr].registerDeclaration(_declaration, false, true);
+ m_scopes[nullptr]->registerDeclaration(_declaration, nullptr, false, true);
solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope.");
}
catch (FatalError const&)
@@ -145,12 +183,12 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
return true;
}
-vector<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const
+vector<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, ASTNode const* _scope) const
{
auto iterator = m_scopes.find(_scope);
if (iterator == end(m_scopes))
return vector<Declaration const*>({});
- return iterator->second.resolveName(_name, false);
+ return iterator->second->resolveName(_name, false);
}
vector<Declaration const*> NameAndTypeResolver::nameFromCurrentScope(ASTString const& _name, bool _recursive) const
@@ -166,7 +204,7 @@ Declaration const* NameAndTypeResolver::pathFromCurrentScope(vector<ASTString> c
{
if (!m_scopes.count(candidates.front()))
return nullptr;
- candidates = m_scopes.at(candidates.front()).resolveName(_path[i], false);
+ candidates = m_scopes.at(candidates.front())->resolveName(_path[i], false);
}
if (candidates.size() == 1)
return candidates.front();
@@ -210,7 +248,7 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base)
{
auto iterator = m_scopes.find(&_base);
solAssert(iterator != end(m_scopes), "");
- for (auto const& nameAndDeclaration: iterator->second.declarations())
+ for (auto const& nameAndDeclaration: iterator->second->declarations())
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())
@@ -342,14 +380,15 @@ void NameAndTypeResolver::reportFatalTypeError(Error const& _e)
}
DeclarationRegistrationHelper::DeclarationRegistrationHelper(
- map<ASTNode const*, DeclarationContainer>& _scopes,
+ map<ASTNode const*, unique_ptr<DeclarationContainer>>& _scopes,
ASTNode& _astRoot,
ErrorList& _errors
):
m_scopes(_scopes),
- m_currentScope(nullptr),
+ m_currentScope(&_astRoot),
m_errors(_errors)
{
+ solAssert(!!m_scopes.at(m_currentScope), "");
_astRoot.accept(*this);
}
@@ -450,9 +489,10 @@ void DeclarationRegistrationHelper::endVisit(EventDefinition&)
void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declaration)
{
- map<ASTNode const*, DeclarationContainer>::iterator iter;
+ map<ASTNode const*, unique_ptr<DeclarationContainer>>::iterator iter;
bool newlyAdded;
- tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, DeclarationContainer(m_currentScope, &m_scopes[m_currentScope]));
+ unique_ptr<DeclarationContainer> container(new DeclarationContainer(m_currentScope, m_scopes[m_currentScope].get()));
+ tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, move(container));
solAssert(newlyAdded, "Unable to add new scope.");
m_currentScope = &_declaration;
}
@@ -460,16 +500,16 @@ void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declara
void DeclarationRegistrationHelper::closeCurrentScope()
{
solAssert(m_currentScope, "Closed non-existing scope.");
- m_currentScope = m_scopes[m_currentScope].enclosingDeclaration();
+ m_currentScope = m_scopes[m_currentScope]->enclosingNode();
}
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
{
- if (!m_scopes[m_currentScope].registerDeclaration(_declaration, !_declaration.isVisibleInContract()))
+ if (!m_scopes[m_currentScope]->registerDeclaration(_declaration, nullptr, !_declaration.isVisibleInContract()))
{
SourceLocation firstDeclarationLocation;
SourceLocation secondDeclarationLocation;
- Declaration const* conflictingDeclaration = m_scopes[m_currentScope].conflictingDeclaration(_declaration);
+ Declaration const* conflictingDeclaration = m_scopes[m_currentScope]->conflictingDeclaration(_declaration);
solAssert(conflictingDeclaration, "");
if (_declaration.location().start < conflictingDeclaration->location().start)
@@ -500,14 +540,17 @@ string DeclarationRegistrationHelper::currentCanonicalName() const
{
string ret;
for (
- Declaration const* scope = m_currentScope;
+ ASTNode const* scope = m_currentScope;
scope != nullptr;
- scope = m_scopes[scope].enclosingDeclaration()
+ scope = m_scopes[scope]->enclosingNode()
)
{
- if (!ret.empty())
- ret = "." + ret;
- ret = scope->name() + ret;
+ if (auto decl = dynamic_cast<Declaration const*>(scope))
+ {
+ if (!ret.empty())
+ ret = "." + ret;
+ ret = decl->name() + ret;
+ }
}
return ret;
}
diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h
index 1547a274..3c444aba 100644
--- a/libsolidity/analysis/NameAndTypeResolver.h
+++ b/libsolidity/analysis/NameAndTypeResolver.h
@@ -46,6 +46,8 @@ public:
/// Registers all declarations found in the source unit.
/// @returns false in case of error.
bool registerDeclarations(SourceUnit& _sourceUnit);
+ /// Applies the effect of import directives.
+ bool performImports(SourceUnit& _sourceUnit, std::map<std::string, SourceUnit const*> const& _sourceUnits);
/// Resolves all names and types referenced from the given contract.
/// @returns false in case of error.
bool resolveNamesAndTypes(ContractDefinition& _contract);
@@ -55,9 +57,9 @@ public:
bool updateDeclaration(Declaration const& _declaration);
/// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted,
- /// the global scope is used (i.e. the one containing only the contract).
+ /// the global scope is used (i.e. the one containing only the pre-defined global variables).
/// @returns a pointer to the declaration on success or nullptr on failure.
- std::vector<Declaration const*> resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const;
+ std::vector<Declaration const*> resolveName(ASTString const& _name, ASTNode const* _scope = nullptr) const;
/// Resolves a name in the "current" scope. Should only be called during the initial
/// resolving phase.
@@ -88,11 +90,6 @@ private:
template <class _T>
static std::vector<_T const*> cThreeMerge(std::list<std::list<_T const*>>& _toMerge);
- /// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration,
- /// where nullptr denotes the global scope. Note that structs are not scope since they do
- /// not contain code.
- std::map<ASTNode const*, DeclarationContainer> m_scopes;
-
// creates the Declaration error and adds it in the errors list
void reportDeclarationError(
SourceLocation _sourceLoction,
@@ -110,6 +107,12 @@ private:
// creates the Declaration error and adds it in the errors list and throws FatalError
void reportFatalTypeError(Error const& _e);
+
+ /// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration,
+ /// where nullptr denotes the global scope. Note that structs are not scope since they do
+ /// not contain code.
+ std::map<ASTNode const*, std::unique_ptr<DeclarationContainer>> m_scopes;
+
DeclarationContainer* m_currentScope = nullptr;
ErrorList& m_errors;
};
@@ -121,7 +124,11 @@ private:
class DeclarationRegistrationHelper: private ASTVisitor
{
public:
- DeclarationRegistrationHelper(std::map<ASTNode const*, DeclarationContainer>& _scopes, ASTNode& _astRoot, ErrorList& _errors);
+ DeclarationRegistrationHelper(
+ std::map<ASTNode const*, std::unique_ptr<DeclarationContainer>>& _scopes,
+ ASTNode& _astRoot,
+ ErrorList& _errors
+ );
private:
bool visit(ContractDefinition& _contract) override;
@@ -159,8 +166,8 @@ private:
// creates the Declaration error and adds it in the errors list and throws FatalError
void fatalDeclarationError(SourceLocation _sourceLocation, std::string const& _description);
- std::map<ASTNode const*, DeclarationContainer>& m_scopes;
- Declaration const* m_currentScope = nullptr;
+ std::map<ASTNode const*, std::unique_ptr<DeclarationContainer>>& m_scopes;
+ ASTNode const* m_currentScope = nullptr;
VariableScope* m_currentFunction = nullptr;
ErrorList& m_errors;
};
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index 2fe53e8b..ca002f58 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -139,7 +139,9 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
bool isPointer = true;
if (_variable.isExternalCallableParameter())
{
- auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
+ auto const& contract = dynamic_cast<ContractDefinition const&>(
+ *dynamic_cast<Declaration const&>(*_variable.scope()).scope()
+ );
if (contract.isLibrary())
{
if (varLoc == Location::Memory)
@@ -162,9 +164,11 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
else
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
}
- else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
+ else if (_variable.isCallableParameter() && dynamic_cast<Declaration const&>(*_variable.scope()).isPublic())
{
- auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
+ auto const& contract = dynamic_cast<ContractDefinition const&>(
+ *dynamic_cast<Declaration const&>(*_variable.scope()).scope()
+ );
// force locations of public or external function (return) parameters to memory
if (varLoc == Location::Storage && !contract.isLibrary())
fatalTypeError(_variable.location(),