diff options
-rw-r--r-- | Changelog.md | 1 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.cpp | 16 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.h | 2 | ||||
-rw-r--r-- | test/libsolidity/ASTJSON.cpp | 226 | ||||
-rw-r--r-- | test/libsolidity/ASTLegacyJSON.cpp | 324 |
5 files changed, 368 insertions, 201 deletions
diff --git a/Changelog.md b/Changelog.md index f56a746e..80f02a2d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -32,6 +32,7 @@ Bugfixes: * Commandline interface: Support ``--evm-version constantinople`` properly. * DocString Parser: Fix error message for empty descriptions. * Gas Estimator: Correctly ignore costs of fallback function for other functions. + * JSON AST: Remove storage qualifier for type name strings. * Parser: Fix internal compiler error when parsing ``var`` declaration without identifier. * Parser: Fix parsing of getters for function type variables. * Standard JSON: Support ``constantinople`` as ``evmVersion`` properly. diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 95ba3089..b8e00b60 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -134,10 +134,10 @@ string ASTJsonConverter::namePathToString(std::vector<ASTString> const& _namePat return boost::algorithm::join(_namePath, "."); } -Json::Value ASTJsonConverter::typePointerToJson(TypePointer _tp) +Json::Value ASTJsonConverter::typePointerToJson(TypePointer _tp, bool _short) { Json::Value typeDescriptions(Json::objectValue); - typeDescriptions["typeString"] = _tp ? Json::Value(_tp->toString()) : Json::nullValue; + typeDescriptions["typeString"] = _tp ? Json::Value(_tp->toString(_short)) : Json::nullValue; typeDescriptions["typeIdentifier"] = _tp ? Json::Value(_tp->identifier()) : Json::nullValue; return typeDescriptions; @@ -354,7 +354,7 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node) make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue), make_pair("scope", idOrNull(_node.scope())), - make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) }; if (m_inEvent) attributes.push_back(make_pair("indexed", _node.isIndexed())); @@ -399,7 +399,7 @@ bool ASTJsonConverter::visit(ElementaryTypeName const& _node) { setJsonNode(_node, "ElementaryTypeName", { make_pair("name", _node.typeName().toString()), - make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) }); return false; } @@ -410,7 +410,7 @@ bool ASTJsonConverter::visit(UserDefinedTypeName const& _node) make_pair("name", namePathToString(_node.namePath())), make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), make_pair("contractScope", idOrNull(_node.annotation().contractScope)), - make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) }); return false; } @@ -425,7 +425,7 @@ bool ASTJsonConverter::visit(FunctionTypeName const& _node) make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.stateMutability() <= StateMutability::View), make_pair("parameterTypes", toJson(*_node.parameterTypeList())), make_pair("returnParameterTypes", toJson(*_node.returnParameterTypeList())), - make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) }); return false; } @@ -435,7 +435,7 @@ bool ASTJsonConverter::visit(Mapping const& _node) setJsonNode(_node, "Mapping", { make_pair("keyType", toJson(_node.keyType())), make_pair("valueType", toJson(_node.valueType())), - make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) }); return false; } @@ -445,7 +445,7 @@ bool ASTJsonConverter::visit(ArrayTypeName const& _node) setJsonNode(_node, "ArrayTypeName", { make_pair("baseType", toJson(_node.baseType())), make_pair("length", toJsonOrNull(_node.length())), - make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) }); return false; } diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index 88b93699..29712f3b 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -152,7 +152,7 @@ private: } return tmp; } - static Json::Value typePointerToJson(TypePointer _tp); + static Json::Value typePointerToJson(TypePointer _tp, bool _short = false); static Json::Value typePointerToJson(std::shared_ptr<std::vector<TypePointer>> _tps); void appendExpressionAttributes( std::vector<std::pair<std::string, Json::Value>> &_attributes, diff --git a/test/libsolidity/ASTJSON.cpp b/test/libsolidity/ASTJSON.cpp index b44dd331..5d5b14e8 100644 --- a/test/libsolidity/ASTJSON.cpp +++ b/test/libsolidity/ASTJSON.cpp @@ -41,207 +41,62 @@ namespace test BOOST_AUTO_TEST_SUITE(SolidityASTJSON) -BOOST_AUTO_TEST_CASE(smoke_test) +BOOST_AUTO_TEST_CASE(short_type_name) { CompilerStack c; - c.addSource("a", "contract C {}"); + c.addSource("a", "contract c { function f() { uint[] memory x; } }"); c.setEVMVersion(dev::test::Options::get().evmVersion()); c.parseAndAnalyze(); map<string, unsigned> sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - BOOST_CHECK_EQUAL(astJson["name"], "SourceUnit"); + Json::Value astJson = ASTJsonConverter(false, sourceIndices).toJson(c.ast("a")); + Json::Value varDecl = astJson["nodes"][0]["nodes"][0]["body"]["statements"][0]["declarations"][0]; + BOOST_CHECK_EQUAL(varDecl["storageLocation"], "memory"); + BOOST_CHECK_EQUAL(varDecl["typeDescriptions"]["typeIdentifier"], "t_array$_t_uint256_$dyn_memory_ptr"); + BOOST_CHECK_EQUAL(varDecl["typeDescriptions"]["typeString"], "uint256[]"); } -BOOST_AUTO_TEST_CASE(source_location) +BOOST_AUTO_TEST_CASE(short_type_name_ref) { CompilerStack c; - c.addSource("a", "contract C { function f() { var x = 2; x++; } }"); + c.addSource("a", "contract c { function f() { uint[][] memory rows; } }"); c.setEVMVersion(dev::test::Options::get().evmVersion()); c.parseAndAnalyze(); map<string, unsigned> sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - BOOST_CHECK_EQUAL(astJson["name"], "SourceUnit"); - BOOST_CHECK_EQUAL(astJson["children"][0]["name"], "ContractDefinition"); - BOOST_CHECK_EQUAL(astJson["children"][0]["children"][0]["name"], "FunctionDefinition"); - BOOST_CHECK_EQUAL(astJson["children"][0]["children"][0]["src"], "13:32:1"); + Json::Value astJson = ASTJsonConverter(false, sourceIndices).toJson(c.ast("a")); + Json::Value varDecl = astJson["nodes"][0]["nodes"][0]["body"]["statements"][0]["declarations"][0]; + BOOST_CHECK_EQUAL(varDecl["storageLocation"], "memory"); + BOOST_CHECK_EQUAL(varDecl["typeName"]["typeDescriptions"]["typeIdentifier"], "t_array$_t_array$_t_uint256_$dyn_storage_$dyn_storage_ptr"); + BOOST_CHECK_EQUAL(varDecl["typeName"]["typeDescriptions"]["typeString"], "uint256[][]"); } -BOOST_AUTO_TEST_CASE(inheritance_specifier) +BOOST_AUTO_TEST_CASE(long_type_name_binary_operation) { CompilerStack c; - c.addSource("a", "contract C1 {} contract C2 is C1 {}"); + c.addSource("a", "contract c { function f() public { uint a = 2 + 3; } }"); c.setEVMVersion(dev::test::Options::get().evmVersion()); c.parseAndAnalyze(); map<string, unsigned> sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - BOOST_CHECK_EQUAL(astJson["children"][1]["attributes"]["name"], "C2"); - BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["name"], "InheritanceSpecifier"); - BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["src"], "30:2:1"); - BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["children"][0]["name"], "UserDefinedTypeName"); - BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["children"][0]["attributes"]["name"], "C1"); + Json::Value astJson = ASTJsonConverter(false, sourceIndices).toJson(c.ast("a")); + Json::Value varDecl = astJson["nodes"][0]["nodes"][0]["body"]["statements"][0]["initialValue"]["commonType"]; + BOOST_CHECK_EQUAL(varDecl["typeIdentifier"], "t_rational_5_by_1"); + BOOST_CHECK_EQUAL(varDecl["typeString"], "int_const 5"); } -BOOST_AUTO_TEST_CASE(using_for_directive) +BOOST_AUTO_TEST_CASE(long_type_name_identifier) { CompilerStack c; - c.addSource("a", "library L {} contract C { using L for uint; }"); + c.addSource("a", "contract c { uint[] a; function f() public { uint[] b = a; } }"); c.setEVMVersion(dev::test::Options::get().evmVersion()); c.parseAndAnalyze(); map<string, unsigned> sourceIndices; sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - Json::Value usingFor = astJson["children"][1]["children"][0]; - BOOST_CHECK_EQUAL(usingFor["name"], "UsingForDirective"); - BOOST_CHECK_EQUAL(usingFor["src"], "26:17:1"); - BOOST_CHECK_EQUAL(usingFor["children"][0]["name"], "UserDefinedTypeName"); - BOOST_CHECK_EQUAL(usingFor["children"][0]["attributes"]["name"], "L"); - BOOST_CHECK_EQUAL(usingFor["children"][1]["name"], "ElementaryTypeName"); - BOOST_CHECK_EQUAL(usingFor["children"][1]["attributes"]["name"], "uint"); -} - -BOOST_AUTO_TEST_CASE(enum_value) -{ - CompilerStack c; - c.addSource("a", "contract C { enum E { A, B } }"); - c.setEVMVersion(dev::test::Options::get().evmVersion()); - c.parseAndAnalyze(); - map<string, unsigned> sourceIndices; - sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - Json::Value enumDefinition = astJson["children"][0]["children"][0]; - BOOST_CHECK_EQUAL(enumDefinition["children"][0]["name"], "EnumValue"); - BOOST_CHECK_EQUAL(enumDefinition["children"][0]["attributes"]["name"], "A"); - BOOST_CHECK_EQUAL(enumDefinition["children"][0]["src"], "22:1:1"); - BOOST_CHECK_EQUAL(enumDefinition["children"][1]["name"], "EnumValue"); - BOOST_CHECK_EQUAL(enumDefinition["children"][1]["attributes"]["name"], "B"); - BOOST_CHECK_EQUAL(enumDefinition["children"][1]["src"], "25:1:1"); -} - -BOOST_AUTO_TEST_CASE(modifier_definition) -{ - CompilerStack c; - c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }"); - c.setEVMVersion(dev::test::Options::get().evmVersion()); - c.parseAndAnalyze(); - map<string, unsigned> sourceIndices; - sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - Json::Value modifier = astJson["children"][0]["children"][0]; - BOOST_CHECK_EQUAL(modifier["name"], "ModifierDefinition"); - BOOST_CHECK_EQUAL(modifier["attributes"]["name"], "M"); - BOOST_CHECK_EQUAL(modifier["src"], "13:25:1"); -} - -BOOST_AUTO_TEST_CASE(modifier_invocation) -{ - CompilerStack c; - c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }"); - c.setEVMVersion(dev::test::Options::get().evmVersion()); - c.parseAndAnalyze(); - map<string, unsigned> sourceIndices; - sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - Json::Value modifier = astJson["children"][0]["children"][1]["children"][2]; - BOOST_CHECK_EQUAL(modifier["name"], "ModifierInvocation"); - BOOST_CHECK_EQUAL(modifier["src"], "52:4:1"); - BOOST_CHECK_EQUAL(modifier["children"][0]["attributes"]["type"], "modifier (uint256)"); - BOOST_CHECK_EQUAL(modifier["children"][0]["attributes"]["value"], "M"); - BOOST_CHECK_EQUAL(modifier["children"][1]["attributes"]["value"], "1"); -} - -BOOST_AUTO_TEST_CASE(event_definition) -{ - CompilerStack c; - c.addSource("a", "contract C { event E(); }"); - c.setEVMVersion(dev::test::Options::get().evmVersion()); - c.parseAndAnalyze(); - map<string, unsigned> sourceIndices; - sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - Json::Value event = astJson["children"][0]["children"][0]; - BOOST_CHECK_EQUAL(event["name"], "EventDefinition"); - BOOST_CHECK_EQUAL(event["attributes"]["name"], "E"); - BOOST_CHECK_EQUAL(event["src"], "13:10:1"); -} - -BOOST_AUTO_TEST_CASE(array_type_name) -{ - CompilerStack c; - c.addSource("a", "contract C { uint[] i; }"); - c.setEVMVersion(dev::test::Options::get().evmVersion()); - c.parseAndAnalyze(); - map<string, unsigned> sourceIndices; - sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - Json::Value array = astJson["children"][0]["children"][0]["children"][0]; - BOOST_CHECK_EQUAL(array["name"], "ArrayTypeName"); - BOOST_CHECK_EQUAL(array["src"], "13:6:1"); -} - -BOOST_AUTO_TEST_CASE(placeholder_statement) -{ - CompilerStack c; - c.addSource("a", "contract C { modifier M { _; } }"); - c.setEVMVersion(dev::test::Options::get().evmVersion()); - c.parseAndAnalyze(); - map<string, unsigned> sourceIndices; - sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - Json::Value placeholder = astJson["children"][0]["children"][0]["children"][1]["children"][0]; - BOOST_CHECK_EQUAL(placeholder["name"], "PlaceholderStatement"); - BOOST_CHECK_EQUAL(placeholder["src"], "26:1:1"); -} - -BOOST_AUTO_TEST_CASE(non_utf8) -{ - CompilerStack c; - c.addSource("a", "contract C { function f() { var x = hex\"ff\"; } }"); - c.setEVMVersion(dev::test::Options::get().evmVersion()); - c.parseAndAnalyze(); - map<string, unsigned> sourceIndices; - sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - Json::Value literal = astJson["children"][0]["children"][0]["children"][2]["children"][0]["children"][1]; - BOOST_CHECK_EQUAL(literal["name"], "Literal"); - BOOST_CHECK_EQUAL(literal["attributes"]["hexvalue"], "ff"); - BOOST_CHECK_EQUAL(literal["attributes"]["token"], "string"); - BOOST_CHECK_EQUAL(literal["attributes"]["value"], Json::nullValue); - BOOST_CHECK(literal["attributes"]["type"].asString().find("invalid") != string::npos); -} - -BOOST_AUTO_TEST_CASE(function_type) -{ - CompilerStack c; - c.addSource("a", - "contract C { function f(function() external payable returns (uint) x) " - "returns (function() external constant returns (uint)) {} }" - ); - c.setEVMVersion(dev::test::Options::get().evmVersion()); - c.parseAndAnalyze(); - map<string, unsigned> sourceIndices; - sourceIndices["a"] = 1; - Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - Json::Value fun = astJson["children"][0]["children"][0]; - BOOST_CHECK_EQUAL(fun["name"], "FunctionDefinition"); - Json::Value argument = fun["children"][0]["children"][0]; - BOOST_CHECK_EQUAL(argument["name"], "VariableDeclaration"); - BOOST_CHECK_EQUAL(argument["attributes"]["name"], "x"); - BOOST_CHECK_EQUAL(argument["attributes"]["type"], "function () payable external returns (uint256)"); - Json::Value funType = argument["children"][0]; - BOOST_CHECK_EQUAL(funType["attributes"]["constant"], false); - BOOST_CHECK_EQUAL(funType["attributes"]["payable"], true); - BOOST_CHECK_EQUAL(funType["attributes"]["visibility"], "external"); - Json::Value retval = fun["children"][1]["children"][0]; - BOOST_CHECK_EQUAL(retval["name"], "VariableDeclaration"); - BOOST_CHECK_EQUAL(retval["attributes"]["name"], ""); - BOOST_CHECK_EQUAL(retval["attributes"]["type"], "function () view external returns (uint256)"); - funType = retval["children"][0]; - BOOST_CHECK_EQUAL(funType["attributes"]["constant"], true); - BOOST_CHECK_EQUAL(funType["attributes"]["payable"], false); - BOOST_CHECK_EQUAL(funType["attributes"]["visibility"], "external"); + Json::Value astJson = ASTJsonConverter(false, sourceIndices).toJson(c.ast("a")); + Json::Value varDecl = astJson["nodes"][0]["nodes"][1]["body"]["statements"][0]["initialValue"]; + BOOST_CHECK_EQUAL(varDecl["typeDescriptions"]["typeIdentifier"], "t_array$_t_uint256_$dyn_storage"); + BOOST_CHECK_EQUAL(varDecl["typeDescriptions"]["typeString"], "uint256[] storage ref"); } BOOST_AUTO_TEST_CASE(documentation) @@ -266,30 +121,17 @@ BOOST_AUTO_TEST_CASE(documentation) sourceIndices["a"] = 0; sourceIndices["b"] = 1; sourceIndices["c"] = 2; - Json::Value astJsonA = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); - Json::Value documentationA = astJsonA["children"][0]["attributes"]["documentation"]; - BOOST_CHECK_EQUAL(documentationA, "This contract is empty"); - Json::Value astJsonB = ASTJsonConverter(true, sourceIndices).toJson(c.ast("b")); - Json::Value documentationB = astJsonB["children"][0]["attributes"]["documentation"]; - BOOST_CHECK_EQUAL(documentationB, "This contract is empty and has a line-breaking comment."); - Json::Value astJsonC = ASTJsonConverter(true, sourceIndices).toJson(c.ast("c")); - Json::Value documentationC0 = astJsonC["children"][0]["children"][0]["attributes"]["documentation"]; - Json::Value documentationC1 = astJsonC["children"][0]["children"][1]["attributes"]["documentation"]; - Json::Value documentationC2 = astJsonC["children"][0]["children"][2]["attributes"]["documentation"]; - BOOST_CHECK_EQUAL(documentationC0, "Some comment on Evt."); - BOOST_CHECK_EQUAL(documentationC1, "Some comment on mod."); - BOOST_CHECK_EQUAL(documentationC2, "Some comment on fn."); //same tests for non-legacy mode - astJsonA = ASTJsonConverter(false, sourceIndices).toJson(c.ast("a")); - documentationA = astJsonA["nodes"][0]["documentation"]; + Json::Value astJsonA = ASTJsonConverter(false, sourceIndices).toJson(c.ast("a")); + Json::Value documentationA = astJsonA["nodes"][0]["documentation"]; BOOST_CHECK_EQUAL(documentationA, "This contract is empty"); - astJsonB = ASTJsonConverter(false, sourceIndices).toJson(c.ast("b")); - documentationB = astJsonB["nodes"][0]["documentation"]; + Json::Value astJsonB = ASTJsonConverter(false, sourceIndices).toJson(c.ast("b")); + Json::Value documentationB = astJsonB["nodes"][0]["documentation"]; BOOST_CHECK_EQUAL(documentationB, "This contract is empty and has a line-breaking comment."); - astJsonC = ASTJsonConverter(false, sourceIndices).toJson(c.ast("c")); - documentationC0 = astJsonC["nodes"][0]["nodes"][0]["documentation"]; - documentationC1 = astJsonC["nodes"][0]["nodes"][1]["documentation"]; - documentationC2 = astJsonC["nodes"][0]["nodes"][2]["documentation"]; + Json::Value astJsonC = ASTJsonConverter(false, sourceIndices).toJson(c.ast("c")); + Json::Value documentationC0 = astJsonC["nodes"][0]["nodes"][0]["documentation"]; + Json::Value documentationC1 = astJsonC["nodes"][0]["nodes"][1]["documentation"]; + Json::Value documentationC2 = astJsonC["nodes"][0]["nodes"][2]["documentation"]; BOOST_CHECK_EQUAL(documentationC0, "Some comment on Evt."); BOOST_CHECK_EQUAL(documentationC1, "Some comment on mod."); BOOST_CHECK_EQUAL(documentationC2, "Some comment on fn."); diff --git a/test/libsolidity/ASTLegacyJSON.cpp b/test/libsolidity/ASTLegacyJSON.cpp new file mode 100644 index 00000000..13148682 --- /dev/null +++ b/test/libsolidity/ASTLegacyJSON.cpp @@ -0,0 +1,324 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2016 + * Tests for the json ast output. + */ + +#include <test/Options.h> + +#include <libsolidity/interface/Exceptions.h> +#include <libsolidity/interface/CompilerStack.h> +#include <libsolidity/ast/ASTJsonConverter.h> + +#include <boost/test/unit_test.hpp> + +#include <string> + +using namespace std; + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +BOOST_AUTO_TEST_SUITE(SolidityASTLegacyJSON) + +BOOST_AUTO_TEST_CASE(smoke_test) +{ + CompilerStack c; + c.addSource("a", "contract C {}"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + BOOST_CHECK_EQUAL(astJson["name"], "SourceUnit"); +} + +BOOST_AUTO_TEST_CASE(source_location) +{ + CompilerStack c; + c.addSource("a", "contract C { function f() { var x = 2; x++; } }"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + BOOST_CHECK_EQUAL(astJson["name"], "SourceUnit"); + BOOST_CHECK_EQUAL(astJson["children"][0]["name"], "ContractDefinition"); + BOOST_CHECK_EQUAL(astJson["children"][0]["children"][0]["name"], "FunctionDefinition"); + BOOST_CHECK_EQUAL(astJson["children"][0]["children"][0]["src"], "13:32:1"); + +} + +BOOST_AUTO_TEST_CASE(inheritance_specifier) +{ + CompilerStack c; + c.addSource("a", "contract C1 {} contract C2 is C1 {}"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + BOOST_CHECK_EQUAL(astJson["children"][1]["attributes"]["name"], "C2"); + BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["name"], "InheritanceSpecifier"); + BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["src"], "30:2:1"); + BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["children"][0]["name"], "UserDefinedTypeName"); + BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["children"][0]["attributes"]["name"], "C1"); +} + +BOOST_AUTO_TEST_CASE(using_for_directive) +{ + CompilerStack c; + c.addSource("a", "library L {} contract C { using L for uint; }"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value usingFor = astJson["children"][1]["children"][0]; + BOOST_CHECK_EQUAL(usingFor["name"], "UsingForDirective"); + BOOST_CHECK_EQUAL(usingFor["src"], "26:17:1"); + BOOST_CHECK_EQUAL(usingFor["children"][0]["name"], "UserDefinedTypeName"); + BOOST_CHECK_EQUAL(usingFor["children"][0]["attributes"]["name"], "L"); + BOOST_CHECK_EQUAL(usingFor["children"][1]["name"], "ElementaryTypeName"); + BOOST_CHECK_EQUAL(usingFor["children"][1]["attributes"]["name"], "uint"); +} + +BOOST_AUTO_TEST_CASE(enum_value) +{ + CompilerStack c; + c.addSource("a", "contract C { enum E { A, B } }"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value enumDefinition = astJson["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(enumDefinition["children"][0]["name"], "EnumValue"); + BOOST_CHECK_EQUAL(enumDefinition["children"][0]["attributes"]["name"], "A"); + BOOST_CHECK_EQUAL(enumDefinition["children"][0]["src"], "22:1:1"); + BOOST_CHECK_EQUAL(enumDefinition["children"][1]["name"], "EnumValue"); + BOOST_CHECK_EQUAL(enumDefinition["children"][1]["attributes"]["name"], "B"); + BOOST_CHECK_EQUAL(enumDefinition["children"][1]["src"], "25:1:1"); +} + +BOOST_AUTO_TEST_CASE(modifier_definition) +{ + CompilerStack c; + c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value modifier = astJson["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(modifier["name"], "ModifierDefinition"); + BOOST_CHECK_EQUAL(modifier["attributes"]["name"], "M"); + BOOST_CHECK_EQUAL(modifier["src"], "13:25:1"); +} + +BOOST_AUTO_TEST_CASE(modifier_invocation) +{ + CompilerStack c; + c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value modifier = astJson["children"][0]["children"][1]["children"][2]; + BOOST_CHECK_EQUAL(modifier["name"], "ModifierInvocation"); + BOOST_CHECK_EQUAL(modifier["src"], "52:4:1"); + BOOST_CHECK_EQUAL(modifier["children"][0]["attributes"]["type"], "modifier (uint256)"); + BOOST_CHECK_EQUAL(modifier["children"][0]["attributes"]["value"], "M"); + BOOST_CHECK_EQUAL(modifier["children"][1]["attributes"]["value"], "1"); +} + +BOOST_AUTO_TEST_CASE(event_definition) +{ + CompilerStack c; + c.addSource("a", "contract C { event E(); }"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value event = astJson["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(event["name"], "EventDefinition"); + BOOST_CHECK_EQUAL(event["attributes"]["name"], "E"); + BOOST_CHECK_EQUAL(event["src"], "13:10:1"); +} + +BOOST_AUTO_TEST_CASE(array_type_name) +{ + CompilerStack c; + c.addSource("a", "contract C { uint[] i; }"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value arrayDecl = astJson["children"][0]["children"][0]["attributes"]; + BOOST_CHECK_EQUAL(arrayDecl["storageLocation"], "default"); + BOOST_CHECK_EQUAL(arrayDecl["type"], "uint256[]"); + Json::Value array = astJson["children"][0]["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(array["name"], "ArrayTypeName"); + BOOST_CHECK_EQUAL(array["src"], "13:6:1"); +} + +BOOST_AUTO_TEST_CASE(short_type_name) +{ + CompilerStack c; + c.addSource("a", "contract c { function f() { uint[] memory x; } }"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value arrayDecl = astJson["children"][0]["children"][0]["children"][2]["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(arrayDecl["attributes"]["storageLocation"], "memory"); + BOOST_CHECK_EQUAL(arrayDecl["attributes"]["type"], "uint256[]"); +} + +BOOST_AUTO_TEST_CASE(short_type_name_ref) +{ + CompilerStack c; + c.addSource("a", "contract c { function f() { uint[][] memory rows; } }"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value arrayDecl = astJson["children"][0]["children"][0]["children"][2]["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(arrayDecl["attributes"]["storageLocation"], "memory"); + BOOST_CHECK_EQUAL(arrayDecl["attributes"]["type"], "uint256[][]"); +} + +BOOST_AUTO_TEST_CASE(placeholder_statement) +{ + CompilerStack c; + c.addSource("a", "contract C { modifier M { _; } }"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value placeholder = astJson["children"][0]["children"][0]["children"][1]["children"][0]; + BOOST_CHECK_EQUAL(placeholder["name"], "PlaceholderStatement"); + BOOST_CHECK_EQUAL(placeholder["src"], "26:1:1"); +} + +BOOST_AUTO_TEST_CASE(non_utf8) +{ + CompilerStack c; + c.addSource("a", "contract C { function f() { var x = hex\"ff\"; } }"); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value varDecl = astJson["children"][0]["children"][0]["children"][2]["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(varDecl["attributes"]["type"], "string"); + BOOST_CHECK_EQUAL(varDecl["attributes"]["typeName"], Json::nullValue); + Json::Value literal = astJson["children"][0]["children"][0]["children"][2]["children"][0]["children"][1]; + BOOST_CHECK_EQUAL(literal["name"], "Literal"); + BOOST_CHECK_EQUAL(literal["attributes"]["hexvalue"], "ff"); + BOOST_CHECK_EQUAL(literal["attributes"]["token"], "string"); + BOOST_CHECK_EQUAL(literal["attributes"]["value"], Json::nullValue); + BOOST_CHECK(literal["attributes"]["type"].asString().find("invalid") != string::npos); +} + +BOOST_AUTO_TEST_CASE(function_type) +{ + CompilerStack c; + c.addSource("a", + "contract C { function f(function() external payable returns (uint) x) " + "returns (function() external constant returns (uint)) {} }" + ); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value fun = astJson["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(fun["name"], "FunctionDefinition"); + Json::Value argument = fun["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(argument["name"], "VariableDeclaration"); + BOOST_CHECK_EQUAL(argument["attributes"]["name"], "x"); + BOOST_CHECK_EQUAL(argument["attributes"]["type"], "function () payable external returns (uint256)"); + Json::Value funType = argument["children"][0]; + BOOST_CHECK_EQUAL(funType["attributes"]["constant"], false); + BOOST_CHECK_EQUAL(funType["attributes"]["payable"], true); + BOOST_CHECK_EQUAL(funType["attributes"]["visibility"], "external"); + Json::Value retval = fun["children"][1]["children"][0]; + BOOST_CHECK_EQUAL(retval["name"], "VariableDeclaration"); + BOOST_CHECK_EQUAL(retval["attributes"]["name"], ""); + BOOST_CHECK_EQUAL(retval["attributes"]["type"], "function () view external returns (uint256)"); + funType = retval["children"][0]; + BOOST_CHECK_EQUAL(funType["attributes"]["constant"], true); + BOOST_CHECK_EQUAL(funType["attributes"]["payable"], false); + BOOST_CHECK_EQUAL(funType["attributes"]["visibility"], "external"); +} + +BOOST_AUTO_TEST_CASE(documentation) +{ + CompilerStack c; + c.addSource("a", "/**This contract is empty*/ contract C {}"); + c.addSource("b", + "/**This contract is empty" + " and has a line-breaking comment.*/" + "contract C {}" + ); + c.addSource("c", + "contract C {" + " /** Some comment on Evt.*/ event Evt();" + " /** Some comment on mod.*/ modifier mod() { _; }" + " /** Some comment on fn.*/ function fn() public {}" + "}" + ); + c.setEVMVersion(dev::test::Options::get().evmVersion()); + c.parseAndAnalyze(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 0; + sourceIndices["b"] = 1; + sourceIndices["c"] = 2; + Json::Value astJsonA = ASTJsonConverter(true, sourceIndices).toJson(c.ast("a")); + Json::Value documentationA = astJsonA["children"][0]["attributes"]["documentation"]; + BOOST_CHECK_EQUAL(documentationA, "This contract is empty"); + Json::Value astJsonB = ASTJsonConverter(true, sourceIndices).toJson(c.ast("b")); + Json::Value documentationB = astJsonB["children"][0]["attributes"]["documentation"]; + BOOST_CHECK_EQUAL(documentationB, "This contract is empty and has a line-breaking comment."); + Json::Value astJsonC = ASTJsonConverter(true, sourceIndices).toJson(c.ast("c")); + Json::Value documentationC0 = astJsonC["children"][0]["children"][0]["attributes"]["documentation"]; + Json::Value documentationC1 = astJsonC["children"][0]["children"][1]["attributes"]["documentation"]; + Json::Value documentationC2 = astJsonC["children"][0]["children"][2]["attributes"]["documentation"]; + BOOST_CHECK_EQUAL(documentationC0, "Some comment on Evt."); + BOOST_CHECK_EQUAL(documentationC1, "Some comment on mod."); + BOOST_CHECK_EQUAL(documentationC2, "Some comment on fn."); +} + + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces |