diff options
author | chriseth <chris@ethereum.org> | 2017-05-19 23:55:33 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-19 23:55:33 +0800 |
commit | 56424bb2026ab484470b5e0e6f1ddb2ab3c7ac85 (patch) | |
tree | 4ba6d697307c932957f7fe95d3d6b80797030e00 | |
parent | 20125c18ba6bd8876b24d988dd299e309fda8c83 (diff) | |
parent | bbef2cd4a8c4dd3ad0d1e16d6070a88a5f83fcc6 (diff) | |
download | dexon-solidity-56424bb2026ab484470b5e0e6f1ddb2ab3c7ac85.tar.gz dexon-solidity-56424bb2026ab484470b5e0e6f1ddb2ab3c7ac85.tar.zst dexon-solidity-56424bb2026ab484470b5e0e6f1ddb2ab3c7ac85.zip |
Merge pull request #2262 from ethereum/interface-cleanup
Cleanup the external interfaces (ABI and Natspec)
-rw-r--r-- | libsolidity/interface/ABI.cpp | 116 | ||||
-rw-r--r-- | libsolidity/interface/ABI.h | 56 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 42 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.h | 16 | ||||
-rw-r--r-- | libsolidity/interface/InterfaceHandler.cpp | 197 | ||||
-rw-r--r-- | libsolidity/interface/Natspec.cpp | 130 | ||||
-rw-r--r-- | libsolidity/interface/Natspec.h (renamed from libsolidity/interface/InterfaceHandler.h) | 9 | ||||
-rw-r--r-- | libsolidity/interface/StandardCompiler.cpp | 6 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 1 | ||||
-rw-r--r-- | solc/CommandLineInterface.cpp | 39 | ||||
-rw-r--r-- | solc/CommandLineInterface.h | 3 | ||||
-rw-r--r-- | solc/jsonCompiler.cpp | 2 | ||||
-rw-r--r-- | test/libsolidity/SolidityABIJSON.cpp | 2 | ||||
-rw-r--r-- | test/libsolidity/SolidityNatspecJSON.cpp | 4 |
14 files changed, 369 insertions, 254 deletions
diff --git a/libsolidity/interface/ABI.cpp b/libsolidity/interface/ABI.cpp new file mode 100644 index 00000000..12f958fc --- /dev/null +++ b/libsolidity/interface/ABI.cpp @@ -0,0 +1,116 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * Utilities to handle the Contract ABI (https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) + */ + +#include <libsolidity/interface/ABI.h> +#include <boost/range/irange.hpp> +#include <libsolidity/ast/AST.h> + +using namespace std; +using namespace dev; +using namespace dev::solidity; + +Json::Value ABI::generate(ContractDefinition const& _contractDef) +{ + Json::Value abi(Json::arrayValue); + + for (auto it: _contractDef.interfaceFunctions()) + { + auto externalFunctionType = it.second->interfaceFunctionType(); + Json::Value method; + method["type"] = "function"; + method["name"] = it.second->declaration().name(); + method["constant"] = it.second->isConstant(); + method["payable"] = it.second->isPayable(); + method["inputs"] = formatTypeList( + externalFunctionType->parameterNames(), + externalFunctionType->parameterTypes(), + _contractDef.isLibrary() + ); + method["outputs"] = formatTypeList( + externalFunctionType->returnParameterNames(), + externalFunctionType->returnParameterTypes(), + _contractDef.isLibrary() + ); + abi.append(method); + } + if (_contractDef.constructor()) + { + Json::Value method; + method["type"] = "constructor"; + auto externalFunction = FunctionType(*_contractDef.constructor(), false).interfaceFunctionType(); + solAssert(!!externalFunction, ""); + method["payable"] = externalFunction->isPayable(); + method["inputs"] = formatTypeList( + externalFunction->parameterNames(), + externalFunction->parameterTypes(), + _contractDef.isLibrary() + ); + abi.append(method); + } + if (_contractDef.fallbackFunction()) + { + auto externalFunctionType = FunctionType(*_contractDef.fallbackFunction(), false).interfaceFunctionType(); + solAssert(!!externalFunctionType, ""); + Json::Value method; + method["type"] = "fallback"; + method["payable"] = externalFunctionType->isPayable(); + abi.append(method); + } + for (auto const& it: _contractDef.interfaceEvents()) + { + Json::Value event; + event["type"] = "event"; + event["name"] = it->name(); + event["anonymous"] = it->isAnonymous(); + Json::Value params(Json::arrayValue); + for (auto const& p: it->parameters()) + { + solAssert(!!p->annotation().type->interfaceType(false), ""); + Json::Value input; + input["name"] = p->name(); + input["type"] = p->annotation().type->interfaceType(false)->canonicalName(false); + input["indexed"] = p->isIndexed(); + params.append(input); + } + event["inputs"] = params; + abi.append(event); + } + + return abi; +} + +Json::Value ABI::formatTypeList( + vector<string> const& _names, + vector<TypePointer> const& _types, + bool _forLibrary +) +{ + Json::Value params(Json::arrayValue); + solAssert(_names.size() == _types.size(), "Names and types vector size does not match"); + for (unsigned i = 0; i < _names.size(); ++i) + { + solAssert(_types[i], ""); + Json::Value param; + param["name"] = _names[i]; + param["type"] = _types[i]->canonicalName(_forLibrary); + params.append(param); + } + return params; +} diff --git a/libsolidity/interface/ABI.h b/libsolidity/interface/ABI.h new file mode 100644 index 00000000..95b162a9 --- /dev/null +++ b/libsolidity/interface/ABI.h @@ -0,0 +1,56 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * Utilities to handle the Contract ABI (https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) + */ + +#pragma once + +#include <string> +#include <memory> +#include <json/json.h> + +namespace dev +{ +namespace solidity +{ + +// Forward declarations +class ContractDefinition; +class Type; +using TypePointer = std::shared_ptr<Type const>; + +class ABI +{ +public: + /// Get the ABI Interface of the contract + /// @param _contractDef The contract definition + /// @return A JSONrepresentation of the contract's ABI Interface + static Json::Value generate(ContractDefinition const& _contractDef); +private: + /// @returns a json value suitable for a list of types in function input or output + /// parameters or other places. If @a _forLibrary is true, complex types are referenced + /// by name, otherwise they are anonymously expanded. + static Json::Value formatTypeList( + std::vector<std::string> const& _names, + std::vector<TypePointer> const& _types, + bool _forLibrary + ); +}; + +} +} diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 5c836358..72712298 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -37,7 +37,8 @@ #include <libsolidity/analysis/PostTypeChecker.h> #include <libsolidity/analysis/SyntaxChecker.h> #include <libsolidity/codegen/Compiler.h> -#include <libsolidity/interface/InterfaceHandler.h> +#include <libsolidity/interface/ABI.h> +#include <libsolidity/interface/Natspec.h> #include <libsolidity/interface/GasEstimator.h> #include <libsolidity/formal/Why3Translator.h> @@ -219,8 +220,8 @@ bool CompilerStack::analyze() TypeChecker typeChecker(m_errors); if (typeChecker.checkTypeRequirements(*contract)) { - contract->setDevDocumentation(InterfaceHandler::devDocumentation(*contract)); - contract->setUserDocumentation(InterfaceHandler::userDocumentation(*contract)); + contract->setDevDocumentation(Natspec::devDocumentation(*contract)); + contract->setUserDocumentation(Natspec::userDocumentation(*contract)); } else noErrors = false; @@ -444,17 +445,31 @@ map<string, unsigned> CompilerStack::sourceIndices() const return indices; } -Json::Value const& CompilerStack::interface(string const& _contractName) const +Json::Value const& CompilerStack::contractABI(string const& _contractName) const { - return metadata(_contractName, DocumentationType::ABIInterface); + return contractABI(contract(_contractName)); } -Json::Value const& CompilerStack::metadata(string const& _contractName, DocumentationType _type) const +Json::Value const& CompilerStack::contractABI(Contract const& _contract) const { - return metadata(contract(_contractName), _type); + if (m_stackState < AnalysisSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + + solAssert(_contract.contract, ""); + + // caches the result + if (!_contract.abi) + _contract.abi.reset(new Json::Value(ABI::generate(*_contract.contract))); + + return *_contract.abi; } -Json::Value const& CompilerStack::metadata(Contract const& _contract, DocumentationType _type) const +Json::Value const& CompilerStack::natspec(string const& _contractName, DocumentationType _type) const +{ + return natspec(contract(_contractName), _type); +} + +Json::Value const& CompilerStack::natspec(Contract const& _contract, DocumentationType _type) const { if (m_stackState < AnalysisSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); @@ -471,16 +486,13 @@ Json::Value const& CompilerStack::metadata(Contract const& _contract, Documentat case DocumentationType::NatspecDev: doc = &_contract.devDocumentation; break; - case DocumentationType::ABIInterface: - doc = &_contract.interface; - break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type.")); } // caches the result if (!*doc) - doc->reset(new Json::Value(InterfaceHandler::documentation(*_contract.contract, _type))); + doc->reset(new Json::Value(Natspec::documentation(*_contract.contract, _type))); return *(*doc); } @@ -830,9 +842,9 @@ string CompilerStack::createOnChainMetadata(Contract const& _contract) const for (auto const& library: m_libraries) meta["settings"]["libraries"][library.first] = "0x" + toHex(library.second.asBytes()); - meta["output"]["abi"] = metadata(_contract, DocumentationType::ABIInterface); - meta["output"]["userdoc"] = metadata(_contract, DocumentationType::NatspecUser); - meta["output"]["devdoc"] = metadata(_contract, DocumentationType::NatspecDev); + meta["output"]["abi"] = contractABI(_contract); + meta["output"]["userdoc"] = natspec(_contract, DocumentationType::NatspecUser); + meta["output"]["devdoc"] = natspec(_contract, DocumentationType::NatspecDev); return jsonCompactPrint(meta); } diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index c1d344ca..84d15d70 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -59,15 +59,14 @@ class FunctionDefinition; class SourceUnit; class Compiler; class GlobalContext; -class InterfaceHandler; +class Natspec; class Error; class DeclarationContainer; enum class DocumentationType: uint8_t { NatspecUser = 1, - NatspecDev, - ABIInterface + NatspecDev }; /** @@ -173,14 +172,14 @@ public: /// @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 interface. + /// @returns a JSON representing the contract ABI. /// Prerequisite: Successful call to parse or compile. - Json::Value const& interface(std::string const& _contractName = "") const; + 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. /// Can be one of 4 types defined at @c DocumentationType - Json::Value const& metadata(std::string const& _contractName, DocumentationType _type) const; + Json::Value const& natspec(std::string const& _contractName, DocumentationType _type) const; std::string const& onChainMetadata(std::string const& _contractName) const; void useMetadataLiteralSources(bool _metadataLiteralSources) { m_metadataLiteralSources = _metadataLiteralSources; } @@ -230,7 +229,7 @@ private: eth::LinkerObject runtimeObject; eth::LinkerObject cloneObject; std::string onChainMetadata; ///< The metadata json that will be hashed into the chain. - mutable std::unique_ptr<Json::Value const> interface; + mutable std::unique_ptr<Json::Value const> abi; mutable std::unique_ptr<Json::Value const> userDocumentation; mutable std::unique_ptr<Json::Value const> devDocumentation; mutable std::unique_ptr<std::string const> sourceMapping; @@ -267,7 +266,8 @@ private: std::string createOnChainMetadata(Contract const& _contract) const; std::string computeSourceMapping(eth::AssemblyItems const& _items) const; - Json::Value const& metadata(Contract const&, DocumentationType _type) const; + Json::Value const& contractABI(Contract const&) const; + Json::Value const& natspec(Contract const&, DocumentationType _type) const; struct Remapping { diff --git a/libsolidity/interface/InterfaceHandler.cpp b/libsolidity/interface/InterfaceHandler.cpp deleted file mode 100644 index 6c1bb0c4..00000000 --- a/libsolidity/interface/InterfaceHandler.cpp +++ /dev/null @@ -1,197 +0,0 @@ - -#include <libsolidity/interface/InterfaceHandler.h> -#include <boost/range/irange.hpp> -#include <libsolidity/ast/AST.h> -#include <libsolidity/interface/CompilerStack.h> - -using namespace std; -using namespace dev; -using namespace dev::solidity; - -Json::Value InterfaceHandler::documentation( - ContractDefinition const& _contractDef, - DocumentationType _type -) -{ - switch(_type) - { - case DocumentationType::NatspecUser: - return userDocumentation(_contractDef); - case DocumentationType::NatspecDev: - return devDocumentation(_contractDef); - case DocumentationType::ABIInterface: - return abiInterface(_contractDef); - } - - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type")); -} - -Json::Value InterfaceHandler::abiInterface(ContractDefinition const& _contractDef) -{ - Json::Value abi(Json::arrayValue); - - for (auto it: _contractDef.interfaceFunctions()) - { - auto externalFunctionType = it.second->interfaceFunctionType(); - Json::Value method; - method["type"] = "function"; - method["name"] = it.second->declaration().name(); - method["constant"] = it.second->isConstant(); - method["payable"] = it.second->isPayable(); - method["inputs"] = formatTypeList( - externalFunctionType->parameterNames(), - externalFunctionType->parameterTypes(), - _contractDef.isLibrary() - ); - method["outputs"] = formatTypeList( - externalFunctionType->returnParameterNames(), - externalFunctionType->returnParameterTypes(), - _contractDef.isLibrary() - ); - abi.append(method); - } - if (_contractDef.constructor()) - { - Json::Value method; - method["type"] = "constructor"; - auto externalFunction = FunctionType(*_contractDef.constructor(), false).interfaceFunctionType(); - solAssert(!!externalFunction, ""); - method["payable"] = externalFunction->isPayable(); - method["inputs"] = formatTypeList( - externalFunction->parameterNames(), - externalFunction->parameterTypes(), - _contractDef.isLibrary() - ); - abi.append(method); - } - if (_contractDef.fallbackFunction()) - { - auto externalFunctionType = FunctionType(*_contractDef.fallbackFunction(), false).interfaceFunctionType(); - solAssert(!!externalFunctionType, ""); - Json::Value method; - method["type"] = "fallback"; - method["payable"] = externalFunctionType->isPayable(); - abi.append(method); - } - for (auto const& it: _contractDef.interfaceEvents()) - { - Json::Value event; - event["type"] = "event"; - event["name"] = it->name(); - event["anonymous"] = it->isAnonymous(); - Json::Value params(Json::arrayValue); - for (auto const& p: it->parameters()) - { - solAssert(!!p->annotation().type->interfaceType(false), ""); - Json::Value input; - input["name"] = p->name(); - input["type"] = p->annotation().type->interfaceType(false)->canonicalName(false); - input["indexed"] = p->isIndexed(); - params.append(input); - } - event["inputs"] = params; - abi.append(event); - } - - return abi; -} - -Json::Value InterfaceHandler::userDocumentation(ContractDefinition const& _contractDef) -{ - Json::Value doc; - Json::Value methods(Json::objectValue); - - for (auto const& it: _contractDef.interfaceFunctions()) - if (it.second->hasDeclaration()) - if (auto const* f = dynamic_cast<FunctionDefinition const*>(&it.second->declaration())) - { - string value = extractDoc(f->annotation().docTags, "notice"); - if (!value.empty()) - { - Json::Value user; - // since @notice is the only user tag if missing function should not appear - user["notice"] = Json::Value(value); - methods[it.second->externalSignature()] = user; - } - } - doc["methods"] = methods; - - return doc; -} - -Json::Value InterfaceHandler::devDocumentation(ContractDefinition const& _contractDef) -{ - Json::Value doc; - Json::Value methods(Json::objectValue); - - auto author = extractDoc(_contractDef.annotation().docTags, "author"); - if (!author.empty()) - doc["author"] = author; - auto title = extractDoc(_contractDef.annotation().docTags, "title"); - if (!title.empty()) - doc["title"] = title; - - for (auto const& it: _contractDef.interfaceFunctions()) - { - if (!it.second->hasDeclaration()) - continue; - Json::Value method; - if (auto fun = dynamic_cast<FunctionDefinition const*>(&it.second->declaration())) - { - auto dev = extractDoc(fun->annotation().docTags, "dev"); - if (!dev.empty()) - method["details"] = Json::Value(dev); - - auto author = extractDoc(fun->annotation().docTags, "author"); - if (!author.empty()) - method["author"] = author; - - auto ret = extractDoc(fun->annotation().docTags, "return"); - if (!ret.empty()) - method["return"] = ret; - - Json::Value params(Json::objectValue); - auto paramRange = fun->annotation().docTags.equal_range("param"); - for (auto i = paramRange.first; i != paramRange.second; ++i) - params[i->second.paramName] = Json::Value(i->second.content); - - if (!params.empty()) - method["params"] = params; - - if (!method.empty()) - // add the function, only if we have any documentation to add - methods[it.second->externalSignature()] = method; - } - } - doc["methods"] = methods; - - return doc; -} - -Json::Value InterfaceHandler::formatTypeList( - vector<string> const& _names, - vector<TypePointer> const& _types, - bool _forLibrary -) -{ - Json::Value params(Json::arrayValue); - solAssert(_names.size() == _types.size(), "Names and types vector size does not match"); - for (unsigned i = 0; i < _names.size(); ++i) - { - solAssert(_types[i], ""); - Json::Value param; - param["name"] = _names[i]; - param["type"] = _types[i]->canonicalName(_forLibrary); - params.append(param); - } - return params; -} - -string InterfaceHandler::extractDoc(multimap<string, DocTag> const& _tags, string const& _name) -{ - string value; - auto range = _tags.equal_range(_name); - for (auto i = range.first; i != range.second; i++) - value += i->second.content; - return value; -} diff --git a/libsolidity/interface/Natspec.cpp b/libsolidity/interface/Natspec.cpp new file mode 100644 index 00000000..70486e23 --- /dev/null +++ b/libsolidity/interface/Natspec.cpp @@ -0,0 +1,130 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Lefteris <lefteris@ethdev.com> + * @date 2014 + * Takes the parsed AST and produces the Natspec documentation: + * https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format + * + * Can generally deal with JSON files + */ + +#include <libsolidity/interface/Natspec.h> +#include <boost/range/irange.hpp> +#include <libsolidity/ast/AST.h> +#include <libsolidity/interface/CompilerStack.h> + +using namespace std; +using namespace dev; +using namespace dev::solidity; + +Json::Value Natspec::documentation( + ContractDefinition const& _contractDef, + DocumentationType _type +) +{ + switch(_type) + { + case DocumentationType::NatspecUser: + return userDocumentation(_contractDef); + case DocumentationType::NatspecDev: + return devDocumentation(_contractDef); + } + + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type")); +} + +Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef) +{ + Json::Value doc; + Json::Value methods(Json::objectValue); + + for (auto const& it: _contractDef.interfaceFunctions()) + if (it.second->hasDeclaration()) + if (auto const* f = dynamic_cast<FunctionDefinition const*>(&it.second->declaration())) + { + string value = extractDoc(f->annotation().docTags, "notice"); + if (!value.empty()) + { + Json::Value user; + // since @notice is the only user tag if missing function should not appear + user["notice"] = Json::Value(value); + methods[it.second->externalSignature()] = user; + } + } + doc["methods"] = methods; + + return doc; +} + +Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef) +{ + Json::Value doc; + Json::Value methods(Json::objectValue); + + auto author = extractDoc(_contractDef.annotation().docTags, "author"); + if (!author.empty()) + doc["author"] = author; + auto title = extractDoc(_contractDef.annotation().docTags, "title"); + if (!title.empty()) + doc["title"] = title; + + for (auto const& it: _contractDef.interfaceFunctions()) + { + if (!it.second->hasDeclaration()) + continue; + Json::Value method; + if (auto fun = dynamic_cast<FunctionDefinition const*>(&it.second->declaration())) + { + auto dev = extractDoc(fun->annotation().docTags, "dev"); + if (!dev.empty()) + method["details"] = Json::Value(dev); + + auto author = extractDoc(fun->annotation().docTags, "author"); + if (!author.empty()) + method["author"] = author; + + auto ret = extractDoc(fun->annotation().docTags, "return"); + if (!ret.empty()) + method["return"] = ret; + + Json::Value params(Json::objectValue); + auto paramRange = fun->annotation().docTags.equal_range("param"); + for (auto i = paramRange.first; i != paramRange.second; ++i) + params[i->second.paramName] = Json::Value(i->second.content); + + if (!params.empty()) + method["params"] = params; + + if (!method.empty()) + // add the function, only if we have any documentation to add + methods[it.second->externalSignature()] = method; + } + } + doc["methods"] = methods; + + return doc; +} + +string Natspec::extractDoc(multimap<string, DocTag> const& _tags, string const& _name) +{ + string value; + auto range = _tags.equal_range(_name); + for (auto i = range.first; i != range.second; i++) + value += i->second.content; + return value; +} diff --git a/libsolidity/interface/InterfaceHandler.h b/libsolidity/interface/Natspec.h index 56927d44..bec9acd2 100644 --- a/libsolidity/interface/InterfaceHandler.h +++ b/libsolidity/interface/Natspec.h @@ -17,8 +17,7 @@ /** * @author Lefteris <lefteris@ethdev.com> * @date 2014 - * Takes the parsed AST and produces the Natspec - * documentation and the ABI interface + * Takes the parsed AST and produces the Natspec documentation: * https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format * * Can generally deal with JSON files @@ -59,7 +58,7 @@ enum class CommentOwner Function }; -class InterfaceHandler +class Natspec { public: /// Get the given type of documentation @@ -71,10 +70,6 @@ public: ContractDefinition const& _contractDef, DocumentationType _type ); - /// Get the ABI Interface of the contract - /// @param _contractDef The contract definition - /// @return A JSONrepresentation of the contract's ABI Interface - static Json::Value abiInterface(ContractDefinition const& _contractDef); /// Get the User documentation of the contract /// @param _contractDef The contract definition /// @return A JSON representation of the contract's user documentation diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 223cc15d..503be57b 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -391,10 +391,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) // ABI, documentation and metadata Json::Value contractData(Json::objectValue); - contractData["abi"] = m_compilerStack.metadata(contractName, DocumentationType::ABIInterface); + contractData["abi"] = m_compilerStack.contractABI(contractName); contractData["metadata"] = m_compilerStack.onChainMetadata(contractName); - contractData["userdoc"] = m_compilerStack.metadata(contractName, DocumentationType::NatspecUser); - contractData["devdoc"] = m_compilerStack.metadata(contractName, DocumentationType::NatspecDev); + contractData["userdoc"] = m_compilerStack.natspec(contractName, DocumentationType::NatspecUser); + contractData["devdoc"] = m_compilerStack.natspec(contractName, DocumentationType::NatspecDev); // EVM Json::Value evmData(Json::objectValue); diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index b5130c8a..72150a3e 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -27,7 +27,6 @@ #include <libsolidity/parsing/Scanner.h> #include <libsolidity/inlineasm/AsmParser.h> #include <libsolidity/interface/Exceptions.h> -#include <libsolidity/interface/InterfaceHandler.h> using namespace std; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 0f2e83dc..d5a60b50 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -266,24 +266,31 @@ void CommandLineInterface::handleOnChainMetadata(string const& _contract) return; string data = m_compiler->onChainMetadata(_contract); - if (m_args.count("output-dir")) + if (m_args.count(g_argOutputDir)) createFile(m_compiler->filesystemFriendlyName(_contract) + "_meta.json", data); else cout << "Metadata: " << endl << data << endl; } -void CommandLineInterface::handleMeta(DocumentationType _type, string const& _contract) +void CommandLineInterface::handleABI(string const& _contract) +{ + if (!m_args.count(g_argAbi)) + return; + + string data = dev::jsonCompactPrint(m_compiler->contractABI(_contract)); + if (m_args.count(g_argOutputDir)) + createFile(m_compiler->filesystemFriendlyName(_contract) + ".abi", data); + else + cout << "Contract JSON ABI " << endl << data << endl; +} + +void CommandLineInterface::handleNatspec(DocumentationType _type, string const& _contract) { std::string argName; std::string suffix; std::string title; switch(_type) { - case DocumentationType::ABIInterface: - argName = g_argAbi; - suffix = ".abi"; - title = "Contract JSON ABI"; - break; case DocumentationType::NatspecUser: argName = g_argNatspecUser; suffix = ".docuser"; @@ -301,11 +308,7 @@ void CommandLineInterface::handleMeta(DocumentationType _type, string const& _co if (m_args.count(argName)) { - std::string output; - if (_type == DocumentationType::ABIInterface) - output = dev::jsonCompactPrint(m_compiler->metadata(_contract, _type)); - else - output = dev::jsonPrettyPrint(m_compiler->metadata(_contract, _type)); + std::string output = dev::jsonPrettyPrint(m_compiler->natspec(_contract, _type)); if (m_args.count(g_argOutputDir)) createFile(m_compiler->filesystemFriendlyName(_contract) + suffix, output); @@ -787,7 +790,7 @@ void CommandLineInterface::handleCombinedJSON() { Json::Value contractData(Json::objectValue); if (requests.count(g_strAbi)) - contractData[g_strAbi] = dev::jsonCompactPrint(m_compiler->interface(contractName)); + contractData[g_strAbi] = dev::jsonCompactPrint(m_compiler->contractABI(contractName)); if (requests.count("metadata")) contractData["metadata"] = m_compiler->onChainMetadata(contractName); if (requests.count(g_strBinary)) @@ -814,9 +817,9 @@ void CommandLineInterface::handleCombinedJSON() contractData[g_strSrcMapRuntime] = map ? *map : ""; } if (requests.count(g_strNatspecDev)) - contractData[g_strNatspecDev] = dev::jsonCompactPrint(m_compiler->metadata(contractName, DocumentationType::NatspecDev)); + contractData[g_strNatspecDev] = dev::jsonCompactPrint(m_compiler->natspec(contractName, DocumentationType::NatspecDev)); if (requests.count(g_strNatspecUser)) - contractData[g_strNatspecUser] = dev::jsonCompactPrint(m_compiler->metadata(contractName, DocumentationType::NatspecUser)); + contractData[g_strNatspecUser] = dev::jsonCompactPrint(m_compiler->natspec(contractName, DocumentationType::NatspecUser)); output[g_strContracts][contractName] = contractData; } @@ -1069,9 +1072,9 @@ void CommandLineInterface::outputCompilationResults() handleBytecode(contract); handleSignatureHashes(contract); handleOnChainMetadata(contract); - handleMeta(DocumentationType::ABIInterface, contract); - handleMeta(DocumentationType::NatspecDev, contract); - handleMeta(DocumentationType::NatspecUser, contract); + handleABI(contract); + handleNatspec(DocumentationType::NatspecDev, contract); + handleNatspec(DocumentationType::NatspecUser, contract); } // end of contracts iteration handleFormal(); diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index f52a03c7..ebf52625 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -67,7 +67,8 @@ private: void handleBytecode(std::string const& _contract); void handleSignatureHashes(std::string const& _contract); void handleOnChainMetadata(std::string const& _contract); - void handleMeta(DocumentationType _type, std::string const& _contract); + void handleABI(std::string const& _contract); + void handleNatspec(DocumentationType _type, std::string const& _contract); void handleGasEstimation(std::string const& _contract); void handleFormal(); diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp index 42c25de0..92a102b6 100644 --- a/solc/jsonCompiler.cpp +++ b/solc/jsonCompiler.cpp @@ -193,7 +193,7 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback for (string const& contractName: compiler.contractNames()) { Json::Value contractData(Json::objectValue); - contractData["interface"] = dev::jsonCompactPrint(compiler.interface(contractName)); + contractData["interface"] = dev::jsonCompactPrint(compiler.contractABI(contractName)); contractData["bytecode"] = compiler.object(contractName).toHex(); contractData["runtimeBytecode"] = compiler.runtimeObject(contractName).toHex(); contractData["opcodes"] = solidity::disassemble(compiler.object(contractName).bytecode); diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp index bdcc5b10..1ebccc13 100644 --- a/test/libsolidity/SolidityABIJSON.cpp +++ b/test/libsolidity/SolidityABIJSON.cpp @@ -44,7 +44,7 @@ public: { ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parseAndAnalyze("pragma solidity >=0.0;\n" + _code), "Parsing contract failed"); - Json::Value generatedInterface = m_compilerStack.metadata("", DocumentationType::ABIInterface); + Json::Value generatedInterface = m_compilerStack.contractABI(""); Json::Value expectedInterface; m_reader.parse(_expectedInterfaceString, expectedInterface); BOOST_CHECK_MESSAGE( diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index 78c1a0ee..2a7376b9 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -49,9 +49,9 @@ public: Json::Value generatedDocumentation; if (_userDocumentation) - generatedDocumentation = m_compilerStack.metadata("", DocumentationType::NatspecUser); + generatedDocumentation = m_compilerStack.natspec("", DocumentationType::NatspecUser); else - generatedDocumentation = m_compilerStack.metadata("", DocumentationType::NatspecDev); + generatedDocumentation = m_compilerStack.natspec("", DocumentationType::NatspecDev); Json::Value expectedDocumentation; m_reader.parse(_expectedDocumentationString, expectedDocumentation); BOOST_CHECK_MESSAGE( |