Coverage Report

Created: 2022-08-24 06:43

/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
}