1 /* 2 This file is part of solidity. 3 4 solidity is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 solidity is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with solidity. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 // SPDX-License-Identifier: GPL-3.0 18 /** 19 * Framework for testing features from the analysis phase of compiler. 20 */ 21 22 #pragma once 23 24 #include <test/libsolidity/ErrorCheck.h> 25 26 #include <libsolidity/interface/CompilerStack.h> 27 28 #include <functional> 29 #include <string> 30 #include <memory> 31 32 namespace solidity::frontend 33 { 34 class Type; 35 class FunctionType; 36 using FunctionTypePointer = FunctionType const*; 37 } 38 39 namespace solidity::frontend::test 40 { 41 42 class AnalysisFramework 43 { 44 45 protected: 46 virtual std::pair<SourceUnit const*, langutil::ErrorList> 47 parseAnalyseAndReturnError( 48 std::string const& _source, 49 bool _reportWarnings = false, 50 bool _insertLicenseAndVersionPragma = true, 51 bool _allowMultipleErrors = false, 52 bool _allowRecoveryErrors = false 53 ); 54 virtual ~AnalysisFramework() = default; 55 56 SourceUnit const* parseAndAnalyse(std::string const& _source); 57 bool success(std::string const& _source); 58 langutil::ErrorList expectError(std::string const& _source, bool _warning = false, bool _allowMultiple = false); 59 60 std::string formatErrors() const; 61 std::string formatError(langutil::Error const& _error) const; 62 63 static ContractDefinition const* retrieveContractByName(SourceUnit const& _source, std::string const& _name); 64 static FunctionTypePointer retrieveFunctionBySignature( 65 ContractDefinition const& _contract, 66 std::string const& _signature 67 ); 68 69 // filter out the warnings in m_warningsToFilter or all warnings and infos if _includeWarningsAndInfos is false 70 langutil::ErrorList filterErrors(langutil::ErrorList const& _errorList, bool _includeWarningsAndInfos) const; 71 72 std::vector<std::string> m_warningsToFilter = {"This is a pre-release compiler version"}; 73 std::vector<std::string> m_messagesToCut = {"Source file requires different compiler version (current compiler is"}; 74 75 /// @returns reference to lazy-instanciated CompilerStack. compiler()76 solidity::frontend::CompilerStack& compiler() 77 { 78 if (!m_compiler) 79 m_compiler = std::make_unique<solidity::frontend::CompilerStack>(); 80 return *m_compiler; 81 } 82 83 /// @returns reference to lazy-instanciated CompilerStack. compiler()84 solidity::frontend::CompilerStack const& compiler() const 85 { 86 if (!m_compiler) 87 m_compiler = std::make_unique<solidity::frontend::CompilerStack>(); 88 return *m_compiler; 89 } 90 91 private: 92 mutable std::unique_ptr<solidity::frontend::CompilerStack> m_compiler; 93 }; 94 95 // Asserts that the compilation down to typechecking 96 // emits multiple errors of different types and messages, provided in the second argument. 97 #define CHECK_ALLOW_MULTI(text, expectations) \ 98 do \ 99 { \ 100 ErrorList errors = expectError((text), true, true); \ 101 auto message = searchErrors(errors, (expectations)); \ 102 BOOST_CHECK_MESSAGE(message.empty(), message); \ 103 } while(0) 104 105 #define CHECK_ERROR_OR_WARNING(text, typ, substrings, warning, allowMulti) \ 106 do \ 107 { \ 108 ErrorList errors = expectError((text), (warning), (allowMulti)); \ 109 std::vector<std::pair<Error::Type, std::string>> expectations; \ 110 for (auto const& str: substrings) \ 111 expectations.emplace_back((Error::Type::typ), str); \ 112 auto message = searchErrors(errors, expectations); \ 113 BOOST_CHECK_MESSAGE(message.empty(), message); \ 114 } while(0) 115 116 // [checkError(text, type, substring)] asserts that the compilation down to typechecking 117 // emits an error of type [type] and with a message containing [substring]. 118 #define CHECK_ERROR(text, type, substring) \ 119 CHECK_ERROR_OR_WARNING(text, type, std::vector<std::string>{(substring)}, false, false) 120 121 // [checkError(text, type, substring)] asserts that the compilation down to typechecking 122 // emits multiple errors of the same type [type] and with a messages containing [substrings]. 123 // Because of the limitations of the preprocessor, you cannot use {{T1, "abc"}, {T2, "def"}} as arguments, 124 // but have to replace them by (std::vector<std::pair<Error::Type, std::string>>{"abc", "def"}) 125 // (note the parentheses) 126 #define CHECK_ERROR_ALLOW_MULTI(text, type, substrings) \ 127 CHECK_ERROR_OR_WARNING(text, type, substrings, false, true) 128 129 // [checkWarning(text, substring)] asserts that the compilation down to typechecking 130 // emits a warning and with a message containing [substring]. 131 #define CHECK_WARNING(text, substring) \ 132 CHECK_ERROR_OR_WARNING(text, Warning, std::vector<std::string>{(substring)}, true, false) 133 134 // [checkWarningAllowMulti(text, substring)] aserts that the compilation down to typechecking 135 // emits a warning and with a message containing [substring]. 136 // Because of the limitations of the preprocessor, you cannot use {"abc", "def"} as arguments, 137 // but have to replace them by (std::vector<std::string>{"abc", "def"}) (note the parentheses) 138 #define CHECK_WARNING_ALLOW_MULTI(text, substrings) \ 139 CHECK_ERROR_OR_WARNING(text, Warning, substrings, true, true) 140 141 // [checkSuccess(text)] asserts that the compilation down to typechecking succeeds. 142 #define CHECK_SUCCESS(text) do { BOOST_CHECK(success((text))); } while(0) 143 144 #define CHECK_SUCCESS_NO_WARNINGS(text) \ 145 do \ 146 { \ 147 auto sourceAndError = parseAnalyseAndReturnError((text), true); \ 148 std::string message; \ 149 if (!sourceAndError.second.empty()) \ 150 message = formatErrors();\ 151 BOOST_CHECK_MESSAGE(sourceAndError.second.empty(), message); \ 152 } \ 153 while(0) 154 155 } 156