diff options
70 files changed, 496 insertions, 89 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index c13bef35..cec69e31 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,7 +15,7 @@ defaults: mkdir -p build cd build [ -n "$COVERAGE" -a "$CIRCLE_BRANCH" != release -a -z "$CIRCLE_TAG" ] && CMAKE_OPTIONS="$CMAKE_OPTIONS -DCOVERAGE=ON" - cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo $CMAKE_OPTIONS + cmake .. -DCMAKE_BUILD_TYPE=Release $CMAKE_OPTIONS make -j4 - run_tests: &run_tests name: Tests diff --git a/Changelog.md b/Changelog.md index 63c0280a..60e3904c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -17,6 +17,7 @@ Compiler Features: Bugfixes: + * Compiler Interface: Report specific error message for json input errors instead of internal compiler error Build System: diff --git a/appveyor.yml b/appveyor.yml index 5377925e..864c6359 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,7 +32,7 @@ branches: - release - develop configuration: - - RelWithDebInfo + - Release environment: matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 diff --git a/cmake/FindCLN.cmake b/cmake/FindCLN.cmake index f2234bb4..0b574ab9 100644 --- a/cmake/FindCLN.cmake +++ b/cmake/FindCLN.cmake @@ -1,3 +1,8 @@ find_library(CLN_LIBRARY NAMES cln) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(CLN DEFAULT_MSG CLN_LIBRARY) + +if(CLN_FOUND AND NOT TARGET CLN::CLN) + add_library(CLN::CLN UNKNOWN IMPORTED) + set_property(TARGET CLN::CLN PROPERTY IMPORTED_LOCATION ${CLN_LIBRARY}) +endif() diff --git a/cmake/FindCVC4.cmake b/cmake/FindCVC4.cmake index 2649d7c7..887b907b 100644 --- a/cmake/FindCVC4.cmake +++ b/cmake/FindCVC4.cmake @@ -14,12 +14,19 @@ if (USE_CVC4) set(CVC4_LIBRARIES ${CVC4_LIBRARY}) if (CLN_FOUND) - set(CVC4_LIBRARIES ${CVC4_LIBRARIES} ${CLN_LIBRARY}) + set(CVC4_LIBRARIES ${CVC4_LIBRARIES} CLN::CLN) endif () if (GMP_FOUND) - set(CVC4_LIBRARIES ${CVC4_LIBRARIES} ${GMP_LIBRARY}) + set(CVC4_LIBRARIES ${CVC4_LIBRARIES} GMP::GMP) endif () + + if (NOT TARGET CVC4::CVC4) + add_library(CVC4::CVC4 UNKNOWN IMPORTED) + set_property(TARGET CVC4::CVC4 PROPERTY IMPORTED_LOCATION ${CVC4_LIBRARY}) + set_property(TARGET CVC4::CVC4 PROPERTY INTERFACE_LINK_LIBRARIES ${CVC4_LIBRARIES}) + set_property(TARGET CVC4::CVC4 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CVC4_INCLUDE_DIR}) + endif() endif() else() set(CVC4_FOUND FALSE) diff --git a/cmake/FindGMP.cmake b/cmake/FindGMP.cmake index 8abe354c..c3a02654 100644 --- a/cmake/FindGMP.cmake +++ b/cmake/FindGMP.cmake @@ -1,3 +1,8 @@ -find_library(GMP_LIBRARY NAMES gmp ) +find_library(GMP_LIBRARY NAMES gmp) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GMP DEFAULT_MSG GMP_LIBRARY) + +if(GMP_FOUND AND NOT TARGET GMP::GMP) + add_library(GMP::GMP UNKNOWN IMPORTED) + set_property(TARGET GMP::GMP PROPERTY IMPORTED_LOCATION ${GMP_LIBRARY}) +endif() diff --git a/cmake/FindZ3.cmake b/cmake/FindZ3.cmake index c017cac2..ad34cbc3 100644 --- a/cmake/FindZ3.cmake +++ b/cmake/FindZ3.cmake @@ -1,9 +1,14 @@ if (USE_Z3) find_path(Z3_INCLUDE_DIR NAMES z3++.h PATH_SUFFIXES z3) - find_library(Z3_LIBRARY NAMES z3 ) + find_library(Z3_LIBRARY NAMES z3) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Z3 DEFAULT_MSG Z3_LIBRARY Z3_INCLUDE_DIR) + + if (NOT TARGET Z3::Z3) + add_library(Z3::Z3 UNKNOWN IMPORTED) + set_property(TARGET Z3::Z3 PROPERTY IMPORTED_LOCATION ${Z3_LIBRARY}) + set_property(TARGET Z3::Z3 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Z3_INCLUDE_DIR}) + endif() else() set(Z3_FOUND FALSE) endif() -# TODO: Create IMPORTED library for Z3. diff --git a/cmake/jsoncpp.cmake b/cmake/jsoncpp.cmake index 318a526e..4db7b9c3 100644 --- a/cmake/jsoncpp.cmake +++ b/cmake/jsoncpp.cmake @@ -51,5 +51,6 @@ ExternalProject_Add(jsoncpp-project add_library(jsoncpp STATIC IMPORTED) file(MAKE_DIRECTORY ${JSONCPP_INCLUDE_DIR}) # Must exist. set_property(TARGET jsoncpp PROPERTY IMPORTED_LOCATION ${JSONCPP_LIBRARY}) +set_property(TARGET jsoncpp PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES ${JSONCPP_INCLUDE_DIR}) set_property(TARGET jsoncpp PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${JSONCPP_INCLUDE_DIR}) add_dependencies(jsoncpp jsoncpp-project) diff --git a/docs/contributing.rst b/docs/contributing.rst index 41573ea1..85816766 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -83,8 +83,8 @@ internally. .. note :: - Those working in a Windows environment wanting to run the above basic sets without aleth or libz3 in Git Bash, you would have to do: ``./build/test/RelWithDebInfo/soltest.exe -- --no-ipc --no-smt``. - If you're running this in plain Command Prompt, use ``.\build\test\RelWithDebInfo\soltest.exe -- --no-ipc --no-smt``. + Those working in a Windows environment wanting to run the above basic sets without aleth or libz3 in Git Bash, you would have to do: ``./build/test/Release/soltest.exe -- --no-ipc --no-smt``. + If you're running this in plain Command Prompt, use ``.\build\test\Release\soltest.exe -- --no-ipc --no-smt``. The option ``--no-smt`` disables the tests that require ``libz3`` and ``--no-ipc`` disables those that require ``aleth``. diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index 2797d8b0..c475d427 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -296,13 +296,13 @@ And for Windows: This latter set of instructions should result in the creation of **solidity.sln** in that build directory. Double-clicking on that file should result in Visual Studio firing up. We suggest building -**RelWithDebugInfo** configuration, but all others work. +**Release** configuration, but all others work. Alternatively, you can build for Windows on the command-line, like so: .. code-block:: bash - cmake --build . --config RelWithDebInfo + cmake --build . --config Release CMake options ============= diff --git a/docs/types.rst b/docs/types.rst index dcd5f644..08fbd7b3 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -811,40 +811,50 @@ Data locations are not only relevant for persistency of data, but also for the s Arrays ------ -Arrays can have a compile-time fixed size or they can be dynamic. -The are few restrictions for the element, it can also be -another array, a mapping or a struct. The general restrictions for -types apply, though, in that mappings can only be used in storage -and publicly-visible functions need parameters that are :ref:`ABI types <ABI>`. - -An array of fixed size ``k`` and element type ``T`` is written as ``T[k]``, -an array of dynamic size as ``T[]``. As an example, an array of 5 dynamic -arrays of ``uint`` is ``uint[][5]`` (note that the notation is reversed when -compared to some other languages). To access the second uint in the -third dynamic array, you use ``x[2][1]`` (indices are zero-based and -access works in the opposite way of the declaration, i.e. ``x[2]`` -shaves off one level in the type from the right). - -Accessing an array past its end causes a revert. If you want to add -new elements, you have to use ``.push()`` or increase the ``.length`` -member (see below). +Arrays can have a compile-time fixed size, or they can have a dynamic size. + +The type of an array of fixed size ``k`` and element type ``T`` is written as ``T[k]``, +and an array of dynamic size as ``T[]``. + +For example, an array of 5 dynamic arrays of ``uint`` is written as +``uint[][5]``. The notation is reversed compared to some other languages. In +Solidity, ``X[3]`` is always an array containing three elements of type ``X``, +even if ``X`` is itself an array. This is not the case in other languages such +as C. + +Indices are zero-based, and access is in the opposite direction of the +declaration. + +For example, if you have a variable ``uint[][5] x memory``, you access the +second ``uint`` in the third dynamic array using ``x[2][1]``, and to access the +third dynamic array, use ``x[2]``. Again, +if you have an array ``T[5] a`` for a type ``T`` that can also be an array, +then ``a[2]`` always has type ``T``. + +Array elements can be of any type, including mapping or struct. The general +restrictions for types apply, in that mappings can only be stored in the +``storage`` data location and publicly-visible functions need parameters that are :ref:`ABI types <ABI>`. + +Accessing an array past its end causes a failing assertion. You can use the ``.push()`` method to append a new element at the end or assign to the ``.length`` :ref:`member <array-members>` to change the size (see below for caveats). +method or increase the ``.length`` :ref:`member <array-members>` to add elements. Variables of type ``bytes`` and ``string`` are special arrays. A ``bytes`` is similar to ``byte[]``, but it is packed tightly in calldata and memory. ``string`` is equal to ``bytes`` but does not allow length or index access. -So ``bytes`` should always be preferred over ``byte[]`` because it is cheaper. -As a rule of thumb, use ``bytes`` for arbitrary-length raw byte data and ``string`` -for arbitrary-length string (UTF-8) data. If you can limit the length to a certain -number of bytes, always use one of ``bytes1`` to ``bytes32`` because they are much cheaper. + +You should use ``bytes`` over ``byte[]`` because it is cheaper, since ``byte[]`` adds 31 padding bytes between the elements. As a general rule, +use ``bytes`` for arbitrary-length raw byte data and ``string`` for arbitrary-length +string (UTF-8) data. If you can limit the length to a certain number of bytes, +always use one of the value types ``bytes1`` to ``bytes32`` because they are much cheaper. .. note:: If you want to access the byte-representation of a string ``s``, use ``bytes(s).length`` / ``bytes(s)[7] = 'x';``. Keep in mind that you are accessing the low-level bytes of the UTF-8 representation, - and not the individual characters! + and not the individual characters. It is possible to mark arrays ``public`` and have Solidity create a :ref:`getter <visibility-and-getters>`. -The numeric index will become a required parameter for the getter. +The numeric index becomes a required parameter for the getter. .. index:: ! array;allocating, new @@ -918,8 +928,10 @@ complications because of how arrays are passed in the ABI. .. index:: ! array;length, length, push, pop, !array;push, !array;pop -Members -^^^^^^^ +.. _array-members: + +Array Members +^^^^^^^^^^^^^ **length**: Arrays have a ``length`` member that contains their number of elements. diff --git a/libdevcore/CMakeLists.txt b/libdevcore/CMakeLists.txt index e2309b16..e68ac10a 100644 --- a/libdevcore/CMakeLists.txt +++ b/libdevcore/CMakeLists.txt @@ -30,7 +30,7 @@ set(sources ) add_library(devcore ${sources}) -target_link_libraries(devcore PRIVATE jsoncpp ${Boost_FILESYSTEM_LIBRARIES} ${Boost_REGEX_LIBRARIES} ${Boost_SYSTEM_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(devcore PUBLIC jsoncpp ${Boost_FILESYSTEM_LIBRARIES} ${Boost_REGEX_LIBRARIES} ${Boost_SYSTEM_LIBRARIES} Threads::Threads) target_include_directories(devcore PUBLIC "${CMAKE_SOURCE_DIR}") target_include_directories(devcore SYSTEM PUBLIC ${Boost_INCLUDE_DIRS}) add_dependencies(devcore solidity_BuildInfo.h) diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index a7875171..d21be199 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -57,22 +57,26 @@ class AssemblyItem public: enum class JumpType { Ordinary, IntoFunction, OutOfFunction }; - AssemblyItem(u256 _push, langutil::SourceLocation const& _location = langutil::SourceLocation()): - AssemblyItem(Push, _push, _location) { } - AssemblyItem(solidity::Instruction _i, langutil::SourceLocation const& _location = langutil::SourceLocation()): + AssemblyItem(u256 _push, langutil::SourceLocation _location = langutil::SourceLocation()): + AssemblyItem(Push, std::move(_push), std::move(_location)) { } + AssemblyItem(solidity::Instruction _i, langutil::SourceLocation _location = langutil::SourceLocation()): m_type(Operation), m_instruction(_i), - m_location(_location) + m_location(std::move(_location)) {} - AssemblyItem(AssemblyItemType _type, u256 _data = 0, langutil::SourceLocation const& _location = langutil::SourceLocation()): + AssemblyItem(AssemblyItemType _type, u256 _data = 0, langutil::SourceLocation _location = langutil::SourceLocation()): m_type(_type), - m_location(_location) + m_location(std::move(_location)) { if (m_type == Operation) m_instruction = Instruction(uint8_t(_data)); else - m_data = std::make_shared<u256>(_data); + m_data = std::make_shared<u256>(std::move(_data)); } + AssemblyItem(AssemblyItem const&) = default; + AssemblyItem(AssemblyItem&&) = default; + AssemblyItem& operator=(AssemblyItem const&) = default; + AssemblyItem& operator=(AssemblyItem&&) = default; AssemblyItem tag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(Tag, data()); } AssemblyItem pushTag() const { assertThrow(m_type == PushTag || m_type == Tag, Exception, ""); return AssemblyItem(PushTag, data()); } @@ -114,6 +118,13 @@ public: return data() < _other.data(); } + /// Shortcut that avoids constructing an AssemblyItem just to perform the comparison. + bool operator==(Instruction _instr) const + { + return type() == Operation && instruction() == _instr; + } + bool operator!=(Instruction _instr) const { return !operator==(_instr); } + /// @returns an upper bound for the number of bytes required by this item, assuming that /// the value of a jump tag takes @a _addressLength bytes. unsigned bytesRequired(unsigned _addressLength) const; diff --git a/libevmasm/PeepholeOptimiser.cpp b/libevmasm/PeepholeOptimiser.cpp index 6d8e1df6..e211026b 100644 --- a/libevmasm/PeepholeOptimiser.cpp +++ b/libevmasm/PeepholeOptimiser.cpp @@ -160,8 +160,7 @@ struct CommutativeSwap: SimplePeepholeOptimizerMethod<CommutativeSwap, 2> { // Remove SWAP1 if following instruction is commutative if ( - _swap.type() == Operation && - _swap.instruction() == Instruction::SWAP1 && + _swap == Instruction::SWAP1 && SemanticInformation::isCommutativeOperation(_op) ) { @@ -177,7 +176,7 @@ struct SwapComparison: SimplePeepholeOptimizerMethod<SwapComparison, 2> { static bool applySimple(AssemblyItem const& _swap, AssemblyItem const& _op, std::back_insert_iterator<AssemblyItems> _out) { - map<Instruction, Instruction> swappableOps{ + static map<Instruction, Instruction> const swappableOps{ { Instruction::LT, Instruction::GT }, { Instruction::GT, Instruction::LT }, { Instruction::SLT, Instruction::SGT }, @@ -185,8 +184,7 @@ struct SwapComparison: SimplePeepholeOptimizerMethod<SwapComparison, 2> }; if ( - _swap.type() == Operation && - _swap.instruction() == Instruction::SWAP1 && + _swap == Instruction::SWAP1 && _op.type() == Operation && swappableOps.count(_op.instruction()) ) diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp index 78f3c9c7..2a24a27e 100644 --- a/libevmasm/SemanticInformation.cpp +++ b/libevmasm/SemanticInformation.cpp @@ -108,7 +108,7 @@ bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item) bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item) { - return _item == AssemblyItem(Instruction::JUMP) || _item == AssemblyItem(Instruction::JUMPI); + return _item == Instruction::JUMP || _item == Instruction::JUMPI; } bool SemanticInformation::altersControlFlow(AssemblyItem const& _item) diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 389f94bd..8c2ab347 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -104,7 +104,6 @@ set(sources find_package(Z3 QUIET) if (${Z3_FOUND}) - include_directories(${Z3_INCLUDE_DIR}) add_definitions(-DHAVE_Z3) message("Z3 SMT solver found. This enables optional SMT checking with Z3.") set(z3_SRCS formal/Z3Interface.cpp formal/Z3Interface.h) @@ -114,7 +113,6 @@ endif() find_package(CVC4 QUIET) if (${CVC4_FOUND}) - include_directories(${CVC4_INCLUDE_DIR}) add_definitions(-DHAVE_CVC4) message("CVC4 SMT solver found. This enables optional SMT checking with CVC4.") set(cvc4_SRCS formal/CVC4Interface.cpp formal/CVC4Interface.h) @@ -131,9 +129,9 @@ add_library(solidity ${sources} ${z3_SRCS} ${cvc4_SRCS}) target_link_libraries(solidity PUBLIC yul evmasm langutil devcore ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY}) if (${Z3_FOUND}) - target_link_libraries(solidity PUBLIC ${Z3_LIBRARY}) + target_link_libraries(solidity PUBLIC Z3::Z3) endif() if (${CVC4_FOUND}) - target_link_libraries(solidity PUBLIC ${CVC4_LIBRARIES}) + target_link_libraries(solidity PUBLIC CVC4::CVC4) endif() diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 12e14864..066b5004 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -114,7 +114,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) vector<string> literals(_pragma.literals().begin() + 1, _pragma.literals().end()); SemVerMatchExpressionParser parser(tokens, literals); auto matchExpression = parser.parse(); - SemVerVersion currentVersion{string(VersionString)}; + static SemVerVersion const currentVersion{string(VersionString)}; if (!matchExpression.matches(currentVersion)) m_errorReporter.syntaxError( _pragma.location(), diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 625a665d..adfb94bd 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -619,6 +619,22 @@ tuple<int, int, int, int> CompilerStack::positionFromSourceLocation(SourceLocati return make_tuple(++startLine, ++startColumn, ++endLine, ++endColumn); } + +h256 const& CompilerStack::Source::keccak256() const +{ + if (keccak256HashCached == h256{}) + keccak256HashCached = dev::keccak256(scanner->source()); + return keccak256HashCached; +} + +h256 const& CompilerStack::Source::swarmHash() const +{ + if (swarmHashCached == h256{}) + swarmHashCached = dev::swarmHash(scanner->source()); + return swarmHashCached; +} + + StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string const& _sourcePath) { solAssert(m_stackState < ParsingSuccessful, ""); @@ -860,16 +876,13 @@ string CompilerStack::createMetadata(Contract const& _contract) const continue; solAssert(s.second.scanner, "Scanner not available"); - meta["sources"][s.first]["keccak256"] = - "0x" + toHex(dev::keccak256(s.second.scanner->source()).asBytes()); + meta["sources"][s.first]["keccak256"] = "0x" + toHex(s.second.keccak256().asBytes()); if (m_metadataLiteralSources) meta["sources"][s.first]["content"] = s.second.scanner->source(); else { meta["sources"][s.first]["urls"] = Json::arrayValue; - meta["sources"][s.first]["urls"].append( - "bzzr://" + toHex(dev::swarmHash(s.second.scanner->source()).asBytes()) - ); + meta["sources"][s.first]["urls"].append("bzzr://" + toHex(s.second.swarmHash().asBytes())); } } meta["settings"]["optimizer"]["enabled"] = m_optimize; @@ -896,7 +909,7 @@ string CompilerStack::createMetadata(Contract const& _contract) const return jsonCompactPrint(meta); } -bytes CompilerStack::createCBORMetadata(string _metadata, bool _experimentalMode) +bytes CompilerStack::createCBORMetadata(string const& _metadata, bool _experimentalMode) { bytes cborEncodedHash = // CBOR-encoding of the key "bzzr0" diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 74033170..81d5009f 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -261,7 +261,11 @@ private: std::shared_ptr<langutil::Scanner> scanner; std::shared_ptr<SourceUnit> ast; bool isLibrary = false; - void reset() { scanner.reset(); ast.reset(); } + h256 mutable keccak256HashCached; + h256 mutable swarmHashCached; + void reset() { *this = Source(); } + h256 const& keccak256() const; + h256 const& swarmHash() const; }; /// The state per contract. Filled gradually during compilation. @@ -315,7 +319,7 @@ private: std::string createMetadata(Contract const& _contract) const; /// @returns the metadata CBOR for the given serialised metadata JSON. - static bytes createCBORMetadata(std::string _metadata, bool _experimentalMode); + static bytes createCBORMetadata(std::string const& _metadata, bool _experimentalMode); /// @returns the computer source mapping string. std::string computeSourceMapping(eth::AssemblyItems const& _items) const; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 5be267e9..e99b1324 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -228,48 +228,97 @@ Json::Value collectEVMObject(eth::LinkerObject const& _object, string const* _so return output; } -boost::optional<Json::Value> checkKeys(Json::Value const& _input, set<string> const& _keys) +boost::optional<Json::Value> checkKeys(Json::Value const& _input, set<string> const& _keys, string const& _name) { + if (!!_input && !_input.isObject()) + return formatFatalError("JSONError", "\"" + _name + "\" must be an object"); + for (auto const& member: _input.getMemberNames()) if (!_keys.count(member)) return formatFatalError("JSONError", "Unknown key \"" + member + "\""); + return boost::none; } boost::optional<Json::Value> checkRootKeys(Json::Value const& _input) { static set<string> keys{"auxiliaryInput", "language", "settings", "sources"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "root"); } -boost::optional<Json::Value> checkSourceKeys(Json::Value const& _input) +boost::optional<Json::Value> checkSourceKeys(Json::Value const& _input, string const& _name) { static set<string> keys{"content", "keccak256", "urls"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "sources." + _name); } boost::optional<Json::Value> checkAuxiliaryInputKeys(Json::Value const& _input) { static set<string> keys{"smtlib2responses"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "auxiliaryInput"); } boost::optional<Json::Value> checkSettingsKeys(Json::Value const& _input) { static set<string> keys{"evmVersion", "libraries", "metadata", "optimizer", "outputSelection", "remappings"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "settings"); } boost::optional<Json::Value> checkOptimizerKeys(Json::Value const& _input) { static set<string> keys{"enabled", "runs"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "settings.optimizer"); } boost::optional<Json::Value> checkMetadataKeys(Json::Value const& _input) { static set<string> keys{"useLiteralContent"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "settings.metadata"); +} + +boost::optional<Json::Value> checkOutputSelection(Json::Value const& _outputSelection) +{ + if (!!_outputSelection && !_outputSelection.isObject()) + return formatFatalError("JSONError", "\"settings.outputSelection\" must be an object"); + + for (auto const& sourceName: _outputSelection.getMemberNames()) + { + auto const& sourceVal = _outputSelection[sourceName]; + + if (!sourceVal.isObject()) + return formatFatalError( + "JSONError", + "\"settings.outputSelection." + sourceName + "\" must be an object" + ); + + for (auto const& contractName: sourceVal.getMemberNames()) + { + auto const& contractVal = sourceVal[contractName]; + + if (!contractVal.isArray()) + return formatFatalError( + "JSONError", + "\"settings.outputSelection." + + sourceName + + "." + + contractName + + "\" must be a string array" + ); + + for (auto const& output: contractVal) + if (!output.isString()) + return formatFatalError( + "JSONError", + "\"settings.outputSelection." + + sourceName + + "." + + contractName + + "\" must be a string array" + ); + } + } + + return boost::none; } } @@ -301,10 +350,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) { string hash; - if (!sources[sourceName].isObject()) - return formatFatalError("JSONError", "Source input is not a JSON object."); - - if (auto result = checkSourceKeys(sources[sourceName])) + if (auto result = checkSourceKeys(sources[sourceName], sourceName)) return *result; if (sources[sourceName]["keccak256"].isString()) @@ -380,6 +426,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) { Json::Value const& smtlib2Responses = auxInputs["smtlib2responses"]; if (!!smtlib2Responses) + { + if (!smtlib2Responses.isObject()) + return formatFatalError("JSONError", "\"auxiliaryInput.smtlib2responses\" must be an object."); + for (auto const& hashString: smtlib2Responses.getMemberNames()) { h256 hash; @@ -392,8 +442,15 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) return formatFatalError("JSONError", "Invalid hex encoding of SMTLib2 auxiliary input."); } + if (!smtlib2Responses[hashString].isString()) + return formatFatalError( + "JSONError", + "\"smtlib2Responses." + hashString + "\" must be a string." + ); + m_compilerStack.addSMTLib2Response(hash, smtlib2Responses[hashString].asString()); } + } } Json::Value const& settings = _input.get("settings", Json::Value()); @@ -411,11 +468,14 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.setEVMVersion(*version); } + if (settings.isMember("remappings") && !settings["remappings"].isArray()) + return formatFatalError("JSONError", "\"settings.remappings\" must be an array of strings."); + vector<CompilerStack::Remapping> remappings; for (auto const& remapping: settings.get("remappings", Json::Value())) { if (!remapping.isString()) - return formatFatalError("JSONError", "Remapping entry must be a string."); + return formatFatalError("JSONError", "\"settings.remappings\" must be an array of strings"); if (auto r = CompilerStack::parseRemapping(remapping.asString())) remappings.emplace_back(std::move(*r)); else @@ -498,6 +558,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.useMetadataLiteralSources(metadataSettings.get("useLiteralContent", Json::Value(false)).asBool()); Json::Value outputSelection = settings.get("outputSelection", Json::Value()); + + if (auto jsonError = checkOutputSelection(outputSelection)) + return *jsonError; + m_compilerStack.setRequestedContractNames(requestedContractNames(outputSelection)); try diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 9de2146e..bcb28988 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -22,6 +22,8 @@ #include <libsolidity/parsing/Parser.h> +#include <libsolidity/analysis/SemVerHandler.h> +#include <libsolidity/interface/Version.h> #include <libyul/AsmParser.h> #include <libyul/backends/evm/EVMDialect.h> #include <liblangutil/ErrorReporter.h> @@ -106,6 +108,20 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner) } } +void Parser::parsePragmaVersion(vector<Token> const& tokens, vector<string> const& literals) +{ + SemVerMatchExpressionParser parser(tokens, literals); + auto matchExpression = parser.parse(); + static SemVerVersion const currentVersion{string(VersionString)}; + // FIXME: only match for major version incompatibility + if (!matchExpression.matches(currentVersion)) + fatalParserError( + "Source file requires different compiler version (current compiler is " + + string(VersionString) + " - note that nightly builds are considered to be " + "strictly less than the released version" + ); +} + ASTPointer<PragmaDirective> Parser::parsePragmaDirective() { RecursionGuard recursionGuard(*this); @@ -134,6 +150,15 @@ ASTPointer<PragmaDirective> Parser::parsePragmaDirective() while (m_scanner->currentToken() != Token::Semicolon && m_scanner->currentToken() != Token::EOS); nodeFactory.markEndPosition(); expectToken(Token::Semicolon); + + if (literals.size() >= 2 && literals[0] == "solidity") + { + parsePragmaVersion( + vector<Token>(tokens.begin() + 1, tokens.end()), + vector<string>(literals.begin() + 1, literals.end()) + ); + } + return nodeFactory.createNode<PragmaDirective>(tokens, literals); } diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 15852096..bf02c626 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -70,6 +70,7 @@ private: ///@{ ///@name Parsing functions for the AST nodes + void parsePragmaVersion(std::vector<Token> const& tokens, std::vector<std::string> const& literals); ASTPointer<PragmaDirective> parsePragmaDirective(); ASTPointer<ImportDirective> parseImportDirective(); ContractDefinition::ContractKind parseContractKind(); diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input.json b/test/cmdlineTests/standard_wrong_type_auxiliary_input.json new file mode 100644 index 00000000..8d2c7593 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input.json @@ -0,0 +1,11 @@ +{ + "language": "Solidity", + "sources": + { + "A": + { + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + }, + "auxiliaryInput": [1, 2, 3] +} diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input.json.exit b/test/cmdlineTests/standard_wrong_type_auxiliary_input.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input.json.stdout b/test/cmdlineTests/standard_wrong_type_auxiliary_input.json.stdout new file mode 100644 index 00000000..046cb6d9 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input.json.stdout @@ -0,0 +1,2 @@ +{"errors":[{"component":"general","formattedMessage":"\"auxiliaryInput\" must be an object","message":"\"auxiliaryInput\" must be an object","severity":"error","type":"JSONError"}]} + diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses.json b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses.json new file mode 100644 index 00000000..9175050f --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses.json @@ -0,0 +1,20 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "abi", "devdoc", "userdoc", "evm.bytecode", "evm.assembly", "evm.gasEstimates", "evm.legacyAssembly", "metadata" ], + "": [ "legacyAST" ] + } + } + }, + "auxiliaryInput": + { + "smtlib2responses": "not an object" + } +} diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses.json.exit b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses.json.stdout b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses.json.stdout new file mode 100644 index 00000000..3efaea20 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"auxiliaryInput.smtlib2responses\" must be an object.","message":"\"auxiliaryInput.smtlib2responses\" must be an object.","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member.json b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member.json new file mode 100644 index 00000000..aa7d451b --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member.json @@ -0,0 +1,23 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "abi", "devdoc", "userdoc", "evm.bytecode", "evm.assembly", "evm.gasEstimates", "evm.legacyAssembly", "metadata" ], + "": [ "legacyAST" ] + } + } + }, + "auxiliaryInput": + { + "smtlib2responses": + { + "abc": ["not a string"] + } + } +} diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member.json.exit b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member.json.stdout b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member.json.stdout new file mode 100644 index 00000000..a05176be --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"smtlib2Responses.abc\" must be a string.","message":"\"smtlib2Responses.abc\" must be a string.","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_metadata.json b/test/cmdlineTests/standard_wrong_type_metadata.json new file mode 100644 index 00000000..d4dd06a1 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_metadata.json @@ -0,0 +1,19 @@ +{ + "language": "Solidity", + "sources": + { + "A": + { + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + }, + "settings": + { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "evmVersion": "byzantium", + "metadata": ["meta1", "meta2", "meta3"] + } +} diff --git a/test/cmdlineTests/standard_wrong_type_metadata.json.exit b/test/cmdlineTests/standard_wrong_type_metadata.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_metadata.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_metadata.json.stdout b/test/cmdlineTests/standard_wrong_type_metadata.json.stdout new file mode 100644 index 00000000..7b997cec --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_metadata.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"settings.metadata\" must be an object","message":"\"settings.metadata\" must be an object","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_optimizer.json b/test/cmdlineTests/standard_wrong_type_optimizer.json new file mode 100644 index 00000000..b42ca550 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_optimizer.json @@ -0,0 +1,18 @@ +{ + "language": "Solidity", + "sources": + { + "A": + { + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + }, + "settings": + { + "optimizer": 1, + "evmVersion": "byzantium", + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/test/cmdlineTests/standard_wrong_type_optimizer.json.exit b/test/cmdlineTests/standard_wrong_type_optimizer.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_optimizer.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_optimizer.json.stdout b/test/cmdlineTests/standard_wrong_type_optimizer.json.stdout new file mode 100644 index 00000000..d43b6470 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_optimizer.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"settings.optimizer\" must be an object","message":"\"settings.optimizer\" must be an object","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_output_selection.json b/test/cmdlineTests/standard_wrong_type_output_selection.json new file mode 100644 index 00000000..a7b615d1 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection.json @@ -0,0 +1,11 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { }" + } + }, + "settings": { + "outputSelection": "not an object" + } +} diff --git a/test/cmdlineTests/standard_wrong_type_output_selection.json.exit b/test/cmdlineTests/standard_wrong_type_output_selection.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_output_selection.json.stdout b/test/cmdlineTests/standard_wrong_type_output_selection.json.stdout new file mode 100644 index 00000000..39e74882 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"settings.outputSelection\" must be an object","message":"\"settings.outputSelection\" must be an object","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_contract.json b/test/cmdlineTests/standard_wrong_type_output_selection_contract.json new file mode 100644 index 00000000..9840a97e --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection_contract.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": "it's a contract, but not an array!", + "": [ "legacyAST" ] + } + } + } +} diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_contract.json.exit b/test/cmdlineTests/standard_wrong_type_output_selection_contract.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection_contract.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_contract.json.stdout b/test/cmdlineTests/standard_wrong_type_output_selection_contract.json.stdout new file mode 100644 index 00000000..a4ba320e --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection_contract.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"settings.outputSelection.fileA.A\" must be a string array","message":"\"settings.outputSelection.fileA.A\" must be a string array","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_file.json b/test/cmdlineTests/standard_wrong_type_output_selection_file.json new file mode 100644 index 00000000..7ab12ba8 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection_file.json @@ -0,0 +1,13 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { }" + } + }, + "settings": { + "outputSelection": { + "fileA": "awesome file!" + } + } +} diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_file.json.exit b/test/cmdlineTests/standard_wrong_type_output_selection_file.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection_file.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_file.json.stdout b/test/cmdlineTests/standard_wrong_type_output_selection_file.json.stdout new file mode 100644 index 00000000..8874e636 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection_file.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"settings.outputSelection.fileA\" must be an object","message":"\"settings.outputSelection.fileA\" must be an object","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_output.json b/test/cmdlineTests/standard_wrong_type_output_selection_output.json new file mode 100644 index 00000000..3e5cd661 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection_output.json @@ -0,0 +1,16 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ 1, 2, 3 ,4], + "": [ "legacyAST" ] + } + } + } +} diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_output.json.exit b/test/cmdlineTests/standard_wrong_type_output_selection_output.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection_output.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_output.json.stdout b/test/cmdlineTests/standard_wrong_type_output_selection_output.json.stdout new file mode 100644 index 00000000..a4ba320e --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_output_selection_output.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"settings.outputSelection.fileA.A\" must be a string array","message":"\"settings.outputSelection.fileA.A\" must be a string array","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_remappings.json b/test/cmdlineTests/standard_wrong_type_remappings.json new file mode 100644 index 00000000..1436e014 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_remappings.json @@ -0,0 +1,17 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "abi", "devdoc", "userdoc", "evm.bytecode", "evm.assembly", "evm.gasEstimates", "evm.legacyAssembly", "metadata" ], + "": [ "legacyAST" ] + } + }, + "remappings": "not an object" + } +} diff --git a/test/cmdlineTests/standard_wrong_type_remappings.json.exit b/test/cmdlineTests/standard_wrong_type_remappings.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_remappings.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_remappings.json.stdout b/test/cmdlineTests/standard_wrong_type_remappings.json.stdout new file mode 100644 index 00000000..b5e4ea5c --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_remappings.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"settings.remappings\" must be an array of strings.","message":"\"settings.remappings\" must be an array of strings.","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_remappings_entry.json b/test/cmdlineTests/standard_wrong_type_remappings_entry.json new file mode 100644 index 00000000..c96611f3 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_remappings_entry.json @@ -0,0 +1,17 @@ +{ + "language": "Solidity", + "sources": { + "fileA": { + "content": "contract A { }" + } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "abi", "devdoc", "userdoc", "evm.bytecode", "evm.assembly", "evm.gasEstimates", "evm.legacyAssembly", "metadata" ], + "": [ "legacyAST" ] + } + }, + "remappings": [1, 2 ,3 ,4] + } +} diff --git a/test/cmdlineTests/standard_wrong_type_remappings_entry.json.exit b/test/cmdlineTests/standard_wrong_type_remappings_entry.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_remappings_entry.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_remappings_entry.json.stdout b/test/cmdlineTests/standard_wrong_type_remappings_entry.json.stdout new file mode 100644 index 00000000..0fc71ded --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_remappings_entry.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"settings.remappings\" must be an array of strings","message":"\"settings.remappings\" must be an array of strings","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_root.json b/test/cmdlineTests/standard_wrong_type_root.json new file mode 100644 index 00000000..4763607a --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_root.json @@ -0,0 +1 @@ +["abc"] diff --git a/test/cmdlineTests/standard_wrong_type_root.json.exit b/test/cmdlineTests/standard_wrong_type_root.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_root.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_root.json.stdout b/test/cmdlineTests/standard_wrong_type_root.json.stdout new file mode 100644 index 00000000..15c12e77 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_root.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"Input is not a JSON object.","message":"Input is not a JSON object.","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_settings.json b/test/cmdlineTests/standard_wrong_type_settings.json new file mode 100644 index 00000000..7cdb0881 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_settings.json @@ -0,0 +1,23 @@ +{ + "language": "Solidity", + "sources": + { + "A": + { + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + }, + "settings": + [ + { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "evmVersion": "byzantium", + "metadata": { + "useLiteralContent": true + } + } + ] +} diff --git a/test/cmdlineTests/standard_wrong_type_settings.json.exit b/test/cmdlineTests/standard_wrong_type_settings.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_settings.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_settings.json.stdout b/test/cmdlineTests/standard_wrong_type_settings.json.stdout new file mode 100644 index 00000000..c78c6086 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_settings.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"settings\" must be an object","message":"\"settings\" must be an object","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_source.json b/test/cmdlineTests/standard_wrong_type_source.json new file mode 100644 index 00000000..d58504fe --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_source.json @@ -0,0 +1,12 @@ +{ + "language": "Solidity", + "sources": + { + "A": "not an object :o", + "B": [1, 2, 3], + "C": + { + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + } +} diff --git a/test/cmdlineTests/standard_wrong_type_source.json.exit b/test/cmdlineTests/standard_wrong_type_source.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_source.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_source.json.stdout b/test/cmdlineTests/standard_wrong_type_source.json.stdout new file mode 100644 index 00000000..98fe32fd --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_source.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"sources.A\" must be an object","message":"\"sources.A\" must be an object","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_type_sources.json b/test/cmdlineTests/standard_wrong_type_sources.json new file mode 100644 index 00000000..76e1ae7d --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_sources.json @@ -0,0 +1,4 @@ +{ + "language": "Solidity", + "sources": ["source1", "source2", "source3"] +} diff --git a/test/cmdlineTests/standard_wrong_type_sources.json.exit b/test/cmdlineTests/standard_wrong_type_sources.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_sources.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_type_sources.json.stdout b/test/cmdlineTests/standard_wrong_type_sources.json.stdout new file mode 100644 index 00000000..ac6c613f --- /dev/null +++ b/test/cmdlineTests/standard_wrong_type_sources.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"\"sources\" is not a JSON object.","message":"\"sources\" is not a JSON object.","severity":"error","type":"JSONError"}]} diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp index 8a72f996..abeecd32 100644 --- a/test/libsolidity/AnalysisFramework.cpp +++ b/test/libsolidity/AnalysisFramework.cpp @@ -52,7 +52,7 @@ AnalysisFramework::parseAnalyseAndReturnError( m_compiler.setEVMVersion(dev::test::Options::get().evmVersion()); if (!m_compiler.parse()) { - BOOST_ERROR("Parsing contract failed in analysis test suite:" + formatErrors()); + BOOST_FAIL("Parsing contract failed in analysis test suite:" + formatErrors()); } m_compiler.analyze(); diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 75726027..774f67fe 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -376,18 +376,6 @@ BOOST_AUTO_TEST_CASE(warn_nonpresent_pragma) BOOST_CHECK(searchErrorMessage(*sourceAndError.second.front(), "Source file does not specify required compiler version!")); } -BOOST_AUTO_TEST_CASE(unsatisfied_version) -{ - char const* text = R"( - pragma solidity ^99.99.0; - )"; - auto sourceAndError = parseAnalyseAndReturnError(text, false, false, false); - BOOST_REQUIRE(!sourceAndError.second.empty()); - BOOST_REQUIRE(!!sourceAndError.first); - BOOST_CHECK(sourceAndError.second.front()->type() == Error::Type::SyntaxError); - BOOST_CHECK(searchErrorMessage(*sourceAndError.second.front(), "Source file requires different compiler version")); -} - BOOST_AUTO_TEST_CASE(returndatasize_as_variable) { char const* text = R"( diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index d86d3d39..a33c6134 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -113,6 +113,23 @@ while(0) BOOST_AUTO_TEST_SUITE(SolidityParser) +BOOST_AUTO_TEST_CASE(unsatisfied_version) +{ + char const* text = R"( + pragma solidity ^99.99.0; + )"; + CHECK_PARSE_ERROR(text, "Source file requires different compiler version"); +} + +BOOST_AUTO_TEST_CASE(unsatisfied_version_followed_by_invalid_syntax) +{ + char const* text = R"( + pragma solidity ^99.99.0; + this is surely invalid + )"; + CHECK_PARSE_ERROR(text, "Source file requires different compiler version"); +} + BOOST_AUTO_TEST_CASE(function_natspec_documentation) { char const* text = R"( |