From 43bf0f01c7d1c1406c4cbe4bfb3899a4e09204b7 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 26 Nov 2014 19:38:09 +0100 Subject: [PATCH 01/33] require ioservice to use multiple threads. thread-safe connecting to nodes. --- libp2p/Host.cpp | 20 ++++++++++++++++---- libp2p/Host.h | 3 +++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 6e151d34d..dc655f7a4 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -199,7 +200,7 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool m_clientVersion(_clientVersion), m_netPrefs(_n), m_ifAddresses(getInterfaceAddresses()), - m_ioService(new ba::io_service), + m_ioService(new ba::io_service(2)), m_acceptor(new bi::tcp::acceptor(*m_ioService)), m_socket(new bi::tcp::socket(*m_ioService)), m_key(KeyPair::create()) @@ -536,7 +537,16 @@ void Host::connect(std::shared_ptr const& _n) // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here. if (!m_ioService) return; - + + // prevent concurrently connecting to a node; tood: better abstraction + Node *nptr = _n.get(); + { + lock_guard l(x_pendingNodeConnsMutex); + if (m_pendingNodeConns.count(nptr)) + return; + m_pendingNodeConns.insert(nptr); + } + clog(NetConnect) << "Attempting connection to node" << _n->id.abridged() << "@" << _n->address << "from" << id().abridged(); _n->lastAttempted = std::chrono::system_clock::now(); _n->failedAttempts++; @@ -559,6 +569,8 @@ void Host::connect(std::shared_ptr const& _n) p->start(); } delete s; + lock_guard l(x_pendingNodeConnsMutex); + m_pendingNodeConns.erase(nptr); }); } @@ -685,7 +697,7 @@ PeerInfos Host::peers(bool _updatePing) const ret.push_back(j->m_info); return ret; } - + void Host::run(boost::system::error_code const& error) { static unsigned s_lasttick = 0; @@ -701,7 +713,7 @@ void Host::run(boost::system::error_code const& error) // network running if (m_run) { - if (s_lasttick >= c_timerInterval * 50) + if (s_lasttick >= c_timerInterval * 10) { growPeers(); prunePeers(); diff --git a/libp2p/Host.h b/libp2p/Host.h index c82ecf84c..e19d81b94 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -241,6 +241,9 @@ private: std::unique_ptr m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms. static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected. + + std::set m_pendingNodeConns; /// Used only by connect(Node&) to limit concurrently connecting to same node. See connect(shared_ptrconst&). + std::mutex x_pendingNodeConnsMutex; bi::tcp::endpoint m_public; ///< Our public listening endpoint. KeyPair m_key; ///< Our unique ID. From cacc761ce9257769faf5bb864e9bf351be9d791f Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 27 Nov 2014 12:17:43 +0100 Subject: [PATCH 02/33] pr fixes --- libp2p/Host.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index dc655f7a4..73690ee94 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -228,7 +228,7 @@ void Host::stop() { { // prevent m_run from being set to false at same time as set to true by start() - lock_guard l(x_runtimer); + Guard l(x_runtimer); // once m_run is false the scheduler will shutdown network and stopWorking() m_run = false; } @@ -538,10 +538,10 @@ void Host::connect(std::shared_ptr const& _n) if (!m_ioService) return; - // prevent concurrently connecting to a node; tood: better abstraction + // prevent concurrently connecting to a node; todo: better abstraction Node *nptr = _n.get(); { - lock_guard l(x_pendingNodeConnsMutex); + Guard l(x_pendingNodeConnsMutex); if (m_pendingNodeConns.count(nptr)) return; m_pendingNodeConns.insert(nptr); @@ -569,7 +569,7 @@ void Host::connect(std::shared_ptr const& _n) p->start(); } delete s; - lock_guard l(x_pendingNodeConnsMutex); + Guard l(x_pendingNodeConnsMutex); m_pendingNodeConns.erase(nptr); }); } @@ -806,7 +806,7 @@ void Host::startedWorking() // prevent m_run from being set to true at same time as set to false by stop() // don't release mutex until m_timer is set so in case stop() is called at same // time, stop will wait on m_timer and graceful network shutdown. - lock_guard l(x_runtimer); + Guard l(x_runtimer); // reset io service and create deadline timer m_timer.reset(new boost::asio::deadline_timer(*m_ioService)); m_run = true; From 60ac4d3a2c3960edec7db7b9e1328c2597c406e9 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Dec 2014 17:03:04 +0100 Subject: [PATCH 03/33] Exporting Natspec documentation to a JSON interface - Adding a getDocumentation() function to solidity compiler stack so that we can obtain the natspec interface for a contract - Adding libjsoncpp as a dependency of libsolidity. This is done in a dirty way, using libjsonrpc-cpp s an intermediate dependency for the moment. Will fix soon. - Start of a test file for Natspec exporting to JSON --- libsolidity/AST.h | 2 +- libsolidity/CMakeLists.txt | 4 ++ libsolidity/CompilerStack.cpp | 26 ++++++++++++ libsolidity/CompilerStack.h | 4 ++ test/solidityNatspecJSON.cpp | 77 +++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 test/solidityNatspecJSON.cpp diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 81a12ad1a..4ed8489fc 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -199,7 +199,7 @@ public: Block& getBody() { return *m_body; } /// @return A shared pointer of an ASTString. /// Can contain a nullptr in which case indicates absence of documentation - ASTPointer const& getDocumentation() { return m_documentation; } + ASTPointer const& getDocumentation() const { return m_documentation; } void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); } std::vector const& getLocalVariables() const { return m_localVariables; } diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index ea2ef4b74..b5147ced3 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -16,6 +16,10 @@ endif() include_directories(..) target_link_libraries(${EXECUTABLE} evmcore devcore) +# TODO: Temporary until PR 532 https://github.com/ethereum/cpp-ethereum/pull/532 +# gets accepted. Then we can simply add jsoncpp as a dependency and not the +# whole of JSONRPC as we are doing right here +target_link_libraries(${EXECUTABLE} ${JSONRPC_LS}) install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 6535e00d4..45d3e0b8a 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -28,6 +28,8 @@ #include #include +#include + using namespace std; namespace dev @@ -125,6 +127,30 @@ string const& CompilerStack::getInterface() return m_interface; } +string const& CompilerStack::getDocumentation() +{ + + Json::StyledWriter writer; + if (!m_parseSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + if (m_documentation.empty()) + { + Json::Value doc; + Json::Value methods; + + vector exportedFunctions = m_contractASTNode->getInterfaceFunctions(); + for (FunctionDefinition const* f: exportedFunctions) + { + Json::Value user; + user["user"] = Json::Value(*f->getDocumentation()); + methods[f->getName()] = user; + } + doc["methods"] = methods; + m_documentation = writer.write(doc); + } + return m_documentation; +} + bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize) { CompilerStack stack; diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 6cae8660f..74784c5ef 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -62,6 +62,9 @@ public: /// Returns a string representing the contract interface in JSON. /// Prerequisite: Successful call to parse or compile. std::string const& getInterface(); + /// Returns a string representing the contract documentation in JSON. + /// Prerequisite: Successful call to parse or compile. + std::string const& getDocumentation(); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } @@ -77,6 +80,7 @@ private: std::shared_ptr m_contractASTNode; bool m_parseSuccessful; std::string m_interface; + std::string m_documentation; std::shared_ptr m_compiler; bytes m_bytecode; }; diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp new file mode 100644 index 000000000..5918eec99 --- /dev/null +++ b/test/solidityNatspecJSON.cpp @@ -0,0 +1,77 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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. + + cpp-ethereum 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 cpp-ethereum. If not, see . + */ +/** + * @author Lefteris Karapetsas + * @date 2014 + * Unit tests for the solidity compiler JSON Interface output. + */ + +#include +#include +#include + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +class DocumentationChecker +{ +public: + void checkNatspec(std::string const& _code, std::string const& _expectedDocumentationString) + { + m_compilerStack.parse(_code); + auto generatedDocumentationString = m_compilerStack.getDocumentation(); + Json::Value generatedDocumentation; + m_reader.parse(generatedDocumentationString, generatedDocumentation); + Json::Value expectedDocumentation; + m_reader.parse(_expectedDocumentationString, expectedDocumentation); + BOOST_CHECK_MESSAGE(expectedDocumentation == generatedDocumentation, + "Expected " << _expectedDocumentationString << + "\n but got:\n" << generatedDocumentationString); + } + +private: + CompilerStack m_compilerStack; + Json::Reader m_reader; +}; + +BOOST_FIXTURE_TEST_SUITE(SolidityNatspecJSON, DocumentationChecker) + +BOOST_AUTO_TEST_CASE(basic_test) +{ + char const* sourceCode = "contract test {\n" + " /// Multiplies `a` by 7\n" + " function mul(uint a) returns(uint d) { return a * 7; }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul\":{ \"user\": \" Multiplies `a` by 7\"}" + "}}"; + + checkNatspec(sourceCode, natspec); +} + + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} From eed32824c3eb5ebd271d7cff585655b48ab5f697 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Dec 2014 18:01:42 +0100 Subject: [PATCH 04/33] Using jsoncpp for exporting ABI interface from solidity - Also changing the interface JSON test to have a shorter name plus to provide meaningful error message in case of failure --- libsolidity/CompilerStack.cpp | 48 ++++++++++++++---------------- test/solidityJSONInterfaceTest.cpp | 26 ++++++++-------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 45d3e0b8a..e25438f7c 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -85,54 +85,52 @@ void CompilerStack::streamAssembly(ostream& _outStream) string const& CompilerStack::getInterface() { + Json::StyledWriter writer; if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + if (m_interface.empty()) { - stringstream interface; - interface << '['; + Json::Value methods(Json::arrayValue); + vector exportedFunctions = m_contractASTNode->getInterfaceFunctions(); - unsigned functionsCount = exportedFunctions.size(); for (FunctionDefinition const* f: exportedFunctions) { - auto streamVariables = [&](vector> const& _vars) + Json::Value method; + Json::Value inputs(Json::arrayValue); + Json::Value outputs(Json::arrayValue); + + auto streamVariables = [&](vector> const& _vars, + Json::Value &json) { - unsigned varCount = _vars.size(); for (ASTPointer const& var: _vars) { - interface << "{" - << "\"name\":" << escaped(var->getName(), false) << "," - << "\"type\":" << escaped(var->getType()->toString(), false) - << "}"; - if (--varCount > 0) - interface << ","; + Json::Value input; + input["name"] = var->getName(); + input["type"] = var->getType()->toString(); + json.append(input); } }; - interface << '{' - << "\"name\":" << escaped(f->getName(), false) << "," - << "\"inputs\":["; - streamVariables(f->getParameters()); - interface << "]," - << "\"outputs\":["; - streamVariables(f->getReturnParameters()); - interface << "]" - << "}"; - if (--functionsCount > 0) - interface << ","; + method["name"] = f->getName(); + streamVariables(f->getParameters(), inputs); + method["inputs"] = inputs; + streamVariables(f->getReturnParameters(), outputs); + method["outputs"] = outputs; + + methods.append(method); } - interface << ']'; - m_interface = interface.str(); + m_interface = writer.write(methods); } return m_interface; } string const& CompilerStack::getDocumentation() { - Json::StyledWriter writer; if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + if (m_documentation.empty()) { Json::Value doc; diff --git a/test/solidityJSONInterfaceTest.cpp b/test/solidityJSONInterfaceTest.cpp index 1a443087f..b91880130 100644 --- a/test/solidityJSONInterfaceTest.cpp +++ b/test/solidityJSONInterfaceTest.cpp @@ -34,7 +34,7 @@ namespace test class InterfaceChecker { public: - bool checkInterface(std::string const& _code, std::string const& _expectedInterfaceString) + void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString) { m_compilerStack.parse(_code); std::string generatedInterfaceString = m_compilerStack.getInterface(); @@ -42,15 +42,17 @@ public: m_reader.parse(generatedInterfaceString, generatedInterface); Json::Value expectedInterface; m_reader.parse(_expectedInterfaceString, expectedInterface); - return expectedInterface == generatedInterface; + BOOST_CHECK_MESSAGE(expectedInterface == generatedInterface, + "Expected " << _expectedInterfaceString << + "\n but got:\n" << generatedInterfaceString); } - + private: CompilerStack m_compilerStack; Json::Reader m_reader; }; -BOOST_FIXTURE_TEST_SUITE(SolidityCompilerJSONInterfaceOutput, InterfaceChecker) +BOOST_FIXTURE_TEST_SUITE(solidityABIJSON, InterfaceChecker) BOOST_AUTO_TEST_CASE(basic_test) { @@ -76,7 +78,7 @@ BOOST_AUTO_TEST_CASE(basic_test) } ])"; - BOOST_CHECK(checkInterface(sourceCode, interface)); + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_CASE(empty_contract) @@ -86,7 +88,7 @@ BOOST_AUTO_TEST_CASE(empty_contract) char const* interface = "[]"; - BOOST_CHECK(checkInterface(sourceCode, interface)); + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_CASE(multiple_methods) @@ -95,7 +97,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods) " function f(uint a) returns(uint d) { return a * 7; }\n" " function g(uint b) returns(uint e) { return b * 8; }\n" "}\n"; - + char const* interface = R"([ { "name": "f", @@ -129,7 +131,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods) } ])"; - BOOST_CHECK(checkInterface(sourceCode, interface)); + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_CASE(multiple_params) @@ -160,7 +162,7 @@ BOOST_AUTO_TEST_CASE(multiple_params) } ])"; - BOOST_CHECK(checkInterface(sourceCode, interface)); + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_CASE(multiple_methods_order) @@ -170,7 +172,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order) " function f(uint a) returns(uint d) { return a * 7; }\n" " function c(uint b) returns(uint e) { return b * 8; }\n" "}\n"; - + char const* interface = R"([ { "name": "c", @@ -203,8 +205,8 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order) ] } ])"; - - BOOST_CHECK(checkInterface(sourceCode, interface)); + + checkInterface(sourceCode, interface); } BOOST_AUTO_TEST_SUITE_END() From 88b1bb25404bba285f903668ae0d3c44642d9a92 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 2 Dec 2014 10:41:18 +0100 Subject: [PATCH 05/33] More Natspec JSON export tests and better error reporting --- libsolidity/CompilerStack.cpp | 2 +- test/solidityJSONInterfaceTest.cpp | 17 ++++++- test/solidityNatspecJSON.cpp | 76 +++++++++++++++++++++++++++++- 3 files changed, 91 insertions(+), 4 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index e25438f7c..77a019b5f 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -134,7 +134,7 @@ string const& CompilerStack::getDocumentation() if (m_documentation.empty()) { Json::Value doc; - Json::Value methods; + Json::Value methods(Json::objectValue); vector exportedFunctions = m_contractASTNode->getInterfaceFunctions(); for (FunctionDefinition const* f: exportedFunctions) diff --git a/test/solidityJSONInterfaceTest.cpp b/test/solidityJSONInterfaceTest.cpp index b91880130..f46a3ad36 100644 --- a/test/solidityJSONInterfaceTest.cpp +++ b/test/solidityJSONInterfaceTest.cpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace dev { @@ -36,7 +37,19 @@ class InterfaceChecker public: void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString) { - m_compilerStack.parse(_code); + try + { + m_compilerStack.parse(_code); + } + catch (const std::exception& e) + { + std::string const* extra = boost::get_error_info(e); + std::string msg = std::string("Parsing contract failed with: ") + + e.what() + std::string("\n"); + if (extra) + msg += *extra; + BOOST_FAIL(msg); + } std::string generatedInterfaceString = m_compilerStack.getInterface(); Json::Value generatedInterface; m_reader.parse(generatedInterfaceString, generatedInterface); @@ -52,7 +65,7 @@ private: Json::Reader m_reader; }; -BOOST_FIXTURE_TEST_SUITE(solidityABIJSON, InterfaceChecker) +BOOST_FIXTURE_TEST_SUITE(SolidityABIJSON, InterfaceChecker) BOOST_AUTO_TEST_CASE(basic_test) { diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index 5918eec99..5a4649d2e 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace dev { @@ -36,7 +37,19 @@ class DocumentationChecker public: void checkNatspec(std::string const& _code, std::string const& _expectedDocumentationString) { - m_compilerStack.parse(_code); + try + { + m_compilerStack.parse(_code); + } + catch (const std::exception& e) + { + std::string const* extra = boost::get_error_info(e); + std::string msg = std::string("Parsing contract failed with: ") + + e.what() + std::string("\n"); + if (extra) + msg += *extra; + BOOST_FAIL(msg); + } auto generatedDocumentationString = m_compilerStack.getDocumentation(); Json::Value generatedDocumentation; m_reader.parse(generatedDocumentationString, generatedDocumentation); @@ -69,6 +82,67 @@ BOOST_AUTO_TEST_CASE(basic_test) checkNatspec(sourceCode, natspec); } +BOOST_AUTO_TEST_CASE(multiline_comment) +{ + char const* sourceCode = "contract test {\n" + " /// Multiplies `a` by 7\n" + " /// and then adds `b`\n" + " function mul_and_add(uint a, uint256 b) returns(uint256 d)\n" + " {\n" + " return (a * 7) + b;\n" + " }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul_and_add\":{ \"user\": \" Multiplies `a` by 7\n and then adds `b`\"}" + "}}"; + + checkNatspec(sourceCode, natspec); +} + +BOOST_AUTO_TEST_CASE(multiple_functions) +{ + char const* sourceCode = "contract test {\n" + " /// Multiplies `a` by 7\n" + " /// and then adds `b`\n" + " function mul_and_add(uint a, uint256 b) returns(uint256 d)\n" + " {\n" + " return (a * 7) + b;\n" + " }\n" + "\n" + " /// Divides `input` by `div`\n" + " function divide(uint input, uint div) returns(uint d)\n" + " {\n" + " return input / div;\n" + " }\n" + " /// Subtracts 3 from `input`\n" + " function sub(int input) returns(int d)\n" + " {\n" + " return input - 3;\n" + " }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul_and_add\":{ \"user\": \" Multiplies `a` by 7\n and then adds `b`\"}," + " \"divide\":{ \"user\": \" Divides `input` by `div`\"}," + " \"sub\":{ \"user\": \" Subtracts 3 from `input`\"}" + "}}"; + + checkNatspec(sourceCode, natspec); +} + +BOOST_AUTO_TEST_CASE(empty_contract) +{ + char const* sourceCode = "contract test {\n" + "}\n"; + + char const* natspec = "{\"methods\":{} }"; + + checkNatspec(sourceCode, natspec); +} + BOOST_AUTO_TEST_SUITE_END() From 93c488ce736f9f26edb556a4e112b188bdf4465e Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 2 Dec 2014 11:03:34 +0100 Subject: [PATCH 06/33] Handle absence of Natspec doc and add option to solc --- libsolidity/CompilerStack.cpp | 8 ++++++-- solc/main.cpp | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 77a019b5f..2b2991584 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -140,8 +140,12 @@ string const& CompilerStack::getDocumentation() for (FunctionDefinition const* f: exportedFunctions) { Json::Value user; - user["user"] = Json::Value(*f->getDocumentation()); - methods[f->getName()] = user; + auto strPtr = f->getDocumentation(); + if (strPtr) + { + user["user"] = Json::Value(*strPtr); + methods[f->getName()] = user; + } } doc["methods"] = methods; m_documentation = writer.write(doc); diff --git a/solc/main.cpp b/solc/main.cpp index a7216e594..6ca130a79 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -136,6 +136,7 @@ int main(int argc, char** argv) cout << eth::disassemble(compiler.getBytecode()) << endl; cout << "Binary: " << toHex(compiler.getBytecode()) << endl; cout << "Interface specification: " << compiler.getInterface() << endl; + cout << "Natspec documentation: " << compiler.getDocumentation() << endl; return 0; } From c89fc7df63fef3e430e17550e28083d71e3db647 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 2 Dec 2014 12:14:24 +0100 Subject: [PATCH 07/33] Removing unneeded local variable in CompilerStack::getDocumentation() --- libsolidity/CompilerStack.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 2b2991584..48a37b9cf 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -136,8 +136,7 @@ string const& CompilerStack::getDocumentation() Json::Value doc; Json::Value methods(Json::objectValue); - vector exportedFunctions = m_contractASTNode->getInterfaceFunctions(); - for (FunctionDefinition const* f: exportedFunctions) + for (FunctionDefinition const* f: m_contractASTNode->getInterfaceFunctions()) { Json::Value user; auto strPtr = f->getDocumentation(); From 9ff245ab52bd35cf7fa5ad845df9cdd7bd693f7c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 2 Dec 2014 17:18:09 +0100 Subject: [PATCH 08/33] Simplifying lambda function in CompilerStack::getInterface() --- libsolidity/CompilerStack.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 48a37b9cf..e44a10fbe 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -100,24 +100,22 @@ string const& CompilerStack::getInterface() Json::Value inputs(Json::arrayValue); Json::Value outputs(Json::arrayValue); - auto streamVariables = [&](vector> const& _vars, - Json::Value &json) + auto streamVariables = [](vector> const& _vars) { + Json::Value params(Json::arrayValue); for (ASTPointer const& var: _vars) { Json::Value input; input["name"] = var->getName(); input["type"] = var->getType()->toString(); - json.append(input); + params.append(input); } + return params; }; method["name"] = f->getName(); - streamVariables(f->getParameters(), inputs); - method["inputs"] = inputs; - streamVariables(f->getReturnParameters(), outputs); - method["outputs"] = outputs; - + method["inputs"] = streamVariables(f->getParameters()); + method["outputs"] = streamVariables(f->getReturnParameters()); methods.append(method); } m_interface = writer.write(methods); From e7be7244960c4f2898b6ba5c32f8a0f36b4bcb21 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 3 Dec 2014 08:36:52 +0100 Subject: [PATCH 09/33] test update due to CALLCODA <-> RETURN --- test/stSystemOperationsTestFiller.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/stSystemOperationsTestFiller.json b/test/stSystemOperationsTestFiller.json index e62753089..edd803641 100644 --- a/test/stSystemOperationsTestFiller.json +++ b/test/stSystemOperationsTestFiller.json @@ -12,7 +12,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 28) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -46,7 +46,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 1000 4 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 1000 4 28) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -80,7 +80,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 0xfffffffffff 28) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 0xfffffffffff 28) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -114,7 +114,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", "nonce" : 0, - "code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 0xfffffffffff) }", + "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 0xfffffffffff) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -195,7 +195,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x6001600155603760005360026000f2", + "code" : "0x6001600155603760005360026000f3", "nonce" : "0", "storage" : { } @@ -321,7 +321,7 @@ }, "945304eb96065b2a98b57a48a06ae28d285a71b5" : { "balance" : "23", - "code" : "0x6001600155603760005360026000f2", + "code" : "0x6001600155603760005360026000f3", "nonce" : "0", "storage" : { } From 8005012f6c4cb135964da8868e56a487e2ba944b Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 3 Dec 2014 13:03:41 +0100 Subject: [PATCH 10/33] fix naming --- libp2p/Host.cpp | 18 +++++++++--------- libp2p/Host.h | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 73690ee94..85225ab7f 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -228,7 +228,7 @@ void Host::stop() { { // prevent m_run from being set to false at same time as set to true by start() - Guard l(x_runtimer); + Guard l(x_runTimer); // once m_run is false the scheduler will shutdown network and stopWorking() m_run = false; } @@ -541,7 +541,7 @@ void Host::connect(std::shared_ptr const& _n) // prevent concurrently connecting to a node; todo: better abstraction Node *nptr = _n.get(); { - Guard l(x_pendingNodeConnsMutex); + Guard l(x_pendingNodeConns); if (m_pendingNodeConns.count(nptr)) return; m_pendingNodeConns.insert(nptr); @@ -569,7 +569,7 @@ void Host::connect(std::shared_ptr const& _n) p->start(); } delete s; - Guard l(x_pendingNodeConnsMutex); + Guard l(x_pendingNodeConns); m_pendingNodeConns.erase(nptr); }); } @@ -700,8 +700,8 @@ PeerInfos Host::peers(bool _updatePing) const void Host::run(boost::system::error_code const& error) { - static unsigned s_lasttick = 0; - s_lasttick += c_timerInterval; + static unsigned s_lastTick = 0; + s_lastTick += c_timerInterval; if (error || !m_ioService) { @@ -713,11 +713,11 @@ void Host::run(boost::system::error_code const& error) // network running if (m_run) { - if (s_lasttick >= c_timerInterval * 10) + if (s_lastTick >= c_timerInterval * 10) { growPeers(); prunePeers(); - s_lasttick = 0; + s_lastTick = 0; } if (m_hadNewNodes) @@ -783,7 +783,7 @@ void Host::run(boost::system::error_code const& error) m_socket->close(); // m_run is false, so we're stopping; kill timer - s_lasttick = 0; + s_lastTick = 0; // causes parent thread's stop() to continue which calls stopWorking() m_timer.reset(); @@ -806,7 +806,7 @@ void Host::startedWorking() // prevent m_run from being set to true at same time as set to false by stop() // don't release mutex until m_timer is set so in case stop() is called at same // time, stop will wait on m_timer and graceful network shutdown. - Guard l(x_runtimer); + Guard l(x_runTimer); // reset io service and create deadline timer m_timer.reset(new boost::asio::deadline_timer(*m_ioService)); m_run = true; diff --git a/libp2p/Host.h b/libp2p/Host.h index e19d81b94..9ee2c1b4a 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -224,7 +224,7 @@ private: Nodes potentialPeers(RangeMask const& _known); bool m_run = false; ///< Whether network is running. - std::mutex x_runtimer; ///< Start/stop mutex. + std::mutex x_runTimer; ///< Start/stop mutex. std::string m_clientVersion; ///< Our version string. @@ -243,7 +243,7 @@ private: static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected. std::set m_pendingNodeConns; /// Used only by connect(Node&) to limit concurrently connecting to same node. See connect(shared_ptrconst&). - std::mutex x_pendingNodeConnsMutex; + Mutex x_pendingNodeConns; bi::tcp::endpoint m_public; ///< Our public listening endpoint. KeyPair m_key; ///< Our unique ID. From 994e891078c0197d6c6b0347d4040f08f6564958 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Dec 2014 13:50:04 +0100 Subject: [PATCH 11/33] Separate user and dev natspec documentation - plus other small changes according to the spec --- libsolidity/CompilerStack.cpp | 23 +++++++++++++++++----- libsolidity/CompilerStack.h | 10 +++++++--- solc/main.cpp | 2 +- test/solidityNatspecJSON.cpp | 37 +++++++++++++++++++++-------------- 4 files changed, 48 insertions(+), 24 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index e44a10fbe..b12097052 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -123,13 +123,13 @@ string const& CompilerStack::getInterface() return m_interface; } -string const& CompilerStack::getDocumentation() +string const& CompilerStack::getUserDocumentation() { Json::StyledWriter writer; if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - if (m_documentation.empty()) + if (m_userDocumentation.empty()) { Json::Value doc; Json::Value methods(Json::objectValue); @@ -140,14 +140,27 @@ string const& CompilerStack::getDocumentation() auto strPtr = f->getDocumentation(); if (strPtr) { - user["user"] = Json::Value(*strPtr); + user["notice"] = Json::Value(*strPtr); methods[f->getName()] = user; } } doc["methods"] = methods; - m_documentation = writer.write(doc); + m_userDocumentation = writer.write(doc); } - return m_documentation; + return m_userDocumentation; +} + +string const& CompilerStack::getDevDocumentation() +{ + Json::StyledWriter writer; + if (!m_parseSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + + if (m_devDocumentation.empty()) + { + // TODO + } + return m_devDocumentation; } bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize) diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 74784c5ef..4e0d2251b 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -62,9 +62,12 @@ public: /// Returns a string representing the contract interface in JSON. /// Prerequisite: Successful call to parse or compile. std::string const& getInterface(); - /// Returns a string representing the contract documentation in JSON. + /// Returns a string representing the contract's user documentation in JSON. /// Prerequisite: Successful call to parse or compile. - std::string const& getDocumentation(); + std::string const& getUserDocumentation(); + /// Returns a string representing the contract's developer documentation in JSON. + /// Prerequisite: Successful call to parse or compile. + std::string const& getDevDocumentation(); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } @@ -80,7 +83,8 @@ private: std::shared_ptr m_contractASTNode; bool m_parseSuccessful; std::string m_interface; - std::string m_documentation; + std::string m_userDocumentation; + std::string m_devDocumentation; std::shared_ptr m_compiler; bytes m_bytecode; }; diff --git a/solc/main.cpp b/solc/main.cpp index 6ca130a79..29239a717 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -136,7 +136,7 @@ int main(int argc, char** argv) cout << eth::disassemble(compiler.getBytecode()) << endl; cout << "Binary: " << toHex(compiler.getBytecode()) << endl; cout << "Interface specification: " << compiler.getInterface() << endl; - cout << "Natspec documentation: " << compiler.getDocumentation() << endl; + cout << "Natspec user documentation: " << compiler.getUserDocumentation() << endl; return 0; } diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index 5a4649d2e..f729e4ff8 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -35,8 +35,11 @@ namespace test class DocumentationChecker { public: - void checkNatspec(std::string const& _code, std::string const& _expectedDocumentationString) + void checkNatspec(std::string const& _code, + std::string const& _expectedDocumentationString, + bool _userDocumentation) { + std::string generatedDocumentationString; try { m_compilerStack.parse(_code); @@ -50,7 +53,11 @@ public: msg += *extra; BOOST_FAIL(msg); } - auto generatedDocumentationString = m_compilerStack.getDocumentation(); + + if (_userDocumentation) + generatedDocumentationString = m_compilerStack.getUserDocumentation(); + else + generatedDocumentationString = m_compilerStack.getDevDocumentation(); Json::Value generatedDocumentation; m_reader.parse(generatedDocumentationString, generatedDocumentation); Json::Value expectedDocumentation; @@ -67,7 +74,7 @@ private: BOOST_FIXTURE_TEST_SUITE(SolidityNatspecJSON, DocumentationChecker) -BOOST_AUTO_TEST_CASE(basic_test) +BOOST_AUTO_TEST_CASE(user_basic_test) { char const* sourceCode = "contract test {\n" " /// Multiplies `a` by 7\n" @@ -76,13 +83,13 @@ BOOST_AUTO_TEST_CASE(basic_test) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \"user\": \" Multiplies `a` by 7\"}" + " \"mul\":{ \"notice\": \" Multiplies `a` by 7\"}" "}}"; - checkNatspec(sourceCode, natspec); + checkNatspec(sourceCode, natspec, true); } -BOOST_AUTO_TEST_CASE(multiline_comment) +BOOST_AUTO_TEST_CASE(user_multiline_comment) { char const* sourceCode = "contract test {\n" " /// Multiplies `a` by 7\n" @@ -95,13 +102,13 @@ BOOST_AUTO_TEST_CASE(multiline_comment) char const* natspec = "{" "\"methods\":{" - " \"mul_and_add\":{ \"user\": \" Multiplies `a` by 7\n and then adds `b`\"}" + " \"mul_and_add\":{ \"notice\": \" Multiplies `a` by 7\n and then adds `b`\"}" "}}"; - checkNatspec(sourceCode, natspec); + checkNatspec(sourceCode, natspec, true); } -BOOST_AUTO_TEST_CASE(multiple_functions) +BOOST_AUTO_TEST_CASE(user_multiple_functions) { char const* sourceCode = "contract test {\n" " /// Multiplies `a` by 7\n" @@ -125,22 +132,22 @@ BOOST_AUTO_TEST_CASE(multiple_functions) char const* natspec = "{" "\"methods\":{" - " \"mul_and_add\":{ \"user\": \" Multiplies `a` by 7\n and then adds `b`\"}," - " \"divide\":{ \"user\": \" Divides `input` by `div`\"}," - " \"sub\":{ \"user\": \" Subtracts 3 from `input`\"}" + " \"mul_and_add\":{ \"notice\": \" Multiplies `a` by 7\n and then adds `b`\"}," + " \"divide\":{ \"notice\": \" Divides `input` by `div`\"}," + " \"sub\":{ \"notice\": \" Subtracts 3 from `input`\"}" "}}"; - checkNatspec(sourceCode, natspec); + checkNatspec(sourceCode, natspec, true); } -BOOST_AUTO_TEST_CASE(empty_contract) +BOOST_AUTO_TEST_CASE(user_empty_contract) { char const* sourceCode = "contract test {\n" "}\n"; char const* natspec = "{\"methods\":{} }"; - checkNatspec(sourceCode, natspec); + checkNatspec(sourceCode, natspec, true); } From 4613214098850490c0da24cfca5c36e5ce014512 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Dec 2014 16:40:37 +0100 Subject: [PATCH 12/33] Moving all Interface and Documentation functionality to own class - Creating the Interface Handler class which will take care of the parsing of Natspec comments and of interfacing with and outputing to JSON files. - Will also handle the ABI interface creation --- libsolidity/CompilerStack.cpp | 90 +++++++----------------------- libsolidity/CompilerStack.h | 26 ++++++--- libsolidity/InterfaceHandler.cpp | 88 +++++++++++++++++++++++++++++ libsolidity/InterfaceHandler.h | 74 ++++++++++++++++++++++++ solc/main.cpp | 5 +- test/solidityJSONInterfaceTest.cpp | 2 +- test/solidityNatspecJSON.cpp | 4 +- 7 files changed, 205 insertions(+), 84 deletions(-) create mode 100644 libsolidity/InterfaceHandler.cpp create mode 100644 libsolidity/InterfaceHandler.h diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index b12097052..6f80d245c 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -27,8 +27,7 @@ #include #include #include - -#include +#include using namespace std; @@ -37,6 +36,8 @@ namespace dev namespace solidity { +CompilerStack::CompilerStack():m_interfaceHandler(make_shared()){} + void CompilerStack::setSource(string const& _sourceCode) { reset(); @@ -83,84 +84,33 @@ void CompilerStack::streamAssembly(ostream& _outStream) m_compiler->streamAssembly(_outStream); } -string const& CompilerStack::getInterface() -{ - Json::StyledWriter writer; - if (!m_parseSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - - if (m_interface.empty()) - { - Json::Value methods(Json::arrayValue); - - vector exportedFunctions = m_contractASTNode->getInterfaceFunctions(); - for (FunctionDefinition const* f: exportedFunctions) - { - Json::Value method; - Json::Value inputs(Json::arrayValue); - Json::Value outputs(Json::arrayValue); - - auto streamVariables = [](vector> const& _vars) - { - Json::Value params(Json::arrayValue); - for (ASTPointer const& var: _vars) - { - Json::Value input; - input["name"] = var->getName(); - input["type"] = var->getType()->toString(); - params.append(input); - } - return params; - }; - - method["name"] = f->getName(); - method["inputs"] = streamVariables(f->getParameters()); - method["outputs"] = streamVariables(f->getReturnParameters()); - methods.append(method); - } - m_interface = writer.write(methods); - } - return m_interface; -} - -string const& CompilerStack::getUserDocumentation() +std::string const* CompilerStack::getJsonDocumentation(enum documentation_type _type) { - Json::StyledWriter writer; if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - if (m_userDocumentation.empty()) + auto createOrReturnDoc = [&, this](std::unique_ptr& _doc) { - Json::Value doc; - Json::Value methods(Json::objectValue); - - for (FunctionDefinition const* f: m_contractASTNode->getInterfaceFunctions()) + if(!_doc) { - Json::Value user; - auto strPtr = f->getDocumentation(); - if (strPtr) - { - user["notice"] = Json::Value(*strPtr); - methods[f->getName()] = user; - } + _doc = m_interfaceHandler->getDocumentation(m_contractASTNode, _type); } - doc["methods"] = methods; - m_userDocumentation = writer.write(doc); - } - return m_userDocumentation; -} - -string const& CompilerStack::getDevDocumentation() -{ - Json::StyledWriter writer; - if (!m_parseSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + }; - if (m_devDocumentation.empty()) + switch (_type) { - // TODO + case NATSPEC_USER: + createOrReturnDoc(m_userDocumentation); + return m_userDocumentation.get(); + case NATSPEC_DEV: + createOrReturnDoc(m_devDocumentation); + return m_devDocumentation.get(); + case ABI_INTERFACE: + createOrReturnDoc(m_interface); + return m_interface.get(); } - return m_devDocumentation; + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal error")); + return nullptr; } bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize) diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 4e0d2251b..7dc86e2be 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -35,6 +35,14 @@ class Scanner; class ContractDefinition; class Compiler; class GlobalContext; +class InterfaceHandler; + +enum documentation_type : unsigned short +{ + NATSPEC_USER = 1, + NATSPEC_DEV, + ABI_INTERFACE +}; /** * Easy to use and self-contained Solidity compiler with as few header dependencies as possible. @@ -44,7 +52,7 @@ class GlobalContext; class CompilerStack { public: - CompilerStack() {} + CompilerStack(); void reset() { *this = CompilerStack(); } void setSource(std::string const& _sourceCode); void parse(); @@ -62,12 +70,11 @@ public: /// Returns a string representing the contract interface in JSON. /// Prerequisite: Successful call to parse or compile. std::string const& getInterface(); - /// Returns a string representing the contract's user documentation in JSON. - /// Prerequisite: Successful call to parse or compile. - std::string const& getUserDocumentation(); - /// Returns a string representing the contract's developer documentation in JSON. + /// Returns a string representing the contract's documentation in JSON. /// Prerequisite: Successful call to parse or compile. - std::string const& getDevDocumentation(); + /// @param type The type of the documentation to get. + /// Can be one of 3 types defined at @c documentation_type + std::string const* getJsonDocumentation(enum documentation_type type); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } @@ -82,10 +89,11 @@ private: std::shared_ptr m_globalContext; std::shared_ptr m_contractASTNode; bool m_parseSuccessful; - std::string m_interface; - std::string m_userDocumentation; - std::string m_devDocumentation; + std::unique_ptr m_interface; + std::unique_ptr m_userDocumentation; + std::unique_ptr m_devDocumentation; std::shared_ptr m_compiler; + std::shared_ptr m_interfaceHandler; bytes m_bytecode; }; diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp new file mode 100644 index 000000000..c0e07280e --- /dev/null +++ b/libsolidity/InterfaceHandler.cpp @@ -0,0 +1,88 @@ +#include +#include +#include + +namespace dev { +namespace solidity { + +InterfaceHandler::InterfaceHandler() +{ +} + +std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr _contractDef, + enum documentation_type _type) +{ + switch(_type) + { + case NATSPEC_USER: + return getUserDocumentation(_contractDef); + case NATSPEC_DEV: + return getDevDocumentation(_contractDef); + case ABI_INTERFACE: + return getABIInterface(_contractDef); + } + + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal error")); + return nullptr; +} + +std::unique_ptr InterfaceHandler::getABIInterface(std::shared_ptr _contractDef) +{ + Json::Value methods(Json::arrayValue); + + std::vector exportedFunctions = _contractDef->getInterfaceFunctions(); + for (FunctionDefinition const* f: exportedFunctions) + { + Json::Value method; + Json::Value inputs(Json::arrayValue); + Json::Value outputs(Json::arrayValue); + + auto streamVariables = [](std::vector> const& _vars) + { + Json::Value params(Json::arrayValue); + for (ASTPointer const& var: _vars) + { + Json::Value input; + input["name"] = var->getName(); + input["type"] = var->getType()->toString(); + params.append(input); + } + return params; + }; + + method["name"] = f->getName(); + method["inputs"] = streamVariables(f->getParameters()); + method["outputs"] = streamVariables(f->getReturnParameters()); + methods.append(method); + } + return std::unique_ptr(new std::string(m_writer.write(methods))); +} + +std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ptr _contractDef) +{ + Json::Value doc; + Json::Value methods(Json::objectValue); + + for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions()) + { + Json::Value user; + auto strPtr = f->getDocumentation(); + if (strPtr) + { + user["notice"] = Json::Value(*strPtr); + methods[f->getName()] = user; + } + } + doc["methods"] = methods; + + return std::unique_ptr(new std::string(m_writer.write(doc))); +} + +std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_ptr _contractDef) +{ + //TODO + return nullptr; +} + +} //solidity NS +} // dev NS diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h new file mode 100644 index 000000000..ed6c8ba44 --- /dev/null +++ b/libsolidity/InterfaceHandler.h @@ -0,0 +1,74 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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. + + cpp-ethereum 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 cpp-ethereum. If not, see . +*/ +/** + * @author Lefteris + * @date 2014 + * Takes the parsed AST and produces the Natspec + * documentation and the ABI interface + * https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format + * + * Can generally deal with JSON files + */ + +#pragma once + +#include +#include +#include + +namespace dev { +namespace solidity { + +// Forward declarations +class ContractDefinition; +enum documentation_type: unsigned short; + +class InterfaceHandler +{ +public: + InterfaceHandler(); + + /// Get the given type of documentation + /// @param _contractDef The contract definition + /// @param _type The type of the documentation. Can be one of the + /// types provided by @c documentation_type + /// @return A unique pointer contained string with the json + /// representation of provided type + std::unique_ptr getDocumentation(std::shared_ptr _contractDef, + enum documentation_type _type); + /// Get the ABI Interface of the contract + /// @param _contractDef The contract definition + /// @return A unique pointer contained string with the json + /// representation of the contract's ABI Interface + std::unique_ptr getABIInterface(std::shared_ptr _contractDef); + /// Get the User documentation of the contract + /// @param _contractDef The contract definition + /// @return A unique pointer contained string with the json + /// representation of the contract's user documentation + std::unique_ptr getUserDocumentation(std::shared_ptr _contractDef); + /// Get the Developer's documentation of the contract + /// @param _contractDef The contract definition + /// @return A unique pointer contained string with the json + /// representation of the contract's developer documentation + std::unique_ptr getDevDocumentation(std::shared_ptr _contractDef); + +private: + Json::StyledWriter m_writer; +}; + +} //solidity NS +} // dev NS diff --git a/solc/main.cpp b/solc/main.cpp index 29239a717..daeb2707c 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -135,8 +135,9 @@ int main(int argc, char** argv) cout << "Opcodes:" << endl; cout << eth::disassemble(compiler.getBytecode()) << endl; cout << "Binary: " << toHex(compiler.getBytecode()) << endl; - cout << "Interface specification: " << compiler.getInterface() << endl; - cout << "Natspec user documentation: " << compiler.getUserDocumentation() << endl; + cout << "Interface specification: " << compiler.getJsonDocumentation(ABI_INTERFACE) << endl; + cout << "Natspec user documentation: " << compiler.getJsonDocumentation(NATSPEC_USER) << endl; + cout << "Natspec developer documentation: " << compiler.getJsonDocumentation(NATSPEC_DEV) << endl; return 0; } diff --git a/test/solidityJSONInterfaceTest.cpp b/test/solidityJSONInterfaceTest.cpp index f46a3ad36..8fe0ea653 100644 --- a/test/solidityJSONInterfaceTest.cpp +++ b/test/solidityJSONInterfaceTest.cpp @@ -50,7 +50,7 @@ public: msg += *extra; BOOST_FAIL(msg); } - std::string generatedInterfaceString = m_compilerStack.getInterface(); + std::string generatedInterfaceString = *m_compilerStack.getJsonDocumentation(ABI_INTERFACE); Json::Value generatedInterface; m_reader.parse(generatedInterfaceString, generatedInterface); Json::Value expectedInterface; diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index f729e4ff8..9e24d23ed 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -55,9 +55,9 @@ public: } if (_userDocumentation) - generatedDocumentationString = m_compilerStack.getUserDocumentation(); + generatedDocumentationString = *m_compilerStack.getJsonDocumentation(NATSPEC_USER); else - generatedDocumentationString = m_compilerStack.getDevDocumentation(); + generatedDocumentationString = *m_compilerStack.getJsonDocumentation(NATSPEC_DEV); Json::Value generatedDocumentation; m_reader.parse(generatedDocumentationString, generatedDocumentation); Json::Value expectedDocumentation; From 9e5a49736cb212468023244d3ae6d5b9c44feb84 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 3 Dec 2014 17:00:52 +0100 Subject: [PATCH 13/33] Avoid need for Qt 5.3. --- mix/qml/BasicContent.qml | 4 ++-- mix/qml/MainContent.qml | 6 +++--- mix/qml/TabStyle.qml | 6 +++--- mix/qml/main.qml | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mix/qml/BasicContent.qml b/mix/qml/BasicContent.qml index 0049e6127..ea1017186 100644 --- a/mix/qml/BasicContent.qml +++ b/mix/qml/BasicContent.qml @@ -1,5 +1,5 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 +import QtQuick 2.2 +import QtQuick.Controls 1.1 Rectangle { anchors.fill: parent diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index f243b16ac..bd4737c3b 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -1,7 +1,7 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 +import QtQuick 2.2 +import QtQuick.Controls 1.1 import QtQuick.Layouts 1.0 -import QtQuick.Controls.Styles 1.2 +import QtQuick.Controls.Styles 1.1 import CodeEditorExtensionManager 1.0 Rectangle { diff --git a/mix/qml/TabStyle.qml b/mix/qml/TabStyle.qml index 5f78f8947..cbae6e25e 100644 --- a/mix/qml/TabStyle.qml +++ b/mix/qml/TabStyle.qml @@ -1,6 +1,6 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Controls.Styles 1.2 +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 TabViewStyle { frameOverlap: 1 diff --git a/mix/qml/main.qml b/mix/qml/main.qml index 8a1b86cee..3553f7710 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -1,6 +1,6 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Controls.Styles 1.2 +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 import CodeEditorExtensionManager 1.0 ApplicationWindow { From eeb186c834aaf30ba63a10585cc9c66ae33fcd6c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Dec 2014 17:46:04 +0100 Subject: [PATCH 14/33] Work in progress for parsing natspec doxytags --- libsolidity/InterfaceHandler.cpp | 69 ++++++++++++++++++++++++++++++-- libsolidity/InterfaceHandler.h | 11 ++++- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index c0e07280e..a2c52c1f0 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -5,12 +5,14 @@ namespace dev { namespace solidity { +/* -- public -- */ + InterfaceHandler::InterfaceHandler() { } std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr _contractDef, - enum documentation_type _type) + enum documentation_type _type) { switch(_type) { @@ -80,8 +82,69 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_ptr _contractDef) { - //TODO - return nullptr; + Json::Value doc; + Json::Value methods(Json::objectValue); + + for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions()) + { + Json::Value method; + auto strPtr = f->getDocumentation(); + if (strPtr) + { + m_dev.clear(); + parseDocString(*strPtr); + + method["dev"] = Json::Value(m_dev); + methods[f->getName()] = method; + } + } + doc["methods"] = methods; + + return std::unique_ptr(new std::string(m_writer.write(doc))); +} + +/* -- private -- */ +size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos) +{ + size_t nlPos = _pos; + if (_tag == "dev") + { + nlPos = _string.find("\n", _pos); + m_dev += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + } + else if (_tag == "notice") + { + nlPos = _string.find("\n", _pos); + m_notice += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + } + else + { + //TODO: Some form of warning + } + + return nlPos; +} + +void InterfaceHandler::parseDocString(std::string const& _string, size_t _startPos) +{ + size_t pos2; + size_t pos1 = _string.find("@", _startPos); + + if (pos1 == std::string::npos) + return; // no doxytags found + + pos2 = _string.find(" ", pos1); + if (pos2 == std::string::npos) + return; //no end of tag found + + size_t newPos = parseDocTag(_string, _string.substr(pos1 + 1, pos2 - pos1), pos2); + parseDocString(_string, newPos); } } //solidity NS diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index ed6c8ba44..125ecda4b 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -20,7 +20,7 @@ * Takes the parsed AST and produces the Natspec * documentation and the ABI interface * https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format - * + * * Can generally deal with JSON files */ @@ -44,7 +44,7 @@ public: /// Get the given type of documentation /// @param _contractDef The contract definition - /// @param _type The type of the documentation. Can be one of the + /// @param _type The type of the documentation. Can be one of the /// types provided by @c documentation_type /// @return A unique pointer contained string with the json /// representation of provided type @@ -67,7 +67,14 @@ public: std::unique_ptr getDevDocumentation(std::shared_ptr _contractDef); private: + void parseDocString(std::string const& _string, size_t _startPos = 0); + size_t parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos); + Json::StyledWriter m_writer; + + // internal state + std::string m_notice; + std::string m_dev; }; } //solidity NS From a769ac51023eee79e73fb9db928b2c75fa0debd3 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 3 Dec 2014 19:49:38 +0100 Subject: [PATCH 15/33] expire whisper messages --- libwhisper/WhisperHost.cpp | 2 +- libwhisper/WhisperPeer.cpp | 35 ++++++++++++----------------------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 9b26e3260..769b39057 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -118,7 +118,6 @@ unsigned WhisperHost::installWatch(shh::TopicFilter const& _f) h256s WhisperHost::watchMessages(unsigned _watchId) { - cleanup(); h256s ret; auto wit = m_watches.find(_watchId); if (wit == m_watches.end()) @@ -160,6 +159,7 @@ void WhisperHost::doWork() { for (auto& i: peers()) i->cap()->sendMessages(); + cleanup(); } void WhisperHost::cleanup() diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index c3a28e3c3..98bf0bc61 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -82,33 +82,22 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r) void WhisperPeer::sendMessages() { - RLPStream amalg; - unsigned n = 0; - + if (m_unseen.size()) { - Guard l(x_unseen); - while (m_unseen.size()) + RLPStream amalg; + unsigned msgCount = m_unseen.size(); { - auto p = *m_unseen.begin(); - m_unseen.erase(m_unseen.begin()); - host()->streamMessage(p.second, amalg); - n++; + Guard l(x_unseen); + while (m_unseen.size()) + { + auto p = *m_unseen.begin(); + m_unseen.erase(m_unseen.begin()); + host()->streamMessage(p.second, amalg); + } } - } - - // the message subsystem should really just keep pumping out messages while m_unseen.size() and there's bandwidth for them. - auto diff = chrono::duration_cast(chrono::system_clock::now() - m_timer); - if (n || diff.count() > 0) - { - RLPStream s; - prep(s, MessagesPacket, n).appendRaw(amalg.out(), n); - sealAndSend(s); - m_timer = chrono::system_clock::now(); - } - - { + RLPStream s; - prep(s, MessagesPacket, n).appendRaw(amalg.out(), n); + prep(s, MessagesPacket, msgCount).appendRaw(amalg.out(), msgCount); sealAndSend(s); } } From b10eddc85e60052ad104da5987eca85b4ae4fc9d Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 3 Dec 2014 20:12:25 +0100 Subject: [PATCH 16/33] static to member in Host::run() --- libp2p/Host.cpp | 9 ++++----- libp2p/Host.h | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 546d54c00..7d08910aa 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -700,8 +700,7 @@ PeerInfos Host::peers(bool _updatePing) const void Host::run(boost::system::error_code const& error) { - static unsigned s_lastTick = 0; - s_lastTick += c_timerInterval; + m_lastTick += c_timerInterval; if (error || !m_ioService) { @@ -713,11 +712,11 @@ void Host::run(boost::system::error_code const& error) // network running if (m_run) { - if (s_lastTick >= c_timerInterval * 10) + if (m_lastTick >= c_timerInterval * 10) { growPeers(); prunePeers(); - s_lastTick = 0; + m_lastTick = 0; } if (m_hadNewNodes) @@ -783,7 +782,7 @@ void Host::run(boost::system::error_code const& error) m_socket->close(); // m_run is false, so we're stopping; kill timer - s_lastTick = 0; + m_lastTick = 0; // causes parent thread's stop() to continue which calls stopWorking() m_timer.reset(); diff --git a/libp2p/Host.h b/libp2p/Host.h index 9ee2c1b4a..644afeb69 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -241,6 +241,7 @@ private: std::unique_ptr m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms. static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected. + unsigned m_lastTick = 0; ///< Used by run() for scheduling; must not be mutated outside of run(). std::set m_pendingNodeConns; /// Used only by connect(Node&) to limit concurrently connecting to same node. See connect(shared_ptrconst&). Mutex x_pendingNodeConns; From 8a4a4b8b56e9e134737b54f0865fc5587f006a38 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 3 Dec 2014 20:14:57 +0100 Subject: [PATCH 17/33] thread-safety fix --- libwhisper/WhisperPeer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index 98bf0bc61..0951a3726 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -85,9 +85,10 @@ void WhisperPeer::sendMessages() if (m_unseen.size()) { RLPStream amalg; - unsigned msgCount = m_unseen.size(); + unsigned msgCount; { Guard l(x_unseen); + msgCount = m_unseen.size(); while (m_unseen.size()) { auto p = *m_unseen.begin(); From 2f16217574b2d610967ee094e209065d50531f90 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 4 Dec 2014 01:27:38 +0100 Subject: [PATCH 18/33] Styling in libsolidity's InterfaceHandler --- libsolidity/CompilerStack.cpp | 4 ++-- libsolidity/CompilerStack.h | 4 ++-- libsolidity/InterfaceHandler.cpp | 8 ++++---- libsolidity/InterfaceHandler.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 6f80d245c..3e9791bd2 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -84,12 +84,12 @@ void CompilerStack::streamAssembly(ostream& _outStream) m_compiler->streamAssembly(_outStream); } -std::string const* CompilerStack::getJsonDocumentation(enum documentation_type _type) +std::string const* CompilerStack::getJsonDocumentation(enum documentationType _type) { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - auto createOrReturnDoc = [&, this](std::unique_ptr& _doc) + auto createOrReturnDoc = [this, _type](std::unique_ptr& _doc) { if(!_doc) { diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 7dc86e2be..511951291 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -37,7 +37,7 @@ class Compiler; class GlobalContext; class InterfaceHandler; -enum documentation_type : unsigned short +enum documentationType: unsigned short { NATSPEC_USER = 1, NATSPEC_DEV, @@ -74,7 +74,7 @@ public: /// Prerequisite: Successful call to parse or compile. /// @param type The type of the documentation to get. /// Can be one of 3 types defined at @c documentation_type - std::string const* getJsonDocumentation(enum documentation_type type); + std::string const* getJsonDocumentation(enum documentationType type); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index a2c52c1f0..61570b8d7 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -12,7 +12,7 @@ InterfaceHandler::InterfaceHandler() } std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr _contractDef, - enum documentation_type _type) + enum documentationType _type) { switch(_type) { @@ -39,7 +39,7 @@ std::unique_ptr InterfaceHandler::getABIInterface(std::shared_ptr> const& _vars) + auto populateParameters = [](std::vector> const& _vars) { Json::Value params(Json::arrayValue); for (ASTPointer const& var: _vars) @@ -53,8 +53,8 @@ std::unique_ptr InterfaceHandler::getABIInterface(std::shared_ptrgetName(); - method["inputs"] = streamVariables(f->getParameters()); - method["outputs"] = streamVariables(f->getReturnParameters()); + method["inputs"] = populateParameters(f->getParameters()); + method["outputs"] = populateParameters(f->getReturnParameters()); methods.append(method); } return std::unique_ptr(new std::string(m_writer.write(methods))); diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index 125ecda4b..5c8bf5bca 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -35,7 +35,7 @@ namespace solidity { // Forward declarations class ContractDefinition; -enum documentation_type: unsigned short; +enum documentationType: unsigned short; class InterfaceHandler { @@ -49,7 +49,7 @@ public: /// @return A unique pointer contained string with the json /// representation of provided type std::unique_ptr getDocumentation(std::shared_ptr _contractDef, - enum documentation_type _type); + enum documentationType _type); /// Get the ABI Interface of the contract /// @param _contractDef The contract definition /// @return A unique pointer contained string with the json From e560ef983afde181027fc52f49f8c3b15843a164 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 4 Dec 2014 01:36:48 +0100 Subject: [PATCH 19/33] fixed mix project not being built on macos --- mix/CodeEditorExtensionManager.cpp | 1 - mix/EthereumMacOSXBundleInfo.plist.in | 38 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 mix/EthereumMacOSXBundleInfo.plist.in diff --git a/mix/CodeEditorExtensionManager.cpp b/mix/CodeEditorExtensionManager.cpp index 596aea165..c778d466f 100644 --- a/mix/CodeEditorExtensionManager.cpp +++ b/mix/CodeEditorExtensionManager.cpp @@ -27,7 +27,6 @@ #include #include #include "ConstantCompilationCtrl.h" -#include "features.h" #include "ApplicationCtx.h" #include "CodeEditorExtensionManager.h" using namespace dev::mix; diff --git a/mix/EthereumMacOSXBundleInfo.plist.in b/mix/EthereumMacOSXBundleInfo.plist.in new file mode 100644 index 000000000..684ad7908 --- /dev/null +++ b/mix/EthereumMacOSXBundleInfo.plist.in @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + LSRequiresCarbon + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + NSHighResolutionCapable + + + From 5fe11335834395d5b8033a5b24eb6ae7c225e4f2 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 4 Dec 2014 09:42:38 +0100 Subject: [PATCH 20/33] Parsing notice and dev doxytags. - Only initial work done. Still need to refine the logic and incorporate all the other types of tags. - Added/Modified some tests - Work in progress --- libsolidity/InterfaceHandler.cpp | 90 ++++++++++++++++++++++++-------- libsolidity/InterfaceHandler.h | 8 +++ test/solidityNatspecJSON.cpp | 58 ++++++++++++++++---- 3 files changed, 122 insertions(+), 34 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 61570b8d7..e7da5e6d5 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -9,6 +9,7 @@ namespace solidity { InterfaceHandler::InterfaceHandler() { + m_lastTag = DOCTAG_NONE; } std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr _contractDef, @@ -71,7 +72,9 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ auto strPtr = f->getDocumentation(); if (strPtr) { - user["notice"] = Json::Value(*strPtr); + m_notice.clear(); + parseDocString(*strPtr); + user["notice"] = Json::Value(m_notice); methods[f->getName()] = user; } } @@ -94,7 +97,7 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p m_dev.clear(); parseDocString(*strPtr); - method["dev"] = Json::Value(m_dev); + method["details"] = Json::Value(m_dev); methods[f->getName()] = method; } } @@ -106,26 +109,55 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p /* -- private -- */ size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos) { + //TODO: This is pretty naive at the moment. e.g. need to check for + // '@' between _pos and \n, remove redundancy e.t.c. size_t nlPos = _pos; - if (_tag == "dev") - { - nlPos = _string.find("\n", _pos); - m_dev += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); - } - else if (_tag == "notice") + if (m_lastTag == DOCTAG_NONE || _tag != "") { - nlPos = _string.find("\n", _pos); - m_notice += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); + if (_tag == "dev") + { + nlPos = _string.find("\n", _pos); + m_dev += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + m_lastTag = DOCTAG_DEV; + } + else if (_tag == "notice") + { + nlPos = _string.find("\n", _pos); + m_notice += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + m_lastTag = DOCTAG_NOTICE; + } + else + { + //TODO: Some form of warning + } } else { - //TODO: Some form of warning + switch(m_lastTag) + { + case DOCTAG_DEV: + nlPos = _string.find("\n", _pos); + m_dev += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + break; + case DOCTAG_NOTICE: + nlPos = _string.find("\n", _pos); + m_notice += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + break; + default: + break; + } } return nlPos; @@ -134,16 +166,28 @@ size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string con void InterfaceHandler::parseDocString(std::string const& _string, size_t _startPos) { size_t pos2; + size_t newPos = _startPos; size_t pos1 = _string.find("@", _startPos); - if (pos1 == std::string::npos) - return; // no doxytags found + if (pos1 != std::string::npos) + { + // we found a tag + pos2 = _string.find(" ", pos1); + if (pos2 == std::string::npos) + { + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); + return; //no end of tag found + } - pos2 = _string.find(" ", pos1); - if (pos2 == std::string::npos) - return; //no end of tag found + newPos = parseDocTag(_string, _string.substr(pos1 + 1, pos2 - pos1 - 1), pos2 + 1); + } + else + { + newPos = parseDocTag(_string, "", _startPos + 1); + } - size_t newPos = parseDocTag(_string, _string.substr(pos1 + 1, pos2 - pos1), pos2); + if (newPos == std::string::npos) + return; // EOS parseDocString(_string, newPos); } diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index 5c8bf5bca..6f2f2937d 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -37,6 +37,13 @@ namespace solidity { class ContractDefinition; enum documentationType: unsigned short; +enum docTagType +{ + DOCTAG_NONE = 0, + DOCTAG_DEV, + DOCTAG_NOTICE, +}; + class InterfaceHandler { public: @@ -73,6 +80,7 @@ private: Json::StyledWriter m_writer; // internal state + enum docTagType m_lastTag; std::string m_notice; std::string m_dev; }; diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index 9e24d23ed..d74aa8ab9 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -77,22 +77,59 @@ BOOST_FIXTURE_TEST_SUITE(SolidityNatspecJSON, DocumentationChecker) BOOST_AUTO_TEST_CASE(user_basic_test) { char const* sourceCode = "contract test {\n" - " /// Multiplies `a` by 7\n" + " /// @notice Multiplies `a` by 7\n" " function mul(uint a) returns(uint d) { return a * 7; }\n" "}\n"; char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \"notice\": \" Multiplies `a` by 7\"}" + " \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}" "}}"; checkNatspec(sourceCode, natspec, true); } +BOOST_AUTO_TEST_CASE(dev_basic_test) +{ + char const* sourceCode = "contract test {\n" + " /// @dev Multiplies a number by 7\n" + " function mul(uint a) returns(uint d) { return a * 7; }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul\":{ \"details\": \"Multiplies a number by 7\"}" + "}}"; + + checkNatspec(sourceCode, natspec, false); +} + +BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) +{ + char const* sourceCode = "contract test {\n" + " /// @notice Multiplies `a` by 7\n" + " /// @dev Multiplies a number by 7\n" + " function mul(uint a) returns(uint d) { return a * 7; }\n" + "}\n"; + + char const* devNatspec = "{" + "\"methods\":{" + " \"mul\":{ \"details\": \"Multiplies a number by 7\"}" + "}}"; + + char const* userNatspec = "{" + "\"methods\":{" + " \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}" + "}}"; + + checkNatspec(sourceCode, devNatspec, false); + checkNatspec(sourceCode, userNatspec, true); +} + BOOST_AUTO_TEST_CASE(user_multiline_comment) { char const* sourceCode = "contract test {\n" - " /// Multiplies `a` by 7\n" + " /// @notice Multiplies `a` by 7\n" " /// and then adds `b`\n" " function mul_and_add(uint a, uint256 b) returns(uint256 d)\n" " {\n" @@ -102,7 +139,7 @@ BOOST_AUTO_TEST_CASE(user_multiline_comment) char const* natspec = "{" "\"methods\":{" - " \"mul_and_add\":{ \"notice\": \" Multiplies `a` by 7\n and then adds `b`\"}" + " \"mul_and_add\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}" "}}"; checkNatspec(sourceCode, natspec, true); @@ -111,19 +148,18 @@ BOOST_AUTO_TEST_CASE(user_multiline_comment) BOOST_AUTO_TEST_CASE(user_multiple_functions) { char const* sourceCode = "contract test {\n" - " /// Multiplies `a` by 7\n" - " /// and then adds `b`\n" + " /// @notice Multiplies `a` by 7 and then adds `b`\n" " function mul_and_add(uint a, uint256 b) returns(uint256 d)\n" " {\n" " return (a * 7) + b;\n" " }\n" "\n" - " /// Divides `input` by `div`\n" + " /// @notice Divides `input` by `div`\n" " function divide(uint input, uint div) returns(uint d)\n" " {\n" " return input / div;\n" " }\n" - " /// Subtracts 3 from `input`\n" + " /// @notice Subtracts 3 from `input`\n" " function sub(int input) returns(int d)\n" " {\n" " return input - 3;\n" @@ -132,9 +168,9 @@ BOOST_AUTO_TEST_CASE(user_multiple_functions) char const* natspec = "{" "\"methods\":{" - " \"mul_and_add\":{ \"notice\": \" Multiplies `a` by 7\n and then adds `b`\"}," - " \"divide\":{ \"notice\": \" Divides `input` by `div`\"}," - " \"sub\":{ \"notice\": \" Subtracts 3 from `input`\"}" + " \"mul_and_add\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}," + " \"divide\":{ \"notice\": \"Divides `input` by `div`\"}," + " \"sub\":{ \"notice\": \"Subtracts 3 from `input`\"}" "}}"; checkNatspec(sourceCode, natspec, true); From 638a784c92659a7e061fc82c27f3a98c97c5d6cf Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 4 Dec 2014 10:13:31 +0100 Subject: [PATCH 21/33] ide working on macos! --- mix/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/CMakeLists.txt b/mix/CMakeLists.txt index da214fd29..0252b5226 100644 --- a/mix/CMakeLists.txt +++ b/mix/CMakeLists.txt @@ -61,7 +61,7 @@ target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore dev if (APPLE) # First have qt5 install plugins and frameworks add_custom_command(TARGET ${EXECUTEABLE} POST_BUILD - COMMAND /usr/local/opt/qt5/bin/macdeployqt ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTEABLE}.app + COMMAND /usr/local/opt/qt5/bin/macdeployqt -qmldir=${CMAKE_CURRENT_SOURCE_DIR}/qml ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTEABLE}.app WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) # This tool and next will inspect linked libraries in order to determine which dependencies are required From 5ccf4ca52c9c38e478de8176f18d3b406e58e34b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 4 Dec 2014 14:04:48 +0100 Subject: [PATCH 22/33] Protocol bump. --- libethcore/CommonEth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 744e85a27..e68839ed5 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -33,7 +33,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 46; +const unsigned c_protocolVersion = 47; const unsigned c_databaseVersion = 5; static const vector> g_units = From 112c583ddb3b43a7260156ab65694e55aac20130 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 4 Dec 2014 17:19:47 +0100 Subject: [PATCH 23/33] Natspec parsing @param doctags - Plus additional work on generally parsing doctags. One important missing feature is to parse a tag midline - Adding more tests --- libsolidity/InterfaceHandler.cpp | 158 ++++++++++++++++++++++--------- libsolidity/InterfaceHandler.h | 9 ++ test/solidityNatspecJSON.cpp | 117 +++++++++++++++++++---- 3 files changed, 225 insertions(+), 59 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index e7da5e6d5..222711e6a 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -1,3 +1,4 @@ + #include #include #include @@ -72,7 +73,7 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ auto strPtr = f->getDocumentation(); if (strPtr) { - m_notice.clear(); + resetUser(); parseDocString(*strPtr); user["notice"] = Json::Value(m_notice); methods[f->getName()] = user; @@ -94,10 +95,16 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p auto strPtr = f->getDocumentation(); if (strPtr) { - m_dev.clear(); + resetDev(); parseDocString(*strPtr); method["details"] = Json::Value(m_dev); + Json::Value params(Json::objectValue); + for (auto const& pair: m_params) + { + params[pair.first] = pair.second; + } + method["params"] = params; methods[f->getName()] = method; } } @@ -107,86 +114,151 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p } /* -- private -- */ +void InterfaceHandler::resetUser() +{ + m_notice.clear(); +} + +void InterfaceHandler::resetDev() +{ + m_dev.clear(); + m_params.clear(); +} + +size_t skipLineOrEOS(std::string const& _string, size_t _nlPos) +{ + return (_nlPos == std::string::npos) ? _string.length() : _nlPos + 1; +} + +size_t InterfaceHandler::parseDocTagLine(std::string const& _string, + std::string& _tagString, + size_t _pos, + enum docTagType _tagType) +{ + size_t nlPos = _string.find("\n", _pos); + _tagString += _string.substr(_pos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _pos); + m_lastTag = _tagType; + return skipLineOrEOS(_string, nlPos); +} + +size_t InterfaceHandler::parseDocTagParam(std::string const& _string, size_t _startPos) +{ + // find param name + size_t currPos = _string.find(" ", _startPos); + if (currPos == std::string::npos) + { + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of param name not found")); + return currPos; //no end of tag found + } + + auto paramName = _string.substr(_startPos, currPos - _startPos); + + currPos += 1; + size_t nlPos = _string.find("\n", currPos); + auto paramDesc = _string.substr(currPos, + nlPos == std::string::npos ? + _string.length() : + nlPos - currPos); + + m_params.push_back(std::make_pair(paramName, paramDesc)); + + m_lastTag = DOCTAG_PARAM; + return skipLineOrEOS(_string, nlPos); +} + +size_t InterfaceHandler::appendDocTagParam(std::string const& _string, size_t _startPos) +{ + // Should never be called with an empty vector + assert(!m_params.empty()); + + auto pair = m_params.back(); + size_t nlPos = _string.find("\n", _startPos); + pair.second += _string.substr(_startPos, + nlPos == std::string::npos ? + _string.length() : + nlPos - _startPos); + + m_params.at(m_params.size() - 1) = pair; + + return skipLineOrEOS(_string, nlPos); +} + size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos) { - //TODO: This is pretty naive at the moment. e.g. need to check for - // '@' between _pos and \n, remove redundancy e.t.c. + //TODO: need to check for @(start of a tag) between here and the end of line + // for all cases size_t nlPos = _pos; if (m_lastTag == DOCTAG_NONE || _tag != "") { if (_tag == "dev") - { - nlPos = _string.find("\n", _pos); - m_dev += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); - m_lastTag = DOCTAG_DEV; - } + nlPos = parseDocTagLine(_string, m_dev, _pos, DOCTAG_DEV); else if (_tag == "notice") - { - nlPos = _string.find("\n", _pos); - m_notice += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); - m_lastTag = DOCTAG_NOTICE; - } + nlPos = parseDocTagLine(_string, m_notice, _pos, DOCTAG_NOTICE); + else if (_tag == "param") + nlPos = parseDocTagParam(_string, _pos); else { //TODO: Some form of warning } } else + appendDocTag(_string, _pos); + + return nlPos; +} + +size_t InterfaceHandler::appendDocTag(std::string const& _string, size_t _startPos) +{ + size_t newPos = _startPos; + switch(m_lastTag) { - switch(m_lastTag) - { case DOCTAG_DEV: - nlPos = _string.find("\n", _pos); - m_dev += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); + m_dev += " "; + newPos = parseDocTagLine(_string, m_dev, _startPos, DOCTAG_DEV); break; case DOCTAG_NOTICE: - nlPos = _string.find("\n", _pos); - m_notice += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() : - nlPos - _pos); + m_notice += " "; + newPos = parseDocTagLine(_string, m_notice, _startPos, DOCTAG_NOTICE); + break; + case DOCTAG_PARAM: + newPos = appendDocTagParam(_string, _startPos); break; default: break; } - } - - return nlPos; + return newPos; } void InterfaceHandler::parseDocString(std::string const& _string, size_t _startPos) { size_t pos2; size_t newPos = _startPos; - size_t pos1 = _string.find("@", _startPos); + size_t tagPos = _string.find("@", _startPos); + size_t nlPos = _string.find("\n", _startPos); - if (pos1 != std::string::npos) + if (tagPos != std::string::npos && tagPos < nlPos) { // we found a tag - pos2 = _string.find(" ", pos1); + pos2 = _string.find(" ", tagPos); if (pos2 == std::string::npos) { BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); return; //no end of tag found } - newPos = parseDocTag(_string, _string.substr(pos1 + 1, pos2 - pos1 - 1), pos2 + 1); + newPos = parseDocTag(_string, _string.substr(tagPos + 1, pos2 - tagPos - 1), pos2 + 1); } - else + else if (m_lastTag != DOCTAG_NONE) // continuation of the previous tag + newPos = appendDocTag(_string, _startPos + 1); + else // skip the line if a newline was found { - newPos = parseDocTag(_string, "", _startPos + 1); + if (newPos != std::string::npos) + newPos = nlPos + 1; } - - if (newPos == std::string::npos) + if (newPos == std::string::npos || newPos == _string.length()) return; // EOS parseDocString(_string, newPos); } diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index 6f2f2937d..2a70af950 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -42,6 +42,7 @@ enum docTagType DOCTAG_NONE = 0, DOCTAG_DEV, DOCTAG_NOTICE, + DOCTAG_PARAM }; class InterfaceHandler @@ -74,7 +75,14 @@ public: std::unique_ptr getDevDocumentation(std::shared_ptr _contractDef); private: + void resetUser(); + void resetDev(); + + size_t parseDocTagLine(std::string const& _string, std::string& _tagString, size_t _pos, enum docTagType _tagType); + size_t parseDocTagParam(std::string const& _string, size_t _startPos); + size_t appendDocTagParam(std::string const& _string, size_t _startPos); void parseDocString(std::string const& _string, size_t _startPos = 0); + size_t appendDocTag(std::string const& _string, size_t _startPos); size_t parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos); Json::StyledWriter m_writer; @@ -83,6 +91,7 @@ private: enum docTagType m_lastTag; std::string m_notice; std::string m_dev; + std::vector> m_params; }; } //solidity NS diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index d74aa8ab9..5894f3b04 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -89,21 +89,6 @@ BOOST_AUTO_TEST_CASE(user_basic_test) checkNatspec(sourceCode, natspec, true); } -BOOST_AUTO_TEST_CASE(dev_basic_test) -{ - char const* sourceCode = "contract test {\n" - " /// @dev Multiplies a number by 7\n" - " function mul(uint a) returns(uint d) { return a * 7; }\n" - "}\n"; - - char const* natspec = "{" - "\"methods\":{" - " \"mul\":{ \"details\": \"Multiplies a number by 7\"}" - "}}"; - - checkNatspec(sourceCode, natspec, false); -} - BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) { char const* sourceCode = "contract test {\n" @@ -114,7 +99,11 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) char const* devNatspec = "{" "\"methods\":{" - " \"mul\":{ \"details\": \"Multiplies a number by 7\"}" + " \"mul\":{ \n" + " \"details\": \"Multiplies a number by 7\",\n" + " \"params\": {}\n" + " }\n" + " }\n" "}}"; char const* userNatspec = "{" @@ -186,6 +175,102 @@ BOOST_AUTO_TEST_CASE(user_empty_contract) checkNatspec(sourceCode, natspec, true); } +BOOST_AUTO_TEST_CASE(dev_multiple_params) +{ + char const* sourceCode = "contract test {\n" + " /// @dev Multiplies a number by 7 and adds second parameter\n" + " /// @param a Documentation for the first parameter\n" + " /// @param second Documentation for the second parameter\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul\":{ \n" + " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" + " \"params\": {\n" + " \"a\": \"Documentation for the first parameter\",\n" + " \"second\": \"Documentation for the second parameter\"\n" + " }\n" + " }\n" + "}}"; + + checkNatspec(sourceCode, natspec, false); +} + +BOOST_AUTO_TEST_CASE(dev_mutiline_param_description) +{ + char const* sourceCode = "contract test {\n" + " /// @dev Multiplies a number by 7 and adds second parameter\n" + " /// @param a Documentation for the first parameter starts here.\n" + " /// Since it's a really complicated parameter we need 2 lines\n" + " /// @param second Documentation for the second parameter\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul\":{ \n" + " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" + " \"params\": {\n" + " \"a\": \"Documentation for the first parameter starts here.Since it's a really complicated parameter we need 2 lines\",\n" + " \"second\": \"Documentation for the second parameter\"\n" + " }\n" + " }\n" + "}}"; + + checkNatspec(sourceCode, natspec, false); +} + +BOOST_AUTO_TEST_CASE(dev_multiple_functions) +{ + char const* sourceCode = "contract test {\n" + " /// @dev Multiplies a number by 7 and adds second parameter\n" + " /// @param a Documentation for the first parameter\n" + " /// @param second Documentation for the second parameter\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + " \n" + " /// @dev Divides 2 numbers\n" + " /// @param input Documentation for the input parameter\n" + " /// @param div Documentation for the div parameter\n" + " function divide(uint input, uint div) returns(uint d)\n" + " {\n" + " return input / div;\n" + " }\n" + " /// @dev Subtracts 3 from `input`\n" + " /// @param input Documentation for the input parameter\n" + " function sub(int input) returns(int d)\n" + " {\n" + " return input - 3;\n" + " }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul\":{ \n" + " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" + " \"params\": {\n" + " \"a\": \"Documentation for the first parameter\",\n" + " \"second\": \"Documentation for the second parameter\"\n" + " }\n" + " },\n" + " \"divide\":{ \n" + " \"details\": \"Divides 2 numbers\",\n" + " \"params\": {\n" + " \"input\": \"Documentation for the input parameter\",\n" + " \"div\": \"Documentation for the div parameter\"\n" + " }\n" + " },\n" + " \"sub\":{ \n" + " \"details\": \"Subtracts 3 from `input`\",\n" + " \"params\": {\n" + " \"input\": \"Documentation for the input parameter\"\n" + " }\n" + " }\n" + "}}"; + + checkNatspec(sourceCode, natspec, false); +} BOOST_AUTO_TEST_SUITE_END() From 69bb2a38b97f25b7973e094a89b9f2126aee8023 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 4 Dec 2014 18:12:52 +0100 Subject: [PATCH 24/33] Natspec @return tag parsing - Also omitting tags from the output JSON file if they are missing instead of providing an empty string for their value --- libsolidity/InterfaceHandler.cpp | 32 +++++++++++--- libsolidity/InterfaceHandler.h | 4 +- test/solidityNatspecJSON.cpp | 74 +++++++++++++++++++++++++++++++- 3 files changed, 100 insertions(+), 10 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 222711e6a..2a6de2c35 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -75,8 +75,11 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ { resetUser(); parseDocString(*strPtr); - user["notice"] = Json::Value(m_notice); - methods[f->getName()] = user; + if (!m_notice.empty()) + {// since @notice is the only user tag if missing function should not appear + user["notice"] = Json::Value(m_notice); + methods[f->getName()] = user; + } } } doc["methods"] = methods; @@ -86,6 +89,8 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(std::shared_ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_ptr _contractDef) { + // LTODO: Somewhere in this function warnings for mismatch of param names + // should be thrown Json::Value doc; Json::Value methods(Json::objectValue); @@ -98,14 +103,20 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p resetDev(); parseDocString(*strPtr); - method["details"] = Json::Value(m_dev); + if (!m_dev.empty()) + method["details"] = Json::Value(m_dev); Json::Value params(Json::objectValue); for (auto const& pair: m_params) { params[pair.first] = pair.second; } - method["params"] = params; - methods[f->getName()] = method; + if (!m_params.empty()) + method["params"] = params; + if (!m_return.empty()) + method["return"] = m_return; + + if (!method.empty()) // add the function, only if we have any documentation to add + methods[f->getName()] = method; } } doc["methods"] = methods; @@ -122,6 +133,7 @@ void InterfaceHandler::resetUser() void InterfaceHandler::resetDev() { m_dev.clear(); + m_return.clear(); m_params.clear(); } @@ -188,7 +200,7 @@ size_t InterfaceHandler::appendDocTagParam(std::string const& _string, size_t _s size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos) { - //TODO: need to check for @(start of a tag) between here and the end of line + // LTODO: need to check for @(start of a tag) between here and the end of line // for all cases size_t nlPos = _pos; if (m_lastTag == DOCTAG_NONE || _tag != "") @@ -197,11 +209,13 @@ size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string con nlPos = parseDocTagLine(_string, m_dev, _pos, DOCTAG_DEV); else if (_tag == "notice") nlPos = parseDocTagLine(_string, m_notice, _pos, DOCTAG_NOTICE); + else if (_tag == "return") + nlPos = parseDocTagLine(_string, m_return, _pos, DOCTAG_RETURN); else if (_tag == "param") nlPos = parseDocTagParam(_string, _pos); else { - //TODO: Some form of warning + // LTODO: Unknown tas, throw some form of warning } } else @@ -223,6 +237,10 @@ size_t InterfaceHandler::appendDocTag(std::string const& _string, size_t _startP m_notice += " "; newPos = parseDocTagLine(_string, m_notice, _startPos, DOCTAG_NOTICE); break; + case DOCTAG_RETURN: + m_return += " "; + newPos = parseDocTagLine(_string, m_return, _startPos, DOCTAG_RETURN); + break; case DOCTAG_PARAM: newPos = appendDocTagParam(_string, _startPos); break; diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index 2a70af950..eeaed033d 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -42,7 +42,8 @@ enum docTagType DOCTAG_NONE = 0, DOCTAG_DEV, DOCTAG_NOTICE, - DOCTAG_PARAM + DOCTAG_PARAM, + DOCTAG_RETURN }; class InterfaceHandler @@ -91,6 +92,7 @@ private: enum docTagType m_lastTag; std::string m_notice; std::string m_dev; + std::string m_return; std::vector> m_params; }; diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index 5894f3b04..2c4be219b 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -100,8 +100,7 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) char const* devNatspec = "{" "\"methods\":{" " \"mul\":{ \n" - " \"details\": \"Multiplies a number by 7\",\n" - " \"params\": {}\n" + " \"details\": \"Multiplies a number by 7\"\n" " }\n" " }\n" "}}"; @@ -175,6 +174,24 @@ BOOST_AUTO_TEST_CASE(user_empty_contract) checkNatspec(sourceCode, natspec, true); } +BOOST_AUTO_TEST_CASE(dev_and_user_no_doc) +{ + char const* sourceCode = "contract test {\n" + " function mul(uint a) returns(uint d) { return a * 7; }\n" + " function sub(int input) returns(int d)\n" + " {\n" + " return input - 3;\n" + " }\n" + "}\n"; + + char const* devNatspec = "{\"methods\":{}}"; + + char const* userNatspec = "{\"methods\":{}}"; + + checkNatspec(sourceCode, devNatspec, false); + checkNatspec(sourceCode, userNatspec, true); +} + BOOST_AUTO_TEST_CASE(dev_multiple_params) { char const* sourceCode = "contract test {\n" @@ -272,6 +289,59 @@ BOOST_AUTO_TEST_CASE(dev_multiple_functions) checkNatspec(sourceCode, natspec, false); } +BOOST_AUTO_TEST_CASE(dev_return) +{ + char const* sourceCode = "contract test {\n" + " /// @dev Multiplies a number by 7 and adds second parameter\n" + " /// @param a Documentation for the first parameter starts here.\n" + " /// Since it's a really complicated parameter we need 2 lines\n" + " /// @param second Documentation for the second parameter\n" + " /// @return The result of the multiplication\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul\":{ \n" + " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" + " \"params\": {\n" + " \"a\": \"Documentation for the first parameter starts here.Since it's a really complicated parameter we need 2 lines\",\n" + " \"second\": \"Documentation for the second parameter\"\n" + " },\n" + " \"return\": \"The result of the multiplication\"\n" + " }\n" + "}}"; + + checkNatspec(sourceCode, natspec, false); +} + +BOOST_AUTO_TEST_CASE(dev_multiline_return) +{ + char const* sourceCode = "contract test {\n" + " /// @dev Multiplies a number by 7 and adds second parameter\n" + " /// @param a Documentation for the first parameter starts here.\n" + " /// Since it's a really complicated parameter we need 2 lines\n" + " /// @param second Documentation for the second parameter\n" + " /// @return The result of the multiplication\n" + " /// and cookies with nutella\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul\":{ \n" + " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" + " \"params\": {\n" + " \"a\": \"Documentation for the first parameter starts here.Since it's a really complicated parameter we need 2 lines\",\n" + " \"second\": \"Documentation for the second parameter\"\n" + " },\n" + " \"return\": \"The result of the multiplication and cookies with nutella\"\n" + " }\n" + "}}"; + + checkNatspec(sourceCode, natspec, false); +} + BOOST_AUTO_TEST_SUITE_END() } From 67da8798cf29b428d06905616b8ef42b1b624a45 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 4 Dec 2014 23:55:47 +0100 Subject: [PATCH 25/33] Addressing styling and miscellaneous issue with Natspec --- libsolidity/CompilerStack.cpp | 20 ++++++------- libsolidity/CompilerStack.h | 4 +-- libsolidity/InterfaceHandler.cpp | 49 ++++++++++++++------------------ libsolidity/InterfaceHandler.h | 18 ++++++------ 4 files changed, 43 insertions(+), 48 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 3e9791bd2..3281442fa 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -36,7 +36,7 @@ namespace dev namespace solidity { -CompilerStack::CompilerStack():m_interfaceHandler(make_shared()){} +CompilerStack::CompilerStack(): m_interfaceHandler(make_shared()) {} void CompilerStack::setSource(string const& _sourceCode) { @@ -84,33 +84,31 @@ void CompilerStack::streamAssembly(ostream& _outStream) m_compiler->streamAssembly(_outStream); } -std::string const* CompilerStack::getJsonDocumentation(enum documentationType _type) +std::string const* CompilerStack::getJsonDocumentation(enum DocumentationType _type) { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - auto createOrReturnDoc = [this, _type](std::unique_ptr& _doc) + auto createDocIfNotThere = [this, _type](std::unique_ptr& _doc) { - if(!_doc) - { + if (!_doc) _doc = m_interfaceHandler->getDocumentation(m_contractASTNode, _type); - } }; switch (_type) { case NATSPEC_USER: - createOrReturnDoc(m_userDocumentation); + createDocIfNotThere(m_userDocumentation); return m_userDocumentation.get(); case NATSPEC_DEV: - createOrReturnDoc(m_devDocumentation); + createDocIfNotThere(m_devDocumentation); return m_devDocumentation.get(); case ABI_INTERFACE: - createOrReturnDoc(m_interface); + createDocIfNotThere(m_interface); return m_interface.get(); } - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal error")); - return nullptr; + + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type.")); } bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize) diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 511951291..de356b1ae 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -37,7 +37,7 @@ class Compiler; class GlobalContext; class InterfaceHandler; -enum documentationType: unsigned short +enum DocumentationType: unsigned short { NATSPEC_USER = 1, NATSPEC_DEV, @@ -74,7 +74,7 @@ public: /// Prerequisite: Successful call to parse or compile. /// @param type The type of the documentation to get. /// Can be one of 3 types defined at @c documentation_type - std::string const* getJsonDocumentation(enum documentationType type); + std::string const* getJsonDocumentation(enum DocumentationType type); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 2a6de2c35..53632bc6f 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -3,8 +3,10 @@ #include #include -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ /* -- public -- */ @@ -14,7 +16,7 @@ InterfaceHandler::InterfaceHandler() } std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr _contractDef, - enum documentationType _type) + enum DocumentationType _type) { switch(_type) { @@ -34,8 +36,7 @@ std::unique_ptr InterfaceHandler::getABIInterface(std::shared_ptr exportedFunctions = _contractDef->getInterfaceFunctions(); - for (FunctionDefinition const* f: exportedFunctions) + for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions()) { Json::Value method; Json::Value inputs(Json::arrayValue); @@ -107,9 +108,8 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(std::shared_p method["details"] = Json::Value(m_dev); Json::Value params(Json::objectValue); for (auto const& pair: m_params) - { params[pair.first] = pair.second; - } + if (!m_params.empty()) method["params"] = params; if (!m_return.empty()) @@ -145,12 +145,12 @@ size_t skipLineOrEOS(std::string const& _string, size_t _nlPos) size_t InterfaceHandler::parseDocTagLine(std::string const& _string, std::string& _tagString, size_t _pos, - enum docTagType _tagType) + enum DocTagType _tagType) { - size_t nlPos = _string.find("\n", _pos); + size_t nlPos = _string.find('\n', _pos); _tagString += _string.substr(_pos, nlPos == std::string::npos ? - _string.length() : + _string.length() - _pos: nlPos - _pos); m_lastTag = _tagType; return skipLineOrEOS(_string, nlPos); @@ -159,20 +159,18 @@ size_t InterfaceHandler::parseDocTagLine(std::string const& _string, size_t InterfaceHandler::parseDocTagParam(std::string const& _string, size_t _startPos) { // find param name - size_t currPos = _string.find(" ", _startPos); + size_t currPos = _string.find(' ', _startPos); if (currPos == std::string::npos) - { BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of param name not found")); - return currPos; //no end of tag found - } + auto paramName = _string.substr(_startPos, currPos - _startPos); currPos += 1; - size_t nlPos = _string.find("\n", currPos); + size_t nlPos = _string.find('\n', currPos); auto paramDesc = _string.substr(currPos, nlPos == std::string::npos ? - _string.length() : + _string.length() - currPos : nlPos - currPos); m_params.push_back(std::make_pair(paramName, paramDesc)); @@ -184,13 +182,13 @@ size_t InterfaceHandler::parseDocTagParam(std::string const& _string, size_t _st size_t InterfaceHandler::appendDocTagParam(std::string const& _string, size_t _startPos) { // Should never be called with an empty vector - assert(!m_params.empty()); - + if (asserts(!m_params.empty())) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal: Tried to append to empty parameter")); auto pair = m_params.back(); - size_t nlPos = _string.find("\n", _startPos); + size_t nlPos = _string.find('\n', _startPos); pair.second += _string.substr(_startPos, nlPos == std::string::npos ? - _string.length() : + _string.length() - _startPos : nlPos - _startPos); m_params.at(m_params.size() - 1) = pair; @@ -227,7 +225,7 @@ size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string con size_t InterfaceHandler::appendDocTag(std::string const& _string, size_t _startPos) { size_t newPos = _startPos; - switch(m_lastTag) + switch (m_lastTag) { case DOCTAG_DEV: m_dev += " "; @@ -254,18 +252,15 @@ void InterfaceHandler::parseDocString(std::string const& _string, size_t _startP { size_t pos2; size_t newPos = _startPos; - size_t tagPos = _string.find("@", _startPos); - size_t nlPos = _string.find("\n", _startPos); + size_t tagPos = _string.find('@', _startPos); + size_t nlPos = _string.find('\n', _startPos); if (tagPos != std::string::npos && tagPos < nlPos) { // we found a tag - pos2 = _string.find(" ", tagPos); + pos2 = _string.find(' ', tagPos); if (pos2 == std::string::npos) - { BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); - return; //no end of tag found - } newPos = parseDocTag(_string, _string.substr(tagPos + 1, pos2 - tagPos - 1), pos2 + 1); } diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index eeaed033d..e9e3a83c8 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -30,14 +30,16 @@ #include #include -namespace dev { -namespace solidity { +namespace dev +{ +namespace solidity +{ // Forward declarations class ContractDefinition; -enum documentationType: unsigned short; +enum DocumentationType: unsigned short; -enum docTagType +enum DocTagType { DOCTAG_NONE = 0, DOCTAG_DEV, @@ -54,11 +56,11 @@ public: /// Get the given type of documentation /// @param _contractDef The contract definition /// @param _type The type of the documentation. Can be one of the - /// types provided by @c documentation_type + /// types provided by @c DocumentationType /// @return A unique pointer contained string with the json /// representation of provided type std::unique_ptr getDocumentation(std::shared_ptr _contractDef, - enum documentationType _type); + enum DocumentationType _type); /// Get the ABI Interface of the contract /// @param _contractDef The contract definition /// @return A unique pointer contained string with the json @@ -79,7 +81,7 @@ private: void resetUser(); void resetDev(); - size_t parseDocTagLine(std::string const& _string, std::string& _tagString, size_t _pos, enum docTagType _tagType); + size_t parseDocTagLine(std::string const& _string, std::string& _tagString, size_t _pos, enum DocTagType _tagType); size_t parseDocTagParam(std::string const& _string, size_t _startPos); size_t appendDocTagParam(std::string const& _string, size_t _startPos); void parseDocString(std::string const& _string, size_t _startPos = 0); @@ -89,7 +91,7 @@ private: Json::StyledWriter m_writer; // internal state - enum docTagType m_lastTag; + enum DocTagType m_lastTag; std::string m_notice; std::string m_dev; std::string m_return; From 4bbb9eb264f3e9cb9a3947c6eed3a60b0645f281 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 5 Dec 2014 02:10:54 +0100 Subject: [PATCH 26/33] Using iterators in Natspec comment parsing - Used iterators in the entirety of the InterfaceHandler natspec comment parsing pipeline - Fixed issue where @param continuing in new line would not get a space --- libsolidity/InterfaceHandler.cpp | 138 +++++++++++++++---------------- libsolidity/InterfaceHandler.h | 20 +++-- test/solidityNatspecJSON.cpp | 6 +- 3 files changed, 82 insertions(+), 82 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 53632bc6f..1450d8fc3 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -137,143 +137,135 @@ void InterfaceHandler::resetDev() m_params.clear(); } -size_t skipLineOrEOS(std::string const& _string, size_t _nlPos) +std::string::const_iterator skipLineOrEOS(std::string::const_iterator _nlPos, + std::string::const_iterator _end) { - return (_nlPos == std::string::npos) ? _string.length() : _nlPos + 1; + return (_nlPos == _end) ? _end : ++_nlPos; } -size_t InterfaceHandler::parseDocTagLine(std::string const& _string, - std::string& _tagString, - size_t _pos, - enum DocTagType _tagType) +std::string::const_iterator InterfaceHandler::parseDocTagLine(std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string& _tagString, + enum DocTagType _tagType) { - size_t nlPos = _string.find('\n', _pos); - _tagString += _string.substr(_pos, - nlPos == std::string::npos ? - _string.length() - _pos: - nlPos - _pos); + auto nlPos = std::find(_pos, _end, '\n'); + std::copy(_pos, nlPos, back_inserter(_tagString)); m_lastTag = _tagType; - return skipLineOrEOS(_string, nlPos); + return skipLineOrEOS(nlPos, _end); } -size_t InterfaceHandler::parseDocTagParam(std::string const& _string, size_t _startPos) +std::string::const_iterator InterfaceHandler::parseDocTagParam(std::string::const_iterator _pos, + std::string::const_iterator _end) { // find param name - size_t currPos = _string.find(' ', _startPos); - if (currPos == std::string::npos) + auto currPos = std::find(_pos, _end, ' '); + if (currPos == _end) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of param name not found")); - auto paramName = _string.substr(_startPos, currPos - _startPos); + auto paramName = std::string(_pos, currPos); currPos += 1; - size_t nlPos = _string.find('\n', currPos); - auto paramDesc = _string.substr(currPos, - nlPos == std::string::npos ? - _string.length() - currPos : - nlPos - currPos); - + auto nlPos = std::find(currPos, _end, '\n'); + auto paramDesc = std::string(currPos, nlPos); m_params.push_back(std::make_pair(paramName, paramDesc)); m_lastTag = DOCTAG_PARAM; - return skipLineOrEOS(_string, nlPos); + return skipLineOrEOS(nlPos, _end); } -size_t InterfaceHandler::appendDocTagParam(std::string const& _string, size_t _startPos) +std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::const_iterator _pos, + std::string::const_iterator _end) { // Should never be called with an empty vector if (asserts(!m_params.empty())) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal: Tried to append to empty parameter")); + auto pair = m_params.back(); - size_t nlPos = _string.find('\n', _startPos); - pair.second += _string.substr(_startPos, - nlPos == std::string::npos ? - _string.length() - _startPos : - nlPos - _startPos); + pair.second += " "; + auto nlPos = std::find(_pos, _end, '\n'); + std::copy(_pos, nlPos, back_inserter(pair.second)); m_params.at(m_params.size() - 1) = pair; - return skipLineOrEOS(_string, nlPos); + return skipLineOrEOS(nlPos, _end); } -size_t InterfaceHandler::parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos) +std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string const& _tag) { // LTODO: need to check for @(start of a tag) between here and the end of line // for all cases - size_t nlPos = _pos; if (m_lastTag == DOCTAG_NONE || _tag != "") { if (_tag == "dev") - nlPos = parseDocTagLine(_string, m_dev, _pos, DOCTAG_DEV); + return parseDocTagLine(_pos, _end, m_dev, DOCTAG_DEV); else if (_tag == "notice") - nlPos = parseDocTagLine(_string, m_notice, _pos, DOCTAG_NOTICE); + return parseDocTagLine(_pos, _end, m_notice, DOCTAG_NOTICE); else if (_tag == "return") - nlPos = parseDocTagLine(_string, m_return, _pos, DOCTAG_RETURN); + return parseDocTagLine(_pos, _end, m_return, DOCTAG_RETURN); else if (_tag == "param") - nlPos = parseDocTagParam(_string, _pos); + return parseDocTagParam(_pos, _end); else { - // LTODO: Unknown tas, throw some form of warning + // LTODO: Unknown tag, throw some form of warning and not just an exception + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Unknown tag encountered")); } } else - appendDocTag(_string, _pos); - - return nlPos; + return appendDocTag(_pos, _end); } -size_t InterfaceHandler::appendDocTag(std::string const& _string, size_t _startPos) +std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_iterator _pos, + std::string::const_iterator _end) { - size_t newPos = _startPos; switch (m_lastTag) { case DOCTAG_DEV: m_dev += " "; - newPos = parseDocTagLine(_string, m_dev, _startPos, DOCTAG_DEV); - break; + return parseDocTagLine(_pos, _end, m_dev, DOCTAG_DEV); case DOCTAG_NOTICE: m_notice += " "; - newPos = parseDocTagLine(_string, m_notice, _startPos, DOCTAG_NOTICE); - break; + return parseDocTagLine(_pos, _end, m_notice, DOCTAG_NOTICE); case DOCTAG_RETURN: m_return += " "; - newPos = parseDocTagLine(_string, m_return, _startPos, DOCTAG_RETURN); - break; + return parseDocTagLine(_pos, _end, m_return, DOCTAG_RETURN); case DOCTAG_PARAM: - newPos = appendDocTagParam(_string, _startPos); - break; + return appendDocTagParam(_pos, _end); default: + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal: Illegal documentation tag")); break; - } - return newPos; + } } -void InterfaceHandler::parseDocString(std::string const& _string, size_t _startPos) +void InterfaceHandler::parseDocString(std::string const& _string) { - size_t pos2; - size_t newPos = _startPos; - size_t tagPos = _string.find('@', _startPos); - size_t nlPos = _string.find('\n', _startPos); + auto currPos = _string.begin(); + auto end = _string.end(); - if (tagPos != std::string::npos && tagPos < nlPos) + while (currPos != end) { - // we found a tag - pos2 = _string.find(' ', tagPos); - if (pos2 == std::string::npos) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); + auto tagPos = std::find(currPos, end, '@'); + auto nlPos = std::find(currPos, end, '\n'); - newPos = parseDocTag(_string, _string.substr(tagPos + 1, pos2 - tagPos - 1), pos2 + 1); - } - else if (m_lastTag != DOCTAG_NONE) // continuation of the previous tag - newPos = appendDocTag(_string, _startPos + 1); - else // skip the line if a newline was found - { - if (newPos != std::string::npos) - newPos = nlPos + 1; + if (tagPos != end && tagPos < nlPos) + { + // we found a tag + auto tagNameEndPos = std::find(tagPos, end, ' '); + if (tagNameEndPos == end) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); + + currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos +1, tagNameEndPos)); + } + else if (m_lastTag != DOCTAG_NONE) // continuation of the previous tag + currPos = appendDocTag(currPos + 1, end); + else // skip the line if a newline was found + { + if (currPos != end) + currPos = nlPos + 1; + } } - if (newPos == std::string::npos || newPos == _string.length()) - return; // EOS - parseDocString(_string, newPos); } } //solidity NS diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index e9e3a83c8..7a5ee66db 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -81,12 +81,20 @@ private: void resetUser(); void resetDev(); - size_t parseDocTagLine(std::string const& _string, std::string& _tagString, size_t _pos, enum DocTagType _tagType); - size_t parseDocTagParam(std::string const& _string, size_t _startPos); - size_t appendDocTagParam(std::string const& _string, size_t _startPos); - void parseDocString(std::string const& _string, size_t _startPos = 0); - size_t appendDocTag(std::string const& _string, size_t _startPos); - size_t parseDocTag(std::string const& _string, std::string const& _tag, size_t _pos); + std::string::const_iterator parseDocTagLine(std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string& _tagString, + enum DocTagType _tagType); + std::string::const_iterator parseDocTagParam(std::string::const_iterator _pos, + std::string::const_iterator _end); + std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos, + std::string::const_iterator _end); + void parseDocString(std::string const& _string); + std::string::const_iterator appendDocTag(std::string::const_iterator _pos, + std::string::const_iterator _end); + std::string::const_iterator parseDocTag(std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string const& _tag); Json::StyledWriter m_writer; diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index 2c4be219b..f2ae15c96 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -230,7 +230,7 @@ BOOST_AUTO_TEST_CASE(dev_mutiline_param_description) " \"mul\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" - " \"a\": \"Documentation for the first parameter starts here.Since it's a really complicated parameter we need 2 lines\",\n" + " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" " \"second\": \"Documentation for the second parameter\"\n" " }\n" " }\n" @@ -305,7 +305,7 @@ BOOST_AUTO_TEST_CASE(dev_return) " \"mul\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" - " \"a\": \"Documentation for the first parameter starts here.Since it's a really complicated parameter we need 2 lines\",\n" + " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" " \"second\": \"Documentation for the second parameter\"\n" " },\n" " \"return\": \"The result of the multiplication\"\n" @@ -332,7 +332,7 @@ BOOST_AUTO_TEST_CASE(dev_multiline_return) " \"mul\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" - " \"a\": \"Documentation for the first parameter starts here.Since it's a really complicated parameter we need 2 lines\",\n" + " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" " \"second\": \"Documentation for the second parameter\"\n" " },\n" " \"return\": \"The result of the multiplication and cookies with nutella\"\n" From c96e1d0c36c7b1a627a3b99591fc0e40ddc39bf5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 5 Dec 2014 09:37:10 +0100 Subject: [PATCH 27/33] Logs from subcalls are folded in. --- libevm/ExtVMFace.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 9e6601d0a..7f7ae7a50 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -88,6 +88,7 @@ struct SubState { suicides += _s.suicides; refunds += _s.refunds; + logs += _s.logs; return *this; } }; From 4cf9f82bc7344207555f4e9f52a4352ba5b6424d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 5 Dec 2014 09:43:29 +0100 Subject: [PATCH 28/33] Windows fix & used code removed --- libevm/ExtVMFace.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 7f7ae7a50..4a175ff4e 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -36,20 +36,12 @@ namespace dev namespace eth { -template inline std::set toSet(std::vector const& _ts) -{ - std::set ret; - for (auto const& t: _ts) - ret.insert(t); - return ret; -} - using LogBloom = h512; struct LogEntry { LogEntry() {} - LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256s)_r[1]; data = _r[2].toBytes(); } + LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = _r[1].toVector(); data = _r[2].toBytes(); } LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(_ts), data(std::move(_d)) {} void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; } From 45499094ef6fb2822da6494cc898c49f90eacbd0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 5 Dec 2014 09:52:34 +0100 Subject: [PATCH 29/33] PV48. --- libethcore/CommonEth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index e68839ed5..5f9332ad8 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -33,7 +33,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 47; +const unsigned c_protocolVersion = 48; const unsigned c_databaseVersion = 5; static const vector> g_units = From 7de687fece7631adca5a78f27d0222c5f911caed Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 5 Dec 2014 10:47:05 +0100 Subject: [PATCH 30/33] Block-level receipts dump. --- alethzero/MainWin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4a32f66b2..2a66a6d69 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1285,6 +1285,7 @@ void Main::on_blocks_currentItemChanged() s << "
" << sha3(i.data()).abridged();// << ": " << i[1].toHash() << " [" << i[2].toInt() << " used]"; s << "
Post: " << info.stateRoot << ""; s << "
Dump: " << toHex(block[0].data()) << ""; + s << "
Receipts-Hex: " << toHex(ethereum()->blockChain().receipts(h).rlp()) << "
"; } else { From cfb8e74a75acac98042a0aef2d26ccfaf6749647 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 5 Dec 2014 12:08:26 +0100 Subject: [PATCH 31/33] Introducing Docstring parsing error exception and style fixes --- libsolidity/Exceptions.h | 1 + libsolidity/InterfaceHandler.cpp | 22 ++++++++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index 1903c1dc2..8298c9810 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -36,6 +36,7 @@ struct TypeError: virtual Exception {}; struct DeclarationError: virtual Exception {}; struct CompilerError: virtual Exception {}; struct InternalCompilerError: virtual Exception {}; +struct DocstringParsingError: virtual Exception {}; typedef boost::error_info errinfo_sourcePosition; typedef boost::error_info errinfo_sourceLocation; diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 1450d8fc3..ca02cc37d 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -28,7 +28,7 @@ std::unique_ptr InterfaceHandler::getDocumentation(std::shared_ptr< return getABIInterface(_contractDef); } - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal error")); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type")); return nullptr; } @@ -160,7 +160,7 @@ std::string::const_iterator InterfaceHandler::parseDocTagParam(std::string::cons // find param name auto currPos = std::find(_pos, _end, ' '); if (currPos == _end) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of param name not found")); + BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of param name not found" + std::string(_pos, _end))); auto paramName = std::string(_pos, currPos); @@ -179,7 +179,7 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con { // Should never be called with an empty vector if (asserts(!m_params.empty())) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal: Tried to append to empty parameter")); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Tried to append to empty parameter")); auto pair = m_params.back(); pair.second += " "; @@ -210,7 +210,7 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite else { // LTODO: Unknown tag, throw some form of warning and not just an exception - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Unknown tag encountered")); + BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("Unknown tag " + _tag + " encountered")); } } else @@ -234,7 +234,7 @@ std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_it case DOCTAG_PARAM: return appendDocTagParam(_pos, _end); default: - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Internal: Illegal documentation tag")); + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type")); break; } } @@ -254,17 +254,15 @@ void InterfaceHandler::parseDocString(std::string const& _string) // we found a tag auto tagNameEndPos = std::find(tagPos, end, ' '); if (tagNameEndPos == end) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("End of tag not found")); + BOOST_THROW_EXCEPTION(DocstringParsingError() << + errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found")); - currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos +1, tagNameEndPos)); + currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos)); } else if (m_lastTag != DOCTAG_NONE) // continuation of the previous tag currPos = appendDocTag(currPos + 1, end); - else // skip the line if a newline was found - { - if (currPos != end) - currPos = nlPos + 1; - } + else if (currPos != end) // skip the line if a newline was found + currPos = nlPos + 1; } } From 9977229d759448bf0a6c89a4451bae8852ed02c1 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 5 Dec 2014 12:27:18 +0100 Subject: [PATCH 32/33] Newline right after doctag is now a valid natspec entry - Plus tests for that --- libsolidity/InterfaceHandler.cpp | 14 +++++++-- test/solidityNatspecJSON.cpp | 51 ++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index ca02cc37d..0115c7f59 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -137,8 +137,8 @@ void InterfaceHandler::resetDev() m_params.clear(); } -std::string::const_iterator skipLineOrEOS(std::string::const_iterator _nlPos, - std::string::const_iterator _end) +static inline std::string::const_iterator skipLineOrEOS(std::string::const_iterator _nlPos, + std::string::const_iterator _end) { return (_nlPos == _end) ? _end : ++_nlPos; } @@ -239,6 +239,14 @@ std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_it } } +static inline std::string::const_iterator getFirstSpaceOrNl(std::string::const_iterator _pos, + std::string::const_iterator _end) +{ + auto spacePos = std::find(_pos, _end, ' '); + auto nlPos = std::find(_pos, _end, '\n'); + return (spacePos < nlPos) ? spacePos : nlPos; +} + void InterfaceHandler::parseDocString(std::string const& _string) { auto currPos = _string.begin(); @@ -252,7 +260,7 @@ void InterfaceHandler::parseDocString(std::string const& _string) if (tagPos != end && tagPos < nlPos) { // we found a tag - auto tagNameEndPos = std::find(tagPos, end, ' '); + auto tagNameEndPos = getFirstSpaceOrNl(tagPos, end); if (tagNameEndPos == end) BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found")); diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index f2ae15c96..9596f2b80 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -192,6 +192,30 @@ BOOST_AUTO_TEST_CASE(dev_and_user_no_doc) checkNatspec(sourceCode, userNatspec, true); } +BOOST_AUTO_TEST_CASE(dev_desc_after_nl) +{ + char const* sourceCode = "contract test {\n" + " /// @dev\n" + " /// Multiplies a number by 7 and adds second parameter\n" + " /// @param a Documentation for the first parameter\n" + " /// @param second Documentation for the second parameter\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul\":{ \n" + " \"details\": \" Multiplies a number by 7 and adds second parameter\",\n" + " \"params\": {\n" + " \"a\": \"Documentation for the first parameter\",\n" + " \"second\": \"Documentation for the second parameter\"\n" + " }\n" + " }\n" + "}}"; + + checkNatspec(sourceCode, natspec, false); +} + BOOST_AUTO_TEST_CASE(dev_multiple_params) { char const* sourceCode = "contract test {\n" @@ -314,6 +338,33 @@ BOOST_AUTO_TEST_CASE(dev_return) checkNatspec(sourceCode, natspec, false); } +BOOST_AUTO_TEST_CASE(dev_return_desc_after_nl) +{ + char const* sourceCode = "contract test {\n" + " /// @dev Multiplies a number by 7 and adds second parameter\n" + " /// @param a Documentation for the first parameter starts here.\n" + " /// Since it's a really complicated parameter we need 2 lines\n" + " /// @param second Documentation for the second parameter\n" + " /// @return\n" + " /// The result of the multiplication\n" + " function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n" + "}\n"; + + char const* natspec = "{" + "\"methods\":{" + " \"mul\":{ \n" + " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" + " \"params\": {\n" + " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" + " \"second\": \"Documentation for the second parameter\"\n" + " },\n" + " \"return\": \" The result of the multiplication\"\n" + " }\n" + "}}"; + + checkNatspec(sourceCode, natspec, false); +} + BOOST_AUTO_TEST_CASE(dev_multiline_return) { From 78938ac468c4eddedd0c8c66a12094668e224668 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 5 Dec 2014 12:41:32 +0100 Subject: [PATCH 33/33] Stack compiler now correctly returns a string and not a pointer --- libsolidity/CompilerStack.cpp | 8 ++++---- libsolidity/CompilerStack.h | 2 +- test/solidityJSONInterfaceTest.cpp | 2 +- test/solidityNatspecJSON.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 3281442fa..c83257a1d 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -84,7 +84,7 @@ void CompilerStack::streamAssembly(ostream& _outStream) m_compiler->streamAssembly(_outStream); } -std::string const* CompilerStack::getJsonDocumentation(enum DocumentationType _type) +std::string const& CompilerStack::getJsonDocumentation(enum DocumentationType _type) { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); @@ -99,13 +99,13 @@ std::string const* CompilerStack::getJsonDocumentation(enum DocumentationType _t { case NATSPEC_USER: createDocIfNotThere(m_userDocumentation); - return m_userDocumentation.get(); + return *m_userDocumentation; case NATSPEC_DEV: createDocIfNotThere(m_devDocumentation); - return m_devDocumentation.get(); + return *m_devDocumentation; case ABI_INTERFACE: createDocIfNotThere(m_interface); - return m_interface.get(); + return *m_interface; } BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type.")); diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index de356b1ae..8dc546fbe 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -74,7 +74,7 @@ public: /// Prerequisite: Successful call to parse or compile. /// @param type The type of the documentation to get. /// Can be one of 3 types defined at @c documentation_type - std::string const* getJsonDocumentation(enum DocumentationType type); + std::string const& getJsonDocumentation(enum DocumentationType type); /// Returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner() const { return *m_scanner; } diff --git a/test/solidityJSONInterfaceTest.cpp b/test/solidityJSONInterfaceTest.cpp index 8fe0ea653..407f05d03 100644 --- a/test/solidityJSONInterfaceTest.cpp +++ b/test/solidityJSONInterfaceTest.cpp @@ -50,7 +50,7 @@ public: msg += *extra; BOOST_FAIL(msg); } - std::string generatedInterfaceString = *m_compilerStack.getJsonDocumentation(ABI_INTERFACE); + std::string generatedInterfaceString = m_compilerStack.getJsonDocumentation(ABI_INTERFACE); Json::Value generatedInterface; m_reader.parse(generatedInterfaceString, generatedInterface); Json::Value expectedInterface; diff --git a/test/solidityNatspecJSON.cpp b/test/solidityNatspecJSON.cpp index 9596f2b80..2ccedf7a2 100644 --- a/test/solidityNatspecJSON.cpp +++ b/test/solidityNatspecJSON.cpp @@ -55,9 +55,9 @@ public: } if (_userDocumentation) - generatedDocumentationString = *m_compilerStack.getJsonDocumentation(NATSPEC_USER); + generatedDocumentationString = m_compilerStack.getJsonDocumentation(NATSPEC_USER); else - generatedDocumentationString = *m_compilerStack.getJsonDocumentation(NATSPEC_DEV); + generatedDocumentationString = m_compilerStack.getJsonDocumentation(NATSPEC_DEV); Json::Value generatedDocumentation; m_reader.parse(generatedDocumentationString, generatedDocumentation); Json::Value expectedDocumentation;