diff options
Diffstat (limited to 'libsolidity/interface')
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 117 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.h | 21 |
2 files changed, 133 insertions, 5 deletions
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index c28e926b..f7982872 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -253,9 +253,11 @@ void CompilerStack::link(const std::map<string, h160>& _libraries) } } -bool CompilerStack::prepareFormalAnalysis() +bool CompilerStack::prepareFormalAnalysis(ErrorList* _errors) { - Why3Translator translator(m_errors); + if (!_errors) + _errors = &m_errors; + Why3Translator translator(*_errors); for (Source const* source: m_sourceOrder) if (!translator.process(*source->ast)) return false; @@ -277,6 +279,28 @@ eth::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _con return currentContract.compiler ? &contract(_contractName).compiler->runtimeAssemblyItems() : nullptr; } +string const* CompilerStack::sourceMapping(string const& _contractName) const +{ + Contract const& c = contract(_contractName); + if (!c.sourceMapping) + { + if (auto items = assemblyItems(_contractName)) + c.sourceMapping.reset(new string(computeSourceMapping(*items))); + } + return c.sourceMapping.get(); +} + +string const* CompilerStack::runtimeSourceMapping(string const& _contractName) const +{ + Contract const& c = contract(_contractName); + if (!c.runtimeSourceMapping) + { + if (auto items = runtimeAssemblyItems(_contractName)) + c.runtimeSourceMapping.reset(new string(computeSourceMapping(*items))); + } + return c.runtimeSourceMapping.get(); +} + eth::LinkerObject const& CompilerStack::object(string const& _contractName) const { return contract(_contractName).object; @@ -313,6 +337,22 @@ Json::Value CompilerStack::streamAssembly(ostream& _outStream, string const& _co } } +vector<string> CompilerStack::sourceNames() const +{ + vector<string> names; + for (auto const& s: m_sources) + names.push_back(s.first); + return names; +} + +map<string, unsigned> CompilerStack::sourceIndices() const +{ + map<string, unsigned> indices; + for (auto const& s: m_sources) + indices[s.first] = indices.size(); + return indices; +} + string const& CompilerStack::interface(string const& _contractName) const { return metadata(_contractName, DocumentationType::ABIInterface); @@ -602,3 +642,76 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co return it->second; } + +string CompilerStack::computeSourceMapping(eth::AssemblyItems const& _items) const +{ + string ret; + map<string, unsigned> sourceIndicesMap = sourceIndices(); + int prevStart = -1; + int prevLength = -1; + int prevSourceIndex = -1; + char prevJump = 0; + for (auto const& item: _items) + { + if (!ret.empty()) + ret += ";"; + + 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) : + -1; + char jump = '-'; + if (item.getJumpType() == eth::AssemblyItem::JumpType::IntoFunction) + jump = 'i'; + else if (item.getJumpType() == eth::AssemblyItem::JumpType::OutOfFunction) + jump = 'o'; + + unsigned components = 4; + if (jump == prevJump) + { + components--; + if (sourceIndex == prevSourceIndex) + { + components--; + if (length == prevLength) + { + components--; + if (location.start == prevStart) + components--; + } + } + } + + if (components-- > 0) + { + if (location.start != prevStart) + ret += std::to_string(location.start); + if (components-- > 0) + { + ret += ':'; + if (length != prevLength) + ret += std::to_string(length); + if (components-- > 0) + { + ret += ':'; + if (sourceIndex != prevSourceIndex) + ret += std::to_string(sourceIndex); + if (components-- > 0) + { + ret += ':'; + if (jump != prevJump) + ret += jump; + } + } + } + } + + prevStart = location.start; + prevLength = length; + prevSourceIndex = sourceIndex; + prevJump = jump; + } + return ret; +} diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index e111c982..a4b8447f 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -124,8 +124,9 @@ public: void link(std::map<std::string, h160> const& _libraries); /// Tries to translate all source files into a language suitable for formal analysis. + /// @param _errors list to store errors - defaults to the internal error list. /// @returns false on error. - bool prepareFormalAnalysis(); + bool prepareFormalAnalysis(ErrorList* _errors = nullptr); std::string const& formalTranslation() const { return m_formalTranslation; } /// @returns the assembled object for a contract. @@ -141,6 +142,12 @@ public: 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 hash of the runtime bytecode for the contract, i.e. the code that is /// returned by the constructor or the zero-h256 if the contract still needs to be linked or /// does not have runtime code. @@ -152,6 +159,11 @@ public: /// 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 string representing the contract interface in JSON. /// Prerequisite: Successful call to parse or compile. std::string const& interface(std::string const& _contractName = "") const; @@ -195,9 +207,8 @@ private: { std::shared_ptr<Scanner> scanner; std::shared_ptr<SourceUnit> ast; - std::string interface; bool isLibrary = false; - void reset() { scanner.reset(); ast.reset(); interface.clear(); } + void reset() { scanner.reset(); ast.reset(); } }; struct Contract @@ -211,6 +222,8 @@ private: mutable std::unique_ptr<std::string const> solidityInterface; mutable std::unique_ptr<std::string const> userDocumentation; mutable std::unique_ptr<std::string const> devDocumentation; + 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 @@ -235,6 +248,8 @@ private: Contract const& contract(std::string const& _contractName = "") const; Source const& source(std::string const& _sourceName = "") const; + std::string computeSourceMapping(eth::AssemblyItems const& _items) const; + struct Remapping { std::string context; |