Coverage Report

Created: 2026-07-13 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libsolidity/ast/ASTUtils.cpp
Line
Count
Source
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
#include <libsolidity/analysis/ConstantEvaluator.h>
20
#include <libsolidity/ast/AST.h>
21
#include <libsolidity/ast/ASTUtils.h>
22
#include <libsolidity/ast/ASTVisitor.h>
23
24
#include <libsolutil/Algorithms.h>
25
26
namespace solidity::frontend
27
{
28
29
ASTNode const* locateInnermostASTNode(int _offsetInFile, SourceUnit const& _sourceUnit)
30
0
{
31
0
  ASTNode const* innermostMatch = nullptr;
32
0
  auto locator = SimpleASTVisitor(
33
0
    [&](ASTNode const& _node) -> bool
34
0
    {
35
      // In the AST parent location always covers the whole child location.
36
      // The parent is visited first so to get the innermost node we simply
37
      // take the last one that still contains the offset.
38
39
0
      if (!_node.location().containsOffset(_offsetInFile))
40
0
        return false;
41
42
0
      innermostMatch = &_node;
43
0
      return true;
44
0
    },
45
0
    [](ASTNode const&) {}
46
0
  );
47
0
  _sourceUnit.accept(locator);
48
0
  return innermostMatch;
49
0
}
50
51
bool isConstantVariableRecursive(VariableDeclaration const& _varDecl)
52
285
{
53
285
  solAssert(_varDecl.isConstant(), "Constant variable expected");
54
55
285
  auto visitor = [](VariableDeclaration const& _variable, util::CycleDetector<VariableDeclaration>& _cycleDetector, size_t _depth)
56
303
  {
57
303
    solAssert(_depth < 256, "Recursion depth limit reached");
58
303
    if (!_variable.value())
59
      // This should result in an error later on.
60
4
      return;
61
62
299
    if (auto referencedVarDecl = dynamic_cast<VariableDeclaration const*>(
63
299
      ASTNode::referencedDeclaration(*_variable.value()))
64
299
    )
65
26
      if (referencedVarDecl->isConstant())
66
22
        _cycleDetector.run(*referencedVarDecl);
67
299
  };
68
69
285
  return util::CycleDetector<VariableDeclaration>(visitor).run(_varDecl) != nullptr;
70
285
}
71
72
VariableDeclaration const* rootConstVariableDeclaration(VariableDeclaration const& _varDecl)
73
169
{
74
169
  solAssert(_varDecl.isConstant(), "Constant variable expected");
75
169
  solAssert(!isConstantVariableRecursive(_varDecl), "Recursive declaration");
76
77
169
  VariableDeclaration const* rootDecl = &_varDecl;
78
169
  Identifier const* identifier;
79
176
  while ((identifier = dynamic_cast<Identifier const*>(rootDecl->value().get())))
80
11
  {
81
11
    auto referencedVarDecl = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration);
82
11
    if (!referencedVarDecl || !referencedVarDecl->isConstant())
83
4
      return nullptr;
84
7
    rootDecl = referencedVarDecl;
85
7
  }
86
165
  return rootDecl;
87
169
}
88
89
Expression const* resolveOuterUnaryTuples(Expression const* _expr)
90
8.40k
{
91
8.49k
  while (auto const* tupleExpression = dynamic_cast<TupleExpression const*>(_expr))
92
532
    if (tupleExpression->components().size() == 1)
93
89
      _expr = tupleExpression->components().front().get();
94
443
    else
95
443
      break;
96
8.40k
  return _expr;
97
8.40k
}
98
99
Type const* type(Expression const& _expression)
100
1.54M
{
101
1.54M
  solAssert(!!_expression.annotation().type, "Type requested but not present.");
102
1.54M
  return _expression.annotation().type;
103
1.54M
}
104
105
Type const* type(VariableDeclaration const& _variable)
106
154k
{
107
154k
  solAssert(!!_variable.annotation().type, "Type requested but not present.");
108
154k
  return _variable.annotation().type;
109
154k
}
110
111
bigint contractStorageSizeUpperBound(ContractDefinition const& _contract, VariableDeclaration::Location _location)
112
69.1k
{
113
69.1k
  solAssert(_location == VariableDeclaration::Location::Unspecified || _location == VariableDeclaration::Location::Transient);
114
115
69.1k
  bigint size = 0;
116
69.1k
  for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
117
83.0k
    for (VariableDeclaration const* variable: contract->stateVariables())
118
36.2k
      if (
119
36.2k
        !(variable->isConstant() || variable->immutable()) &&
120
32.3k
        variable->referenceLocation() == _location
121
36.2k
      )
122
20.3k
        size += variable->annotation().type->storageSizeUpperBound();
123
124
69.1k
  return size;
125
69.1k
}
126
127
u256 layoutBaseForInheritanceHierarchy(ContractDefinition const& _topLevelContract, DataLocation _location)
128
82.7k
{
129
82.7k
  if (_location != DataLocation::Storage)
130
32.7k
  {
131
32.7k
    solAssert(_location == DataLocation::Transient);
132
32.7k
    return 0;
133
32.7k
  }
134
135
50.0k
  if (auto const* storageLayoutSpecifier = _topLevelContract.storageLayoutSpecifier())
136
0
    return *storageLayoutSpecifier->annotation().baseSlot;
137
138
50.0k
  return 0;
139
50.0k
}
140
141
std::optional<u256> erc7201CompileTimeValue(FunctionCall const& _erc7201Call)
142
0
{
143
0
  auto const* erc7201Function = dynamic_cast<MagicVariableDeclaration const*>(ASTNode::referencedDeclaration(_erc7201Call.expression()));
144
0
  solAssert(erc7201Function);
145
0
  solAssert(erc7201Function->functionType(true /* internal */)->kind() == FunctionType::Kind::ERC7201);
146
147
0
  auto evaluatedResult = ConstantEvaluator::tryEvaluate(_erc7201Call);
148
149
0
  if (std::holds_alternative<std::monostate>(evaluatedResult.value))
150
0
    return std::nullopt;
151
152
0
  solAssert(std::holds_alternative<rational>(evaluatedResult.value));
153
0
  auto rationalValue = std::get<rational>(evaluatedResult.value);
154
0
  solAssert(rationalValue.denominator() == 1);
155
0
  bigint baseSlot = rationalValue.numerator();
156
  solAssert(baseSlot <= std::numeric_limits<u256>::max());
157
0
  return u256(baseSlot);
158
0
}
159
}