aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/ast/AST.cpp26
-rw-r--r--libsolidity/ast/AST.h6
-rw-r--r--libsolidity/codegen/CompilerContext.cpp1
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp7
-rw-r--r--libsolidity/interface/CompilerStack.cpp29
-rw-r--r--libsolidity/interface/CompilerStack.h74
-rw-r--r--libsolidity/interface/StandardCompiler.cpp41
7 files changed, 124 insertions, 60 deletions
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index 724a908f..ebc8bd48 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -84,13 +84,35 @@ SourceUnitAnnotation& SourceUnit::annotation() const
return dynamic_cast<SourceUnitAnnotation&>(*m_annotation);
}
-string Declaration::sourceUnitName() const
+set<SourceUnit const*> SourceUnit::referencedSourceUnits(bool _recurse, set<SourceUnit const*> _skipList) const
+{
+ set<SourceUnit const*> sourceUnits;
+ for (ImportDirective const* importDirective: filteredNodes<ImportDirective>(nodes()))
+ {
+ auto const& sourceUnit = importDirective->annotation().sourceUnit;
+ if (!_skipList.count(sourceUnit))
+ {
+ _skipList.insert(sourceUnit);
+ sourceUnits.insert(sourceUnit);
+ if (_recurse)
+ sourceUnits += sourceUnit->referencedSourceUnits(true, _skipList);
+ }
+ }
+ return sourceUnits;
+}
+
+SourceUnit const& Declaration::sourceUnit() const
{
solAssert(!!m_scope, "");
ASTNode const* scope = m_scope;
while (dynamic_cast<Declaration const*>(scope) && dynamic_cast<Declaration const*>(scope)->m_scope)
scope = dynamic_cast<Declaration const*>(scope)->m_scope;
- return dynamic_cast<SourceUnit const&>(*scope).annotation().path;
+ return dynamic_cast<SourceUnit const&>(*scope);
+}
+
+string Declaration::sourceUnitName() const
+{
+ return sourceUnit().annotation().path;
}
ImportAnnotation& ImportDirective::annotation() const
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 38396c43..e4656f72 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -136,6 +136,9 @@ public:
std::vector<ASTPointer<ASTNode>> nodes() const { return m_nodes; }
+ /// @returns a set of referenced SourceUnits. Recursively if @a _recurse is true.
+ std::set<SourceUnit const*> referencedSourceUnits(bool _recurse = false, std::set<SourceUnit const*> _skipList = std::set<SourceUnit const*>()) const;
+
private:
std::vector<ASTPointer<ASTNode>> m_nodes;
};
@@ -168,6 +171,9 @@ public:
ASTNode const* scope() const { return m_scope; }
void setScope(ASTNode const* _scope) { m_scope = _scope; }
+ /// @returns the source unit this declaration is present in.
+ SourceUnit const& sourceUnit() const;
+
/// @returns the source name this declaration is present in.
/// Can be combined with annotation().canonicalName to form a globally unique name.
std::string sourceUnitName() const;
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp
index 2110b93d..e52d14de 100644
--- a/libsolidity/codegen/CompilerContext.cpp
+++ b/libsolidity/codegen/CompilerContext.cpp
@@ -309,6 +309,7 @@ void CompilerContext::appendInlineAssembly(
if (stackDiff < 1 || stackDiff > 16)
BOOST_THROW_EXCEPTION(
CompilerError() <<
+ errinfo_sourceLocation(_identifier.location) <<
errinfo_comment("Stack too deep (" + to_string(stackDiff) + "), try removing local variables.")
);
if (_context == julia::IdentifierContext::RValue)
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 1e6dffe1..a35008bf 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -174,7 +174,12 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
retSizeOnStack = returnTypes.front()->sizeOnStack();
}
solAssert(retSizeOnStack == utils().sizeOnStack(returnTypes), "");
- solAssert(retSizeOnStack <= 15, "Stack is too deep.");
+ if (retSizeOnStack > 15)
+ BOOST_THROW_EXCEPTION(
+ CompilerError() <<
+ errinfo_sourceLocation(_varDecl.location()) <<
+ errinfo_comment("Stack too deep.")
+ );
m_context << dupInstruction(retSizeOnStack + 1);
m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction);
}
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index d7763928..02983a82 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -252,16 +252,6 @@ bool CompilerStack::parseAndAnalyze()
return parse() && analyze();
}
-vector<string> CompilerStack::contractNames() const
-{
- if (m_stackState < AnalysisSuccessful)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
- vector<string> contractNames;
- for (auto const& contract: m_contracts)
- contractNames.push_back(contract.first);
- return contractNames;
-}
-
bool CompilerStack::compile()
{
if (m_stackState < AnalysisSuccessful)
@@ -288,6 +278,16 @@ void CompilerStack::link()
}
}
+vector<string> CompilerStack::contractNames() const
+{
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
+ vector<string> contractNames;
+ for (auto const& contract: m_contracts)
+ contractNames.push_back(contract.first);
+ return contractNames;
+}
+
eth::AssemblyItems const* CompilerStack::assemblyItems(string const& _contractName) const
{
Contract const& currentContract = contract(_contractName);
@@ -753,9 +753,18 @@ string CompilerStack::createMetadata(Contract const& _contract) const
meta["language"] = "Solidity";
meta["compiler"]["version"] = VersionStringStrict;
+ /// All the source files (including self), which should be included in the metadata.
+ set<string> referencedSources;
+ referencedSources.insert(_contract.contract->sourceUnit().annotation().path);
+ for (auto const sourceUnit: _contract.contract->sourceUnit().referencedSourceUnits(true))
+ referencedSources.insert(sourceUnit->annotation().path);
+
meta["sources"] = Json::objectValue;
for (auto const& s: m_sources)
{
+ if (!referencedSources.count(s.first))
+ continue;
+
solAssert(s.second.scanner, "Scanner not available");
meta["sources"][s.first]["keccak256"] =
"0x" + toHex(dev::keccak256(s.second.scanner->source()).asBytes());
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index 356389db..d287f224 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -93,6 +93,17 @@ public:
m_errorList(),
m_errorReporter(m_errorList) {}
+ /// @returns the list of errors that occured during parsing and type checking.
+ ErrorList const& errors() { return m_errorReporter.errors(); }
+
+ /// @returns the current state.
+ State state() const { return m_stackState; }
+
+ /// Resets the compiler to a state where the sources are not parsed or even removed.
+ /// Sets the state to SourcesSet if @a _keepSources is true, otherwise to Empty.
+ /// All settings, with the exception of remappings, are reset.
+ void reset(bool _keepSources = false);
+
/// Sets path remappings in the format "context:prefix=target"
void setRemappings(std::vector<std::string> const& _remappings);
@@ -111,24 +122,23 @@ public:
m_optimizeRuns = _runs;
}
- /// Resets the compiler to a state where the sources are not parsed or even removed.
- /// Sets the state to SourcesSet if @a _keepSources is true, otherwise to Empty.
- /// All settings, with the exception of remappings, are reset.
- void reset(bool _keepSources = false);
-
/// Adds a source object (e.g. file) to the parser. After this, parse has to be called again.
/// @returns true if a source object by the name already existed and was replaced.
bool addSource(std::string const& _name, std::string const& _content, bool _isLibrary = false);
+
/// Parses all source units that were added
/// @returns false on error.
bool parse();
+
/// Performs the analysis steps (imports, scopesetting, syntaxCheck, referenceResolving,
/// typechecking, staticAnalysis) on previously set sources
/// @returns false on error.
bool analyze();
+
/// Parses and analyzes all source units that were added
/// @returns false on error.
bool parseAndAnalyze();
+
/// @returns a list of the contract names in the sources.
std::vector<std::string> contractNames() const;
@@ -136,43 +146,63 @@ public:
/// @returns false on error.
bool compile();
+ /// @returns the list of sources (paths) used
+ std::vector<std::string> sourceNames() const;
+
+ /// @returns a mapping assigning each source name its index inside the vector returned
+ /// by sourceNames().
+ std::map<std::string, unsigned> sourceIndices() const;
+
+ /// @returns the previously used scanner, useful for counting lines during error reporting.
+ Scanner const& scanner(std::string const& _sourceName = "") const;
+
+ /// @returns the parsed source unit with the supplied name.
+ SourceUnit const& ast(std::string const& _sourceName = "") const;
+
+ /// Helper function for logs printing. Do only use in error cases, it's quite expensive.
+ /// line and columns are numbered starting from 1 with following order:
+ /// start line, start column, end line, end column
+ std::tuple<int, int, int, int> positionFromSourceLocation(SourceLocation const& _sourceLocation) const;
+
+ /// @returns either the contract's name or a mixture of its name and source file, sanitized for filesystem use
+ std::string const filesystemFriendlyName(std::string const& _contractName) const;
+
/// @returns the assembled object for a contract.
eth::LinkerObject const& object(std::string const& _contractName = "") const;
+
/// @returns the runtime object for the contract.
eth::LinkerObject const& runtimeObject(std::string const& _contractName = "") const;
+
/// @returns the bytecode of a contract that uses an already deployed contract via DELEGATECALL.
/// The returned bytes will contain a sequence of 20 bytes of the format "XXX...XXX" which have to
/// substituted by the actual address. Note that this sequence starts end ends in three X
/// characters but can contain anything in between.
eth::LinkerObject const& cloneObject(std::string const& _contractName = "") const;
+
/// @returns normal contract assembly items
eth::AssemblyItems const* assemblyItems(std::string const& _contractName = "") const;
+
/// @returns runtime contract assembly items
eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName = "") const;
+
/// @returns the string that provides a mapping between bytecode and sourcecode or a nullptr
/// if the contract does not (yet) have bytecode.
std::string const* sourceMapping(std::string const& _contractName = "") const;
+
/// @returns the string that provides a mapping between runtime bytecode and sourcecode.
/// if the contract does not (yet) have bytecode.
std::string const* runtimeSourceMapping(std::string const& _contractName = "") const;
- /// @returns either the contract's name or a mixture of its name and source file, sanitized for filesystem use
- std::string const filesystemFriendlyName(std::string const& _contractName) const;
-
/// Streams a verbose version of the assembly to @a _outStream.
/// @arg _sourceCodes is the map of input files to source code strings
/// @arg _inJsonFromat shows whether the out should be in Json format
/// Prerequisite: Successful compilation.
Json::Value streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const;
- /// @returns the list of sources (paths) used
- std::vector<std::string> sourceNames() const;
- /// @returns a mapping assigning each source name its index inside the vector returned
- /// by sourceNames().
- std::map<std::string, unsigned> sourceIndices() const;
/// @returns a JSON representing the contract ABI.
/// Prerequisite: Successful call to parse or compile.
Json::Value const& contractABI(std::string const& _contractName = "") const;
+
/// @returns a JSON representing the contract's documentation.
/// Prerequisite: Successful call to parse or compile.
/// @param type The type of the documentation to get.
@@ -182,28 +212,13 @@ public:
/// @returns a JSON representing a map of method identifiers (hashes) to function names.
Json::Value methodIdentifiers(std::string const& _contractName) const;
+ /// @returns the Contract Metadata
std::string const& metadata(std::string const& _contractName) const;
void useMetadataLiteralSources(bool _metadataLiteralSources) { m_metadataLiteralSources = _metadataLiteralSources; }
/// @returns a JSON representing the estimated gas usage for contract creation, internal and external functions
Json::Value gasEstimates(std::string const& _contractName) const;
- /// @returns the previously used scanner, useful for counting lines during error reporting.
- Scanner const& scanner(std::string const& _sourceName = "") const;
- /// @returns the parsed source unit with the supplied name.
- SourceUnit const& ast(std::string const& _sourceName = "") const;
-
- /// Helper function for logs printing. Do only use in error cases, it's quite expensive.
- /// line and columns are numbered starting from 1 with following order:
- /// start line, start column, end line, end column
- std::tuple<int, int, int, int> positionFromSourceLocation(SourceLocation const& _sourceLocation) const;
-
- /// @returns the list of errors that occured during parsing and type checking.
- ErrorList const& errors() { return m_errorReporter.errors(); }
-
- /// @returns the current state.
- State state() const { return m_stackState; }
-
private:
/**
* Information pertaining to one source unit, filled gradually during parsing and compilation.
@@ -230,6 +245,7 @@ private:
mutable std::unique_ptr<std::string const> sourceMapping;
mutable std::unique_ptr<std::string const> runtimeSourceMapping;
};
+
/// Loads the missing sources from @a _ast (named @a _path) using the callback
/// @a m_readFile and stores the absolute paths of all imports in the AST annotations.
/// @returns the newly loaded sources.
diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp
index 23687340..dd135ce5 100644
--- a/libsolidity/interface/StandardCompiler.cpp
+++ b/libsolidity/interface/StandardCompiler.cpp
@@ -285,24 +285,27 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
));
}
}
+ /// This is only thrown in a very few locations.
catch (Error const& _error)
{
- if (_error.type() == Error::Type::DocstringParsingError)
- errors.append(formatError(
- false,
- "DocstringParsingError",
- "general",
- "Documentation parsing error: " + *boost::get_error_info<errinfo_comment>(_error)
- ));
- else
- errors.append(formatErrorWithException(
- _error,
- false,
- _error.typeName(),
- "general",
- "",
- scannerFromSourceName
- ));
+ errors.append(formatErrorWithException(
+ _error,
+ false,
+ _error.typeName(),
+ "general",
+ "Uncaught error: ",
+ scannerFromSourceName
+ ));
+ }
+ /// This should not be leaked from compile().
+ catch (FatalError const& _exception)
+ {
+ errors.append(formatError(
+ false,
+ "FatalError",
+ "general",
+ "Uncaught fatal error: " + boost::diagnostic_information(_exception)
+ ));
}
catch (CompilerError const& _exception)
{
@@ -322,7 +325,8 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
false,
"InternalCompilerError",
"general",
- "Internal compiler error (" + _exception.lineInfo() + ")", scannerFromSourceName
+ "Internal compiler error (" + _exception.lineInfo() + ")",
+ scannerFromSourceName
));
}
catch (UnimplementedFeatureError const& _exception)
@@ -333,7 +337,8 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
"UnimplementedFeatureError",
"general",
"Unimplemented feature (" + _exception.lineInfo() + ")",
- scannerFromSourceName));
+ scannerFromSourceName
+ ));
}
catch (Exception const& _exception)
{