/src/solidity/liblangutil/Exceptions.h
Line | Count | Source (jump to first uncovered line) |
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 | | * @author Christian <c@ethdev.com> |
20 | | * @date 2014 |
21 | | * Solidity exception hierarchy. |
22 | | */ |
23 | | |
24 | | #pragma once |
25 | | |
26 | | #include <libsolutil/Exceptions.h> |
27 | | #include <libsolutil/Assertions.h> |
28 | | #include <libsolutil/CommonData.h> |
29 | | #include <liblangutil/SourceLocation.h> |
30 | | |
31 | | #include <boost/preprocessor/cat.hpp> |
32 | | #include <boost/preprocessor/facilities/empty.hpp> |
33 | | #include <boost/preprocessor/facilities/overload.hpp> |
34 | | |
35 | | #include <string> |
36 | | #include <utility> |
37 | | #include <vector> |
38 | | #include <memory> |
39 | | |
40 | | namespace solidity::langutil |
41 | | { |
42 | | class Error; |
43 | | using ErrorList = std::vector<std::shared_ptr<Error const>>; |
44 | | |
45 | | struct CompilerError: virtual util::Exception {}; |
46 | | struct StackTooDeepError: virtual CompilerError {}; |
47 | | struct InternalCompilerError: virtual util::Exception {}; |
48 | | struct FatalError: virtual util::Exception {}; |
49 | | struct UnimplementedFeatureError: virtual util::Exception {}; |
50 | | struct InvalidAstError: virtual util::Exception {}; |
51 | | |
52 | | |
53 | | /// Assertion that throws an InternalCompilerError containing the given description if it is not met. |
54 | | #if !BOOST_PP_VARIADICS_MSVC |
55 | 400k | #define solAssert(...) BOOST_PP_OVERLOAD(solAssert_,__VA_ARGS__)(__VA_ARGS__) |
56 | | #else |
57 | | #define solAssert(...) BOOST_PP_CAT(BOOST_PP_OVERLOAD(solAssert_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY()) |
58 | | #endif |
59 | | |
60 | | #define solAssert_1(CONDITION) \ |
61 | 687k | solAssert_2((CONDITION), "") |
62 | | |
63 | | #define solAssert_2(CONDITION, DESCRIPTION) \ |
64 | 75.4M | assertThrowWithDefaultDescription( \ |
65 | 75.9M | (CONDITION), \ |
66 | 75.9M | ::solidity::langutil::InternalCompilerError, \ |
67 | 75.9M | (DESCRIPTION), \ |
68 | 75.9M | "Solidity assertion failed" \ |
69 | 75.9M | ) |
70 | | |
71 | | |
72 | | /// Assertion that throws an UnimplementedFeatureError containing the given description if it is not met. |
73 | | #if !BOOST_PP_VARIADICS_MSVC |
74 | 259 | #define solUnimplementedAssert(...) BOOST_PP_OVERLOAD(solUnimplementedAssert_,__VA_ARGS__)(__VA_ARGS__) |
75 | | #else |
76 | | #define solUnimplementedAssert(...) BOOST_PP_CAT(BOOST_PP_OVERLOAD(solUnimplementedAssert_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY()) |
77 | | #endif |
78 | | |
79 | | #define solUnimplementedAssert_1(CONDITION) \ |
80 | 10.8k | solUnimplementedAssert_2((CONDITION), "") |
81 | | |
82 | | #define solUnimplementedAssert_2(CONDITION, DESCRIPTION) \ |
83 | 76.9k | assertThrowWithDefaultDescription( \ |
84 | 143k | (CONDITION), \ |
85 | 143k | ::solidity::langutil::UnimplementedFeatureError, \ |
86 | 143k | (DESCRIPTION), \ |
87 | 143k | "Unimplemented feature" \ |
88 | 143k | ) |
89 | | |
90 | | |
91 | | /// Helper that unconditionally reports an unimplemented feature. |
92 | | #define solUnimplemented(DESCRIPTION) \ |
93 | 67.0k | solUnimplementedAssert(false, DESCRIPTION) |
94 | | |
95 | | |
96 | | /// Assertion that throws an InvalidAstError containing the given description if it is not met. |
97 | | #if !BOOST_PP_VARIADICS_MSVC |
98 | 0 | #define astAssert(...) BOOST_PP_OVERLOAD(astAssert_,__VA_ARGS__)(__VA_ARGS__) |
99 | | #else |
100 | | #define astAssert(...) BOOST_PP_CAT(BOOST_PP_OVERLOAD(astAssert_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY()) |
101 | | #endif |
102 | | |
103 | | #define astAssert_1(CONDITION) \ |
104 | 0 | astAssert_2(CONDITION, "") |
105 | | |
106 | | #define astAssert_2(CONDITION, DESCRIPTION) \ |
107 | 0 | assertThrowWithDefaultDescription( \ |
108 | 0 | (CONDITION), \ |
109 | 0 | ::solidity::langutil::InvalidAstError, \ |
110 | 0 | (DESCRIPTION), \ |
111 | 0 | "AST assertion failed" \ |
112 | 0 | ) |
113 | | |
114 | | |
115 | | using errorSourceLocationInfo = std::pair<std::string, SourceLocation>; |
116 | | |
117 | | class SecondarySourceLocation |
118 | | { |
119 | | public: |
120 | | SecondarySourceLocation& append(std::string const& _errMsg, SourceLocation const& _sourceLocation) |
121 | 10.0k | { |
122 | 10.0k | infos.emplace_back(_errMsg, _sourceLocation); |
123 | 10.0k | return *this; |
124 | 10.0k | } |
125 | | SecondarySourceLocation& append(SecondarySourceLocation&& _other) |
126 | 0 | { |
127 | 0 | infos += std::move(_other.infos); |
128 | 0 | return *this; |
129 | 0 | } |
130 | | |
131 | | /// Limits the number of secondary source locations to 32 and appends a notice to the |
132 | | /// error message. |
133 | | void limitSize(std::string& _message) |
134 | 297 | { |
135 | 297 | size_t occurrences = infos.size(); |
136 | 297 | if (occurrences > 32) |
137 | 0 | { |
138 | 0 | infos.resize(32); |
139 | 0 | _message += " Truncated from " + std::to_string(occurrences) + " to the first 32 occurrences."; |
140 | 0 | } |
141 | 297 | } |
142 | | |
143 | | std::vector<errorSourceLocationInfo> infos; |
144 | | }; |
145 | | |
146 | | using errinfo_sourceLocation = boost::error_info<struct tag_sourceLocation, SourceLocation>; |
147 | | using errinfo_secondarySourceLocation = boost::error_info<struct tag_secondarySourceLocation, SecondarySourceLocation>; |
148 | | |
149 | | /** |
150 | | * Unique identifiers are used to tag and track individual error cases. |
151 | | * They are passed as the first parameter of error reporting functions. |
152 | | * Suffix _error helps to find them in the sources. |
153 | | * The struct ErrorId prevents incidental calls like typeError(3141) instead of typeError(3141_error). |
154 | | * To create a new ID, one can add 0000_error and then run "python ./scripts/error_codes.py --fix" |
155 | | * from the root of the repo. |
156 | | */ |
157 | | struct ErrorId |
158 | | { |
159 | | unsigned long long error = 0; |
160 | 0 | bool operator==(ErrorId const& _rhs) const { return error == _rhs.error; } |
161 | 0 | bool operator!=(ErrorId const& _rhs) const { return !(*this == _rhs); } |
162 | 117k | bool operator<(ErrorId const& _rhs) const { return error < _rhs.error; } |
163 | | }; |
164 | 141k | constexpr ErrorId operator"" _error(unsigned long long _error) { return ErrorId{ _error }; } |
165 | | |
166 | | class Error: virtual public util::Exception |
167 | | { |
168 | | public: |
169 | | enum class Type |
170 | | { |
171 | | CodeGenerationError, |
172 | | DeclarationError, |
173 | | DocstringParsingError, |
174 | | ParserError, |
175 | | TypeError, |
176 | | SyntaxError, |
177 | | Warning, |
178 | | Info |
179 | | }; |
180 | | |
181 | | enum class Severity |
182 | | { |
183 | | Error, |
184 | | Warning, |
185 | | Info |
186 | | }; |
187 | | |
188 | | Error( |
189 | | ErrorId _errorId, |
190 | | Type _type, |
191 | | std::string const& _description, |
192 | | SourceLocation const& _location = SourceLocation(), |
193 | | SecondarySourceLocation const& _secondaryLocation = SecondarySourceLocation() |
194 | | ); |
195 | | |
196 | 0 | ErrorId errorId() const { return m_errorId; } |
197 | 522k | Type type() const { return m_type; } |
198 | 0 | std::string const& typeName() const { return m_typeName; } |
199 | | |
200 | | SourceLocation const* sourceLocation() const noexcept; |
201 | | SecondarySourceLocation const* secondarySourceLocation() const noexcept; |
202 | | |
203 | | /// helper functions |
204 | | static Error const* containsErrorOfType(ErrorList const& _list, Error::Type _type) |
205 | 0 | { |
206 | 0 | for (auto e: _list) |
207 | 0 | if (e->type() == _type) |
208 | 0 | return e.get(); |
209 | 0 | return nullptr; |
210 | 0 | } |
211 | | |
212 | | static constexpr Severity errorSeverity(Type _type) |
213 | 522k | { |
214 | 522k | if (_type == Type::Info) |
215 | 0 | return Severity::Info; |
216 | 522k | if (_type == Type::Warning) |
217 | 511k | return Severity::Warning; |
218 | 10.3k | return Severity::Error; |
219 | 522k | } |
220 | | |
221 | | static bool isError(Severity _severity) |
222 | 522k | { |
223 | 522k | return _severity == Severity::Error; |
224 | 522k | } |
225 | | |
226 | | static bool isError(Type _type) |
227 | 522k | { |
228 | 522k | return isError(errorSeverity(_type)); |
229 | 522k | } |
230 | | |
231 | | static bool containsErrors(ErrorList const& _list) |
232 | 133k | { |
233 | 133k | for (auto e: _list) |
234 | 522k | if (isError(e->type())) |
235 | 10.3k | return true; |
236 | 123k | return false; |
237 | 133k | } |
238 | | |
239 | | static std::string formatErrorSeverity(Severity _severity) |
240 | 0 | { |
241 | 0 | if (_severity == Severity::Info) |
242 | 0 | return "Info"; |
243 | 0 | if (_severity == Severity::Warning) |
244 | 0 | return "Warning"; |
245 | 0 | solAssert(isError(_severity), ""); |
246 | 0 | return "Error"; |
247 | 0 | } |
248 | | |
249 | | static std::string formatErrorSeverityLowercase(Severity _severity) |
250 | 0 | { |
251 | 0 | switch (_severity) |
252 | 0 | { |
253 | 0 | case Severity::Info: |
254 | 0 | return "info"; |
255 | 0 | case Severity::Warning: |
256 | 0 | return "warning"; |
257 | 0 | case Severity::Error: |
258 | 0 | solAssert(isError(_severity), ""); |
259 | 0 | return "error"; |
260 | 0 | } |
261 | 0 | solAssert(false, ""); |
262 | 0 | } |
263 | | |
264 | | static std::optional<Severity> severityFromString(std::string _input); |
265 | | |
266 | | private: |
267 | | ErrorId m_errorId; |
268 | | Type m_type; |
269 | | std::string m_typeName; |
270 | | }; |
271 | | |
272 | | } |