diff options
author | chriseth <chris@ethereum.org> | 2018-12-03 22:48:03 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-03 22:48:03 +0800 |
commit | c8a2cb62832afb2dc09ccee6fd42c1516dfdb981 (patch) | |
tree | 7977e9dcbbc215088c05b847f849871ef5d4ae66 /libsolidity/interface/CompilerStack.cpp | |
parent | 1d4f565a64988a3400847d2655ca24f73f234bc6 (diff) | |
parent | 590be1d84cea9850ce69b68be3dc5294b39041e5 (diff) | |
download | dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.gz dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.bz2 dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.lz dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.xz dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.zst dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.zip |
Merge pull request #5571 from ethereum/develop
Version 0.5.1
Diffstat (limited to 'libsolidity/interface/CompilerStack.cpp')
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 84 |
1 files changed, 56 insertions, 28 deletions
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 441c7897..610caea1 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -27,8 +27,8 @@ #include <libsolidity/interface/Version.h> #include <libsolidity/analysis/SemVerHandler.h> #include <libsolidity/ast/AST.h> -#include <libsolidity/parsing/Scanner.h> #include <libsolidity/parsing/Parser.h> +#include <libsolidity/analysis/ContractLevelChecker.h> #include <libsolidity/analysis/ControlFlowAnalyzer.h> #include <libsolidity/analysis/ControlFlowGraph.h> #include <libsolidity/analysis/GlobalContext.h> @@ -45,10 +45,12 @@ #include <libsolidity/interface/Natspec.h> #include <libsolidity/interface/GasEstimator.h> -#include <libevmasm/Exceptions.h> - #include <libyul/YulString.h> +#include <liblangutil/Scanner.h> + +#include <libevmasm/Exceptions.h> + #include <libdevcore/SwarmHash.h> #include <libdevcore/JSON.h> @@ -58,6 +60,7 @@ using namespace std; using namespace dev; +using namespace langutil; using namespace dev::solidity; boost::optional<CompilerStack::Remapping> CompilerStack::parseRemapping(string const& _remapping) @@ -106,6 +109,8 @@ void CompilerStack::reset(bool _keepSources) m_stackState = Empty; m_sources.clear(); } + m_smtlib2Responses.clear(); + m_unhandledSMTLib2Queries.clear(); m_libraries.clear(); m_evmVersion = EVMVersion(); m_optimize = false; @@ -121,7 +126,7 @@ bool CompilerStack::addSource(string const& _name, string const& _content, bool { bool existed = m_sources.count(_name) != 0; reset(true); - m_sources[_name].scanner = make_shared<Scanner>(CharStream(_content), _name); + m_sources[_name].scanner = make_shared<Scanner>(CharStream(_content, _name)); m_sources[_name].isLibrary = _isLibrary; m_stackState = SourcesSet; return existed; @@ -156,7 +161,7 @@ bool CompilerStack::parse() { string const& newPath = newSource.first; string const& newContents = newSource.second; - m_sources[newPath].scanner = make_shared<Scanner>(CharStream(newContents), newPath); + m_sources[newPath].scanner = make_shared<Scanner>(CharStream(newContents, newPath)); sourcesToParse.push_back(newPath); } } @@ -221,8 +226,21 @@ bool CompilerStack::analyze() m_contracts[contract->fullyQualifiedName()].contract = contract; } - // This cannot be done in the above loop, because cross-contract types couldn't be resolved. - // A good example is `LibraryName.TypeName x;`. + // Next, we check inheritance, overrides, function collisions and other things at + // contract or function level. + // This also calculates whether a contract is abstract, which is needed by the + // type checker. + ContractLevelChecker contractLevelChecker(m_errorReporter); + for (Source const* source: m_sourceOrder) + for (ASTPointer<ASTNode> const& node: source->ast->nodes()) + if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) + if (!contractLevelChecker.check(*contract)) + noErrors = false; + + // New we run full type checks that go down to the expression level. This + // cannot be done earlier, because we need cross-contract types and information + // about whether a contract is abstract for the `new` expression. + // This populates the `type` annotation for all expressions. // // Note: this does not resolve overloaded functions. In order to do that, types of arguments are needed, // which is only done one step later. @@ -282,9 +300,10 @@ bool CompilerStack::analyze() if (noErrors) { - SMTChecker smtChecker(m_errorReporter, m_smtQuery); + SMTChecker smtChecker(m_errorReporter, m_smtlib2Responses); for (Source const* source: m_sourceOrder) smtChecker.analyze(*source->ast, source->scanner); + m_unhandledSMTLib2Queries += smtChecker.unhandledQueries(); } } catch(FatalError const&) @@ -329,13 +348,14 @@ bool CompilerStack::compile() if (auto contract = dynamic_cast<ContractDefinition const*>(node.get())) if (isRequestedContract(*contract)) compileContract(*contract, compiledContracts); - this->link(); m_stackState = CompilationSuccessful; + this->link(); return true; } void CompilerStack::link() { + solAssert(m_stackState >= CompilationSuccessful, ""); for (auto& contract: m_contracts) { contract.second.object.link(m_libraries); @@ -353,6 +373,19 @@ vector<string> CompilerStack::contractNames() const return contractNames; } +string const CompilerStack::lastContractName() const +{ + if (m_stackState < AnalysisSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + // try to find some user-supplied contract + string contractName; + for (auto const& it: m_sources) + for (ASTPointer<ASTNode> const& node: it.second.ast->nodes()) + if (auto contract = dynamic_cast<ContractDefinition const*>(node.get())) + contractName = contract->fullyQualifiedName(); + return contractName; +} + eth::AssemblyItems const* CompilerStack::assemblyItems(string const& _contractName) const { Contract const& currentContract = contract(_contractName); @@ -389,6 +422,9 @@ string const* CompilerStack::runtimeSourceMapping(string const& _contractName) c std::string const CompilerStack::filesystemFriendlyName(string const& _contractName) const { + if (m_stackState < AnalysisSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found.")); + // Look up the contract (by its fully-qualified name) Contract const& matchContract = m_contracts.at(_contractName); // Check to see if it could collide on name @@ -576,14 +612,15 @@ tuple<int, int, int, int> CompilerStack::positionFromSourceLocation(SourceLocati int startColumn; int endLine; int endColumn; - tie(startLine, startColumn) = scanner(*_sourceLocation.sourceName).translatePositionToLineColumn(_sourceLocation.start); - tie(endLine, endColumn) = scanner(*_sourceLocation.sourceName).translatePositionToLineColumn(_sourceLocation.end); + tie(startLine, startColumn) = scanner(_sourceLocation.source->name()).translatePositionToLineColumn(_sourceLocation.start); + tie(endLine, endColumn) = scanner(_sourceLocation.source->name()).translatePositionToLineColumn(_sourceLocation.end); return make_tuple(++startLine, ++startColumn, ++endLine, ++endColumn); } StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string const& _sourcePath) { + solAssert(m_stackState < ParsingSuccessful, ""); StringMap newSources; for (auto const& node: _ast.nodes()) if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get())) @@ -617,6 +654,7 @@ StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string string CompilerStack::applyRemapping(string const& _path, string const& _context) { + solAssert(m_stackState < ParsingSuccessful, ""); // Try to find the longest prefix match in all remappings that are active in the current context. auto isPrefixOf = [](string const& _a, string const& _b) { @@ -658,6 +696,8 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context void CompilerStack::resolveImports() { + solAssert(m_stackState == ParsingSuccessful, ""); + // topological sorting (depth first search) of the import graph, cutting potential cycles vector<Source const*> sourceOrder; set<Source const*> sourcesSeen; @@ -702,6 +742,8 @@ void CompilerStack::compileContract( map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts ) { + solAssert(m_stackState >= AnalysisSuccessful, ""); + if ( _compiledContracts.count(&_contract) || !_contract.annotation().unimplementedFunctions.empty() || @@ -757,23 +799,9 @@ void CompilerStack::compileContract( _compiledContracts[compiledContract.contract] = &compiler->assembly(); } -string const CompilerStack::lastContractName() const -{ - if (m_contracts.empty()) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found.")); - // try to find some user-supplied contract - string contractName; - for (auto const& it: m_sources) - for (ASTPointer<ASTNode> const& node: it.second.ast->nodes()) - if (auto contract = dynamic_cast<ContractDefinition const*>(node.get())) - contractName = contract->fullyQualifiedName(); - return contractName; -} - CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const { - if (m_contracts.empty()) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found.")); + solAssert(m_stackState >= AnalysisSuccessful, ""); auto it = m_contracts.find(_contractName); if (it != m_contracts.end()) @@ -908,8 +936,8 @@ string CompilerStack::computeSourceMapping(eth::AssemblyItems const& _items) con SourceLocation const& location = item.location(); int length = location.start != -1 && location.end != -1 ? location.end - location.start : -1; int sourceIndex = - location.sourceName && sourceIndicesMap.count(*location.sourceName) ? - sourceIndicesMap.at(*location.sourceName) : + location.source && sourceIndicesMap.count(location.source->name()) ? + sourceIndicesMap.at(location.source->name()) : -1; char jump = '-'; if (item.getJumpType() == eth::AssemblyItem::JumpType::IntoFunction) |