mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Relative paths in import directives.
This commit is contained in:
parent
7cb7818cea
commit
f8228e8ab1
@ -71,19 +71,25 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So
|
|||||||
for (auto const& node: _sourceUnit.nodes())
|
for (auto const& node: _sourceUnit.nodes())
|
||||||
if (auto imp = dynamic_cast<ImportDirective const*>(node.get()))
|
if (auto imp = dynamic_cast<ImportDirective const*>(node.get()))
|
||||||
{
|
{
|
||||||
if (!_sourceUnits.count(imp->identifier()))
|
string const& path = imp->annotation().absolutePath;
|
||||||
|
if (!_sourceUnits.count(path))
|
||||||
{
|
{
|
||||||
reportDeclarationError(node->location(), "Import \"" + imp->identifier() + "\" not found.");
|
reportDeclarationError( node->location(),
|
||||||
|
"Import \"" +
|
||||||
|
path +
|
||||||
|
"\" (referenced as \"" +
|
||||||
|
imp->identifier() +
|
||||||
|
"\") not found."
|
||||||
|
);
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto scope = m_scopes.find(_sourceUnits.at(imp->identifier()));
|
auto scope = m_scopes.find(_sourceUnits.at(path));
|
||||||
solAssert(scope != end(m_scopes), "");
|
solAssert(scope != end(m_scopes), "");
|
||||||
for (auto const& nameAndDeclaration: scope->second->declarations())
|
for (auto const& nameAndDeclaration: scope->second->declarations())
|
||||||
for (auto const& declaration: nameAndDeclaration.second)
|
for (auto const& declaration: nameAndDeclaration.second)
|
||||||
target.registerDeclaration(*declaration, &nameAndDeclaration.first);
|
target.registerDeclaration(*declaration, &nameAndDeclaration.first);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return !error;
|
return !error;
|
||||||
|
@ -56,6 +56,13 @@ Error ASTNode::createTypeError(string const& _description) const
|
|||||||
return Error(Error::Type::TypeError) << errinfo_sourceLocation(location()) << errinfo_comment(_description);
|
return Error(Error::Type::TypeError) << errinfo_sourceLocation(location()) << errinfo_comment(_description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImportAnnotation& ImportDirective::annotation() const
|
||||||
|
{
|
||||||
|
if (!m_annotation)
|
||||||
|
m_annotation = new ImportAnnotation();
|
||||||
|
return static_cast<ImportAnnotation&>(*m_annotation);
|
||||||
|
}
|
||||||
|
|
||||||
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
|
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
|
||||||
{
|
{
|
||||||
auto exportedFunctionList = interfaceFunctionList();
|
auto exportedFunctionList = interfaceFunctionList();
|
||||||
|
@ -142,6 +142,7 @@ public:
|
|||||||
virtual void accept(ASTConstVisitor& _visitor) const override;
|
virtual void accept(ASTConstVisitor& _visitor) const override;
|
||||||
|
|
||||||
ASTString const& identifier() const { return *m_identifier; }
|
ASTString const& identifier() const { return *m_identifier; }
|
||||||
|
virtual ImportAnnotation& annotation() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ASTPointer<ASTString> m_identifier;
|
ASTPointer<ASTString> m_identifier;
|
||||||
|
@ -54,6 +54,12 @@ struct DocumentedAnnotation
|
|||||||
std::multimap<std::string, DocTag> docTags;
|
std::multimap<std::string, DocTag> docTags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ImportAnnotation: ASTAnnotation
|
||||||
|
{
|
||||||
|
/// The absolute path of the source unit to import.
|
||||||
|
std::string absolutePath;
|
||||||
|
};
|
||||||
|
|
||||||
struct TypeDeclarationAnnotation: ASTAnnotation
|
struct TypeDeclarationAnnotation: ASTAnnotation
|
||||||
{
|
{
|
||||||
/// The name of this type, prefixed by proper namespaces if globally accessible.
|
/// The name of this type, prefixed by proper namespaces if globally accessible.
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
#include <libsolidity/parsing/Scanner.h>
|
#include <libsolidity/parsing/Scanner.h>
|
||||||
#include <libsolidity/parsing/Parser.h>
|
#include <libsolidity/parsing/Parser.h>
|
||||||
@ -367,7 +368,7 @@ void CompilerStack::resolveImports()
|
|||||||
vector<Source const*> sourceOrder;
|
vector<Source const*> sourceOrder;
|
||||||
set<Source const*> sourcesSeen;
|
set<Source const*> sourcesSeen;
|
||||||
|
|
||||||
function<void(Source const*)> toposort = [&](Source const* _source)
|
function<void(string const&, Source const*)> toposort = [&](string const& _sourceName, Source const* _source)
|
||||||
{
|
{
|
||||||
if (sourcesSeen.count(_source))
|
if (sourcesSeen.count(_source))
|
||||||
return;
|
return;
|
||||||
@ -375,26 +376,44 @@ void CompilerStack::resolveImports()
|
|||||||
for (ASTPointer<ASTNode> const& node: _source->ast->nodes())
|
for (ASTPointer<ASTNode> const& node: _source->ast->nodes())
|
||||||
if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
|
if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
|
||||||
{
|
{
|
||||||
string const& id = import->identifier();
|
string path = absolutePath(import->identifier(), _sourceName);
|
||||||
if (!m_sources.count(id))
|
import->annotation().absolutePath = path;
|
||||||
|
if (!m_sources.count(path))
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
Error(Error::Type::ParserError)
|
Error(Error::Type::ParserError)
|
||||||
<< errinfo_sourceLocation(import->location())
|
<< errinfo_sourceLocation(import->location())
|
||||||
<< errinfo_comment("Source not found.")
|
<< errinfo_comment("Source not found.")
|
||||||
);
|
);
|
||||||
|
|
||||||
toposort(&m_sources[id]);
|
toposort(path, &m_sources[path]);
|
||||||
}
|
}
|
||||||
sourceOrder.push_back(_source);
|
sourceOrder.push_back(_source);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto const& sourcePair: m_sources)
|
for (auto const& sourcePair: m_sources)
|
||||||
if (!sourcePair.second.isLibrary)
|
if (!sourcePair.second.isLibrary)
|
||||||
toposort(&sourcePair.second);
|
toposort(sourcePair.first, &sourcePair.second);
|
||||||
|
|
||||||
swap(m_sourceOrder, sourceOrder);
|
swap(m_sourceOrder, sourceOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
path result(_reference);
|
||||||
|
result.remove_filename();
|
||||||
|
for (path::iterator it = p.begin(); it != p.end(); ++it)
|
||||||
|
if (*it == "..")
|
||||||
|
result = result.parent_path();
|
||||||
|
else if (*it != ".")
|
||||||
|
result /= *it;
|
||||||
|
return result.string();
|
||||||
|
}
|
||||||
|
|
||||||
void CompilerStack::compileContract(
|
void CompilerStack::compileContract(
|
||||||
bool _optimize,
|
bool _optimize,
|
||||||
unsigned _runs,
|
unsigned _runs,
|
||||||
|
@ -199,6 +199,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void resolveImports();
|
void resolveImports();
|
||||||
|
/// @returns the absolute path corresponding to @a _path relative to @a _reference.
|
||||||
|
std::string absolutePath(std::string const& _path, std::string const& _reference) const;
|
||||||
/// Compile a single contract and put the result in @a _compiledContracts.
|
/// Compile a single contract and put the result in @a _compiledContracts.
|
||||||
void compileContract(
|
void compileContract(
|
||||||
bool _optimize,
|
bool _optimize,
|
||||||
|
@ -76,6 +76,23 @@ BOOST_AUTO_TEST_CASE(circular_import)
|
|||||||
BOOST_CHECK(c.compile());
|
BOOST_CHECK(c.compile());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(relative_import)
|
||||||
|
{
|
||||||
|
CompilerStack c;
|
||||||
|
c.addSource("a", "import \"./dir/b\"; contract A is B {}");
|
||||||
|
c.addSource("dir/b", "contract B {}");
|
||||||
|
c.addSource("dir/c", "import \"../a\"; contract C is A {}");
|
||||||
|
BOOST_CHECK(c.compile());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(relative_import_multiplex)
|
||||||
|
{
|
||||||
|
CompilerStack c;
|
||||||
|
c.addSource("a", "contract A {}");
|
||||||
|
c.addSource("dir/a/b/c", "import \"../../.././a\"; contract B is A {}");
|
||||||
|
BOOST_CHECK(c.compile());
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user