Coverage Report

Created: 2025-06-24 07:59

/src/solidity/libyul/Utilities.cpp
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
 * Some useful snippets for the optimiser.
20
 */
21
22
#include <libyul/Utilities.h>
23
24
#include <libyul/backends/evm/EVMDialect.h>
25
26
#include <libyul/AST.h>
27
#include <libyul/Dialect.h>
28
#include <libyul/Exceptions.h>
29
30
#include <libsolutil/CommonData.h>
31
#include <libsolutil/FixedHash.h>
32
#include <libsolutil/Visitor.h>
33
34
#include <boost/algorithm/string.hpp>
35
36
#include <algorithm>
37
#include <sstream>
38
#include <vector>
39
40
using namespace solidity;
41
using namespace solidity::yul;
42
using namespace solidity::util;
43
44
std::string solidity::yul::reindent(std::string const& _code)
45
12.4k
{
46
12.4k
  int constexpr indentationWidth = 4;
47
48
12.4k
  auto constexpr static countBraces = [](std::string const& _s) noexcept -> int
49
3.29M
  {
50
3.29M
    auto const i = _s.find("//");
51
3.29M
    auto const e = i == _s.npos ? end(_s) : next(begin(_s), static_cast<ptrdiff_t>(i));
52
79.4M
    auto const opening = count_if(begin(_s), e, [](auto ch) { return ch == '{' || ch == '('; });
53
79.4M
    auto const closing = count_if(begin(_s), e, [](auto ch) { return ch == '}' || ch == ')'; });
54
3.29M
    return int(opening - closing);
55
3.29M
  };
56
57
12.4k
  std::vector<std::string> lines;
58
12.4k
  boost::split(lines, _code, boost::is_any_of("\n"));
59
12.4k
  for (std::string& line: lines)
60
3.46M
    boost::trim(line);
61
62
  // Reduce multiple consecutive empty lines.
63
3.46M
  lines = fold(lines, std::vector<std::string>{}, [](auto&& _lines, auto&& _line) {
64
3.46M
    if (!(_line.empty() && !_lines.empty() && _lines.back().empty()))
65
3.29M
      _lines.emplace_back(std::move(_line));
66
3.46M
    return std::move(_lines);
67
3.46M
  });
68
69
12.4k
  std::stringstream out;
70
12.4k
  int depth = 0;
71
72
12.4k
  for (std::string const& line: lines)
73
3.29M
  {
74
3.29M
    int const diff = countBraces(line);
75
3.29M
    if (diff < 0)
76
506k
      depth += diff;
77
78
3.29M
    if (!line.empty())
79
2.38M
    {
80
27.3M
      for (int i = 0; i < depth * indentationWidth; ++i)
81
24.9M
        out << ' ';
82
2.38M
      out << line;
83
2.38M
    }
84
3.29M
    out << '\n';
85
86
3.29M
    if (diff > 0)
87
506k
      depth += diff;
88
3.29M
  }
89
90
12.4k
  return out.str();
91
12.4k
}
92
93
LiteralValue solidity::yul::valueOfNumberLiteral(std::string_view const _literal)
94
30.4M
{
95
30.4M
  return LiteralValue{LiteralValue::Data(_literal), std::string(_literal)};
96
30.4M
}
97
98
LiteralValue solidity::yul::valueOfStringLiteral(std::string_view const _literal)
99
220k
{
100
220k
  std::string const s(_literal);
101
220k
  return LiteralValue{u256(h256(s, h256::FromBinary, h256::AlignLeft)), s};
102
220k
}
103
104
LiteralValue solidity::yul::valueOfBuiltinStringLiteralArgument(std::string_view _literal)
105
45.1k
{
106
45.1k
  return LiteralValue{std::string(_literal)};
107
45.1k
}
108
109
LiteralValue solidity::yul::valueOfBoolLiteral(std::string_view const _literal)
110
19.2k
{
111
19.2k
  if (_literal == "true")
112
16.6k
    return LiteralValue{true};
113
2.57k
  else if (_literal == "false")
114
2.57k
    return LiteralValue{false};
115
116
0
  yulAssert(false, "Unexpected bool literal value!");
117
0
}
118
119
LiteralValue solidity::yul::valueOfLiteral(std::string_view const _literal, LiteralKind const& _kind, bool const _unlimitedLiteralArgument)
120
30.6M
{
121
30.6M
  switch (_kind)
122
30.6M
  {
123
30.4M
  case LiteralKind::Number:
124
30.4M
    return valueOfNumberLiteral(_literal);
125
19.2k
  case LiteralKind::Boolean:
126
19.2k
    return valueOfBoolLiteral(_literal);
127
265k
  case LiteralKind::String:
128
265k
    return _unlimitedLiteralArgument ? valueOfBuiltinStringLiteralArgument(_literal) : valueOfStringLiteral(_literal);
129
30.6M
  }
130
0
  util::unreachable();
131
0
}
132
133
std::string solidity::yul::formatLiteral(solidity::yul::Literal const& _literal, bool const _validated)
134
4.23M
{
135
4.23M
  if (_validated)
136
4.23M
    yulAssert(validLiteral(_literal), "Encountered invalid literal in formatLiteral.");
137
138
4.23M
  if (_literal.value.unlimited())
139
180k
    return _literal.value.builtinStringLiteralValue();
140
141
4.05M
  if (_literal.value.hint())
142
3.65M
    return *_literal.value.hint();
143
144
403k
  if (_literal.kind == LiteralKind::Boolean)
145
10.5k
    return _literal.value.value() == false ? "false" : "true";
146
147
  // if there is no hint and it is not a boolean, just stringify the u256 word
148
392k
  return _literal.value.value().str();
149
403k
}
150
151
bool solidity::yul::validLiteral(solidity::yul::Literal const& _literal)
152
26.2M
{
153
26.2M
  switch (_literal.kind)
154
26.2M
  {
155
25.7M
  case LiteralKind::Number:
156
25.7M
    return validNumberLiteral(_literal);
157
79.9k
  case LiteralKind::Boolean:
158
79.9k
    return validBoolLiteral(_literal);
159
388k
  case LiteralKind::String:
160
388k
    return validStringLiteral(_literal);
161
26.2M
  }
162
0
  util::unreachable();
163
0
}
164
165
bool solidity::yul::validStringLiteral(solidity::yul::Literal const& _literal)
166
388k
{
167
388k
  if (_literal.kind != LiteralKind::String)
168
0
    return false;
169
170
388k
  if (_literal.value.unlimited())
171
216k
    return true;
172
173
171k
  if (_literal.value.hint())
174
171k
    return _literal.value.hint()->size() <= 32 && _literal.value.value() == valueOfLiteral(*_literal.value.hint(), _literal.kind).value();
175
176
0
  return true;
177
171k
}
178
179
bool solidity::yul::validNumberLiteral(solidity::yul::Literal const& _literal)
180
25.7M
{
181
25.7M
  if (_literal.kind != LiteralKind::Number || _literal.value.unlimited())
182
0
    return false;
183
184
25.7M
  if (!_literal.value.hint())
185
2.03M
    return true;
186
187
23.7M
  auto const& repr = *_literal.value.hint();
188
189
23.7M
  if (!isValidDecimal(repr) && !isValidHex(repr))
190
0
    return false;
191
192
23.7M
  if (bigint(repr) > u256(-1))
193
132
    return false;
194
195
23.7M
  if (_literal.value.value() != valueOfLiteral(repr, _literal.kind).value())
196
0
    return false;
197
198
23.7M
  return true;
199
23.7M
}
200
201
bool solidity::yul::validBoolLiteral(solidity::yul::Literal const& _literal)
202
79.9k
{
203
79.9k
  if (_literal.kind != LiteralKind::Boolean || _literal.value.unlimited())
204
0
    return false;
205
206
79.9k
  if (_literal.value.hint() && !(*_literal.value.hint() == "true" || *_literal.value.hint() == "false"))
207
0
    return false;
208
209
79.9k
  yulAssert(u256(0) == u256(false));
210
79.9k
  yulAssert(u256(1) == u256(true));
211
212
79.9k
  if (_literal.value.hint())
213
0
  {
214
0
    if (*_literal.value.hint() == "false")
215
0
      return _literal.value.value() == false;
216
0
    else
217
0
      return _literal.value.value() == true;
218
0
  }
219
220
79.9k
  return _literal.value.value() == true || _literal.value.value() == false;
221
79.9k
}
222
223
template<>
224
bool Less<Literal>::operator()(Literal const& _lhs, Literal const& _rhs) const
225
713k
{
226
713k
  if (_lhs.kind != _rhs.kind)
227
70.7k
    return _lhs.kind < _rhs.kind;
228
229
642k
  if (_lhs.value.unlimited() && _rhs.value.unlimited())
230
642k
    yulAssert(
231
642k
      _lhs.kind == LiteralKind::String && _rhs.kind == LiteralKind::String,
232
642k
      "Cannot have unlimited value that is not of String kind."
233
642k
    );
234
235
642k
  return _lhs.value < _rhs.value;
236
237
642k
}
238
239
bool SwitchCaseCompareByLiteralValue::operator()(Case const* _lhs, Case const* _rhs) const
240
802k
{
241
802k
  yulAssert(_lhs && _rhs, "");
242
802k
  return Less<Literal*>{}(_lhs->value.get(), _rhs->value.get());
243
802k
}
244
245
std::string_view yul::resolveFunctionName(FunctionName const& _functionName, Dialect const& _dialect)
246
15.5M
{
247
15.5M
  GenericVisitor visitor{
248
15.5M
    [&](Identifier const& _identifier) -> std::string const& { return _identifier.name.str(); },
249
15.5M
    [&](BuiltinName const& _builtin) -> std::string const& { return _dialect.builtin(_builtin.handle).name; }
250
15.5M
  };
251
15.5M
  return std::visit(visitor, _functionName);
252
15.5M
}
253
254
BuiltinFunction const* yul::resolveBuiltinFunction(FunctionName const& _functionName, Dialect const& _dialect)
255
344M
{
256
344M
  GenericVisitor visitor{
257
344M
    [&](Identifier const&) -> BuiltinFunction const* { return nullptr; },
258
344M
    [&](BuiltinName const& _builtin) -> BuiltinFunction const* { return &_dialect.builtin(_builtin.handle); }
259
344M
  };
260
344M
  return std::visit(visitor, _functionName);
261
344M
}
262
263
BuiltinFunctionForEVM const* yul::resolveBuiltinFunctionForEVM(FunctionName const& _functionName, EVMDialect const& _dialect)
264
140M
{
265
140M
  GenericVisitor visitor{
266
140M
    [&](Identifier const&) -> BuiltinFunctionForEVM const* { return nullptr; },
267
140M
    [&](BuiltinName const& _builtin) -> BuiltinFunctionForEVM const* { return &_dialect.builtin(_builtin.handle); }
268
140M
  };
269
140M
  return std::visit(visitor, _functionName);
270
140M
}
271
272
FunctionHandle yul::functionNameToHandle(FunctionName const& _functionName)
273
154M
{
274
154M
  GenericVisitor visitor{
275
154M
    [&](Identifier const& _identifier) -> FunctionHandle { return _identifier.name; },
276
154M
    [&](BuiltinName const& _builtin) -> FunctionHandle { return _builtin.handle; }
277
154M
  };
278
154M
  return std::visit(visitor, _functionName);
279
154M
}
280