Coverage Report

Created: 2025-06-24 07:59

/src/solidity/libsolidity/analysis/OverrideChecker.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
 * Component that verifies overloads, abstract contracts, function clashes and others
20
 * checks at contract or function level.
21
 */
22
23
#include <libsolidity/analysis/OverrideChecker.h>
24
25
#include <libsolidity/ast/AST.h>
26
#include <libsolidity/ast/TypeProvider.h>
27
#include <libsolidity/analysis/TypeChecker.h>
28
#include <liblangutil/ErrorReporter.h>
29
#include <libsolutil/Visitor.h>
30
31
#include <boost/algorithm/string/predicate.hpp>
32
33
34
using namespace solidity;
35
using namespace solidity::frontend;
36
using namespace solidity::langutil;
37
38
using solidity::util::GenericVisitor;
39
using solidity::util::contains_if;
40
using solidity::util::joinHumanReadable;
41
42
namespace
43
{
44
45
// Helper struct to do a search by name
46
struct MatchByName
47
{
48
  std::string const& m_name;
49
  bool operator()(OverrideProxy const& _item)
50
299
  {
51
299
    return _item.name() == m_name;
52
299
  }
53
};
54
55
/**
56
 * Construct the override graph for this signature.
57
 * Reserve node 0 for the current contract and node
58
 * 1 for an artificial top node to which all override paths
59
 * connect at the end.
60
 */
61
struct OverrideGraph
62
{
63
  OverrideGraph(std::set<OverrideProxy> const& _baseCallables)
64
150
  {
65
150
    for (auto const& baseFunction: _baseCallables)
66
305
      addEdge(0, visit(baseFunction));
67
150
  }
68
  std::map<OverrideProxy, int> nodes;
69
  std::map<int, OverrideProxy> nodeInv;
70
  std::map<int, std::set<int>> edges;
71
  size_t numNodes = 2;
72
  void addEdge(int _a, int _b)
73
649
  {
74
649
    edges[_a].insert(_b);
75
649
    edges[_b].insert(_a);
76
649
  }
77
private:
78
  /// Completes the graph starting from @a _function and
79
  /// @returns the node ID.
80
  int visit(OverrideProxy const& _function)
81
424
  {
82
424
    auto it = nodes.find(_function);
83
424
    if (it != nodes.end())
84
92
      return it->second;
85
332
    int currentNode = static_cast<int>(numNodes++);
86
332
    nodes[_function] = currentNode;
87
332
    nodeInv[currentNode] = _function;
88
89
332
    if (!_function.baseFunctions().empty())
90
107
      for (auto const& baseFunction: _function.baseFunctions())
91
119
        addEdge(currentNode, visit(baseFunction));
92
225
    else
93
225
      addEdge(currentNode, 1);
94
95
332
    return currentNode;
96
424
  }
97
};
98
99
/**
100
 * Detect cut vertices following https://en.wikipedia.org/wiki/Biconnected_component#Pseudocode
101
 * Can ignore the root node, since it is never a cut vertex in our case.
102
 */
103
struct CutVertexFinder
104
{
105
  CutVertexFinder(OverrideGraph const& _graph): m_graph(_graph)
106
150
  {
107
150
    run();
108
150
  }
109
150
  std::set<OverrideProxy> const& cutVertices() const { return m_cutVertices; }
110
111
private:
112
  OverrideGraph const& m_graph;
113
114
  std::vector<bool> m_visited = std::vector<bool>(m_graph.numNodes, false);
115
  std::vector<int> m_depths = std::vector<int>(m_graph.numNodes, -1);
116
  std::vector<int> m_low = std::vector<int>(m_graph.numNodes, -1);
117
  std::vector<int> m_parent = std::vector<int>(m_graph.numNodes, -1);
118
  std::set<OverrideProxy> m_cutVertices{};
119
120
  void run(size_t _u = 0, size_t _depth = 0)
121
632
  {
122
632
    m_visited.at(_u) = true;
123
632
    m_depths.at(_u) = m_low.at(_u) = static_cast<int>(_depth);
124
632
    for (int const v: m_graph.edges.at(static_cast<int>(_u)))
125
1.29k
    {
126
1.29k
      auto const vInd = static_cast<size_t>(v);
127
1.29k
      if (!m_visited.at(vInd))
128
482
      {
129
482
        m_parent[vInd] = static_cast<int>(_u);
130
482
        run(vInd, _depth + 1);
131
482
        if (m_low[vInd] >= m_depths[_u] && m_parent[_u] != -1)
132
86
          m_cutVertices.insert(m_graph.nodeInv.at(static_cast<int>(_u)));
133
482
        m_low[_u] = std::min(m_low[_u], m_low[vInd]);
134
482
      }
135
816
      else if (v != m_parent[_u])
136
334
        m_low[_u] = std::min(m_low[_u], m_depths[vInd]);
137
1.29k
    }
138
632
  }
139
};
140
141
std::vector<ContractDefinition const*> resolveDirectBaseContracts(ContractDefinition const& _contract)
142
53.0k
{
143
53.0k
  std::vector<ContractDefinition const*> resolvedContracts;
144
145
53.0k
  for (ASTPointer<InheritanceSpecifier> const& specifier: _contract.baseContracts())
146
9.13k
  {
147
9.13k
    Declaration const* baseDecl =
148
9.13k
      specifier->name().annotation().referencedDeclaration;
149
9.13k
    auto contract = dynamic_cast<ContractDefinition const*>(baseDecl);
150
9.13k
    if (contract)
151
9.13k
      resolvedContracts.emplace_back(contract);
152
9.13k
  }
153
154
53.0k
  return resolvedContracts;
155
53.0k
}
156
157
std::vector<ASTPointer<IdentifierPath>> sortByContract(std::vector<ASTPointer<IdentifierPath>> const& _list)
158
106
{
159
106
  auto sorted = _list;
160
161
106
  stable_sort(sorted.begin(), sorted.end(),
162
2.39k
    [] (ASTPointer<IdentifierPath> _a, ASTPointer<IdentifierPath> _b) {
163
2.39k
      if (!_a || !_b)
164
0
        return _a < _b;
165
166
2.39k
      Declaration const* aDecl = _a->annotation().referencedDeclaration;
167
2.39k
      Declaration const* bDecl = _b->annotation().referencedDeclaration;
168
169
2.39k
      if (!aDecl || !bDecl)
170
0
        return aDecl < bDecl;
171
172
2.39k
      return aDecl->id() < bDecl->id();
173
2.39k
    }
174
106
  );
175
176
106
  return sorted;
177
106
}
178
179
OverrideProxy makeOverrideProxy(CallableDeclaration const& _callable)
180
253
{
181
253
  if (auto const* fun = dynamic_cast<FunctionDefinition const*>(&_callable))
182
222
    return OverrideProxy{fun};
183
31
  else if (auto const* mod = dynamic_cast<ModifierDefinition const*>(&_callable))
184
31
    return OverrideProxy{mod};
185
0
  else
186
31
    solAssert(false, "Invalid call to makeOverrideProxy.");
187
0
  return {};
188
253
}
189
190
}
191
192
bool OverrideProxy::operator<(OverrideProxy const& _other) const
193
1.75k
{
194
1.75k
  return id() < _other.id();
195
1.75k
}
196
197
bool OverrideProxy::isVariable() const
198
4.23k
{
199
4.23k
  return std::holds_alternative<VariableDeclaration const*>(m_item);
200
4.23k
}
201
202
bool OverrideProxy::isFunction() const
203
6.86k
{
204
6.86k
  return std::holds_alternative<FunctionDefinition const*>(m_item);
205
6.86k
}
206
207
bool OverrideProxy::isModifier() const
208
6.63k
{
209
6.63k
  return std::holds_alternative<ModifierDefinition const*>(m_item);
210
6.63k
}
211
212
bool OverrideProxy::CompareBySignature::operator()(OverrideProxy const& _a, OverrideProxy const& _b) const
213
151k
{
214
151k
  return _a.overrideComparator() < _b.overrideComparator();
215
151k
}
216
217
size_t OverrideProxy::id() const
218
3.50k
{
219
3.50k
  return std::visit(GenericVisitor{
220
3.50k
    [&](auto const* _item) -> size_t { return static_cast<size_t>(_item->id()); }
OverrideChecker.cpp:unsigned long solidity::frontend::OverrideProxy::id() const::$_1::operator()<solidity::frontend::FunctionDefinition>(solidity::frontend::FunctionDefinition const*) const
Line
Count
Source
220
2.78k
    [&](auto const* _item) -> size_t { return static_cast<size_t>(_item->id()); }
OverrideChecker.cpp:unsigned long solidity::frontend::OverrideProxy::id() const::$_1::operator()<solidity::frontend::ModifierDefinition>(solidity::frontend::ModifierDefinition const*) const
Line
Count
Source
220
528
    [&](auto const* _item) -> size_t { return static_cast<size_t>(_item->id()); }
OverrideChecker.cpp:unsigned long solidity::frontend::OverrideProxy::id() const::$_1::operator()<solidity::frontend::VariableDeclaration>(solidity::frontend::VariableDeclaration const*) const
Line
Count
Source
220
194
    [&](auto const* _item) -> size_t { return static_cast<size_t>(_item->id()); }
221
3.50k
  }, m_item);
222
3.50k
}
223
224
std::shared_ptr<OverrideSpecifier> OverrideProxy::overrides() const
225
94.7k
{
226
94.7k
  return std::visit(GenericVisitor{
227
94.7k
    [&](auto const* _item) { return _item->overrides(); }
OverrideChecker.cpp:auto solidity::frontend::OverrideProxy::overrides() const::$_2::operator()<solidity::frontend::FunctionDefinition>(solidity::frontend::FunctionDefinition const*) const
Line
Count
Source
227
70.6k
    [&](auto const* _item) { return _item->overrides(); }
OverrideChecker.cpp:auto solidity::frontend::OverrideProxy::overrides() const::$_2::operator()<solidity::frontend::ModifierDefinition>(solidity::frontend::ModifierDefinition const*) const
Line
Count
Source
227
10.4k
    [&](auto const* _item) { return _item->overrides(); }
OverrideChecker.cpp:auto solidity::frontend::OverrideProxy::overrides() const::$_2::operator()<solidity::frontend::VariableDeclaration>(solidity::frontend::VariableDeclaration const*) const
Line
Count
Source
227
13.6k
    [&](auto const* _item) { return _item->overrides(); }
228
94.7k
  }, m_item);
229
94.7k
}
230
231
std::set<OverrideProxy> OverrideProxy::baseFunctions() const
232
540
{
233
540
  return std::visit(GenericVisitor{
234
540
    [&](auto const* _item) -> std::set<OverrideProxy> {
235
540
      std::set<OverrideProxy> ret;
236
540
      for (auto const* f: _item->annotation().baseFunctions)
237
253
        ret.insert(makeOverrideProxy(*f));
238
540
      return ret;
239
540
    }
OverrideChecker.cpp:std::__1::set<solidity::frontend::OverrideProxy, std::__1::less<solidity::frontend::OverrideProxy>, std::__1::allocator<solidity::frontend::OverrideProxy> > solidity::frontend::OverrideProxy::baseFunctions() const::$_3::operator()<solidity::frontend::FunctionDefinition>(solidity::frontend::FunctionDefinition const*) const
Line
Count
Source
234
452
    [&](auto const* _item) -> std::set<OverrideProxy> {
235
452
      std::set<OverrideProxy> ret;
236
452
      for (auto const* f: _item->annotation().baseFunctions)
237
216
        ret.insert(makeOverrideProxy(*f));
238
452
      return ret;
239
452
    }
OverrideChecker.cpp:std::__1::set<solidity::frontend::OverrideProxy, std::__1::less<solidity::frontend::OverrideProxy>, std::__1::allocator<solidity::frontend::OverrideProxy> > solidity::frontend::OverrideProxy::baseFunctions() const::$_3::operator()<solidity::frontend::ModifierDefinition>(solidity::frontend::ModifierDefinition const*) const
Line
Count
Source
234
65
    [&](auto const* _item) -> std::set<OverrideProxy> {
235
65
      std::set<OverrideProxy> ret;
236
65
      for (auto const* f: _item->annotation().baseFunctions)
237
31
        ret.insert(makeOverrideProxy(*f));
238
65
      return ret;
239
65
    }
OverrideChecker.cpp:std::__1::set<solidity::frontend::OverrideProxy, std::__1::less<solidity::frontend::OverrideProxy>, std::__1::allocator<solidity::frontend::OverrideProxy> > solidity::frontend::OverrideProxy::baseFunctions() const::$_3::operator()<solidity::frontend::VariableDeclaration>(solidity::frontend::VariableDeclaration const*) const
Line
Count
Source
234
23
    [&](auto const* _item) -> std::set<OverrideProxy> {
235
23
      std::set<OverrideProxy> ret;
236
23
      for (auto const* f: _item->annotation().baseFunctions)
237
6
        ret.insert(makeOverrideProxy(*f));
238
23
      return ret;
239
23
    }
240
540
  }, m_item);
241
540
}
242
243
void OverrideProxy::storeBaseFunction(OverrideProxy const& _base) const
244
1.83k
{
245
1.83k
  std::visit(GenericVisitor{
246
1.83k
    [&](FunctionDefinition const* _item) {
247
826
      _item->annotation().baseFunctions.emplace(std::get<FunctionDefinition const*>(_base.m_item));
248
826
    },
249
1.83k
    [&](ModifierDefinition const* _item) {
250
856
      _item->annotation().baseFunctions.emplace(std::get<ModifierDefinition const*>(_base.m_item));
251
856
    },
252
1.83k
    [&](VariableDeclaration const* _item) {
253
156
      _item->annotation().baseFunctions.emplace(std::get<FunctionDefinition const*>(_base.m_item));
254
156
    }
255
1.83k
  }, m_item);
256
1.83k
}
257
258
std::string const& OverrideProxy::name() const
259
1.04k
{
260
1.04k
  return std::visit(GenericVisitor{
261
1.04k
    [&](auto const* _item) -> std::string const& { return _item->name(); }
OverrideChecker.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const& solidity::frontend::OverrideProxy::name() const::$_7::operator()<solidity::frontend::FunctionDefinition>(solidity::frontend::FunctionDefinition const*) const
Line
Count
Source
261
87
    [&](auto const* _item) -> std::string const& { return _item->name(); }
OverrideChecker.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const& solidity::frontend::OverrideProxy::name() const::$_7::operator()<solidity::frontend::ModifierDefinition>(solidity::frontend::ModifierDefinition const*) const
Line
Count
Source
261
944
    [&](auto const* _item) -> std::string const& { return _item->name(); }
OverrideChecker.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const& solidity::frontend::OverrideProxy::name() const::$_7::operator()<solidity::frontend::VariableDeclaration>(solidity::frontend::VariableDeclaration const*) const
Line
Count
Source
261
13
    [&](auto const* _item) -> std::string const& { return _item->name(); }
262
1.04k
  }, m_item);
263
1.04k
}
264
265
ContractDefinition const& OverrideProxy::contract() const
266
2.37k
{
267
2.37k
  return std::visit(GenericVisitor{
268
2.37k
    [&](auto const* _item) -> ContractDefinition const& {
269
2.37k
      return dynamic_cast<ContractDefinition const&>(*_item->scope());
270
2.37k
    }
OverrideChecker.cpp:solidity::frontend::ContractDefinition const& solidity::frontend::OverrideProxy::contract() const::$_8::operator()<solidity::frontend::FunctionDefinition>(solidity::frontend::FunctionDefinition const*) const
Line
Count
Source
268
1.39k
    [&](auto const* _item) -> ContractDefinition const& {
269
1.39k
      return dynamic_cast<ContractDefinition const&>(*_item->scope());
270
1.39k
    }
OverrideChecker.cpp:solidity::frontend::ContractDefinition const& solidity::frontend::OverrideProxy::contract() const::$_8::operator()<solidity::frontend::ModifierDefinition>(solidity::frontend::ModifierDefinition const*) const
Line
Count
Source
268
892
    [&](auto const* _item) -> ContractDefinition const& {
269
892
      return dynamic_cast<ContractDefinition const&>(*_item->scope());
270
892
    }
OverrideChecker.cpp:solidity::frontend::ContractDefinition const& solidity::frontend::OverrideProxy::contract() const::$_8::operator()<solidity::frontend::VariableDeclaration>(solidity::frontend::VariableDeclaration const*) const
Line
Count
Source
268
85
    [&](auto const* _item) -> ContractDefinition const& {
269
85
      return dynamic_cast<ContractDefinition const&>(*_item->scope());
270
85
    }
271
2.37k
  }, m_item);
272
2.37k
}
273
274
std::string const& OverrideProxy::contractName() const
275
165
{
276
165
  return contract().name();
277
165
}
278
279
Visibility OverrideProxy::visibility() const
280
4.89k
{
281
4.89k
  return std::visit(GenericVisitor{
282
4.89k
    [&](FunctionDefinition const* _item) { return _item->visibility(); },
283
4.89k
    [&](ModifierDefinition const* _item) { return _item->visibility(); },
284
4.89k
    [&](VariableDeclaration const*) { return Visibility::External; }
285
4.89k
  }, m_item);
286
4.89k
}
287
288
StateMutability OverrideProxy::stateMutability() const
289
3.03k
{
290
3.03k
  return std::visit(GenericVisitor{
291
3.03k
    [&](FunctionDefinition const* _item) { return _item->stateMutability(); },
292
3.03k
    [&](ModifierDefinition const*) { solAssert(false, "Requested state mutability from modifier."); return StateMutability{}; },
293
3.03k
    [&](VariableDeclaration const* _var) { return _var->isConstant() ? StateMutability::Pure : StateMutability::View; }
294
3.03k
  }, m_item);
295
3.03k
}
296
297
bool OverrideProxy::virtualSemantics() const
298
1.83k
{
299
1.83k
  return std::visit(GenericVisitor{
300
1.83k
    [&](FunctionDefinition const* _item) { return _item->virtualSemantics(); },
301
1.83k
    [&](ModifierDefinition const* _item) { return _item->virtualSemantics(); },
302
1.83k
    [&](VariableDeclaration const*) { return false; }
303
1.83k
  }, m_item);
304
1.83k
}
305
306
Token OverrideProxy::functionKind() const
307
1.34k
{
308
1.34k
  return std::visit(GenericVisitor{
309
1.34k
    [&](FunctionDefinition const* _item) { return _item->kind(); },
310
1.34k
    [&](ModifierDefinition const*) { return Token::Function; },
311
1.34k
    [&](VariableDeclaration const*) { return Token::Function; }
312
1.34k
  }, m_item);
313
1.34k
}
314
315
FunctionType const* OverrideProxy::externalFunctionType() const
316
26.9k
{
317
26.9k
  return std::visit(GenericVisitor{
318
26.9k
    [&](FunctionDefinition const* _item) { return FunctionType(*_item).asExternallyCallableFunction(false); },
319
26.9k
    [&](VariableDeclaration const* _item) { return FunctionType(*_item).asExternallyCallableFunction(false); },
320
26.9k
    [&](ModifierDefinition const*) -> FunctionType const* { solAssert(false, "Requested function type of modifier."); return nullptr; }
321
26.9k
  }, m_item);
322
26.9k
}
323
324
FunctionType const* OverrideProxy::originalFunctionType() const
325
1.43k
{
326
1.43k
  return std::visit(GenericVisitor{
327
1.43k
    [&](FunctionDefinition const* _item) { return TypeProvider::function(*_item); },
328
1.43k
    [&](VariableDeclaration const*) -> FunctionType const* { solAssert(false, "Requested specific function type of variable."); return nullptr; },
329
1.43k
    [&](ModifierDefinition const*) -> FunctionType const* { solAssert(false, "Requested specific function type of modifier."); return nullptr; }
330
1.43k
  }, m_item);
331
1.43k
}
332
333
ModifierType const* OverrideProxy::modifierType() const
334
1.71k
{
335
1.71k
  return std::visit(GenericVisitor{
336
1.71k
    [&](FunctionDefinition const*) -> ModifierType const* { solAssert(false, "Requested modifier type of function."); return nullptr; },
337
1.71k
    [&](VariableDeclaration const*) -> ModifierType const* { solAssert(false, "Requested modifier type of variable."); return nullptr; },
338
1.71k
    [&](ModifierDefinition const* _modifier) -> ModifierType const* { return TypeProvider::modifier(*_modifier); }
339
1.71k
  }, m_item);
340
1.71k
}
341
342
343
Declaration const* OverrideProxy::declaration() const
344
6.15k
{
345
6.15k
  return std::visit(GenericVisitor{
346
6.15k
    [&](FunctionDefinition const* _function) -> Declaration const* { return _function; },
347
6.15k
    [&](VariableDeclaration const* _variable) -> Declaration const* { return _variable; },
348
6.15k
    [&](ModifierDefinition const* _modifier) -> Declaration const* { return _modifier; }
349
6.15k
  }, m_item);
350
6.15k
}
351
352
SourceLocation const& OverrideProxy::location() const
353
3.82k
{
354
3.82k
  return std::visit(GenericVisitor{
355
3.82k
    [&](auto const* _item) -> SourceLocation const& { return _item->location(); }
OverrideChecker.cpp:solidity::langutil::SourceLocation const& solidity::frontend::OverrideProxy::location() const::$_33::operator()<solidity::frontend::FunctionDefinition>(solidity::frontend::FunctionDefinition const*) const
Line
Count
Source
355
456
    [&](auto const* _item) -> SourceLocation const& { return _item->location(); }
OverrideChecker.cpp:solidity::langutil::SourceLocation const& solidity::frontend::OverrideProxy::location() const::$_33::operator()<solidity::frontend::ModifierDefinition>(solidity::frontend::ModifierDefinition const*) const
Line
Count
Source
355
3.09k
    [&](auto const* _item) -> SourceLocation const& { return _item->location(); }
OverrideChecker.cpp:solidity::langutil::SourceLocation const& solidity::frontend::OverrideProxy::location() const::$_33::operator()<solidity::frontend::VariableDeclaration>(solidity::frontend::VariableDeclaration const*) const
Line
Count
Source
355
275
    [&](auto const* _item) -> SourceLocation const& { return _item->location(); }
356
3.82k
  }, m_item);
357
3.82k
}
358
359
std::string OverrideProxy::astNodeName() const
360
5.30k
{
361
5.30k
  return std::visit(GenericVisitor{
362
5.30k
    [&](FunctionDefinition const*) { return "function"; },
363
5.30k
    [&](ModifierDefinition const*) { return "modifier"; },
364
5.30k
    [&](VariableDeclaration const*) { return "public state variable"; },
365
5.30k
  }, m_item);
366
5.30k
}
367
368
std::string OverrideProxy::astNodeNameCapitalized() const
369
331
{
370
331
  return std::visit(GenericVisitor{
371
331
    [&](FunctionDefinition const*) { return "Function"; },
372
331
    [&](ModifierDefinition const*) { return "Modifier"; },
373
331
    [&](VariableDeclaration const*) { return "Public state variable"; },
374
331
  }, m_item);
375
331
}
376
377
std::string OverrideProxy::distinguishingProperty() const
378
80
{
379
80
  return std::visit(GenericVisitor{
380
80
    [&](FunctionDefinition const*) { return "name and parameter types"; },
381
80
    [&](ModifierDefinition const*) { return "name"; },
382
80
    [&](VariableDeclaration const*) { return "name and parameter types"; },
383
80
  }, m_item);
384
80
}
385
386
bool OverrideProxy::unimplemented() const
387
74.8k
{
388
74.8k
  return std::visit(GenericVisitor{
389
74.8k
    [&](FunctionDefinition const* _item) { return !_item->isImplemented(); },
390
74.8k
    [&](ModifierDefinition const* _item) { return !_item->isImplemented(); },
391
74.8k
    [&](VariableDeclaration const*) { return false; }
392
74.8k
  }, m_item);
393
74.8k
}
394
395
bool OverrideProxy::OverrideComparator::operator<(OverrideComparator const& _other) const
396
151k
{
397
151k
  if (name != _other.name)
398
122k
    return name < _other.name;
399
400
29.5k
  if (!functionKind || !_other.functionKind)
401
11.5k
    return false;
402
403
17.9k
  if (functionKind != _other.functionKind)
404
77
    return *functionKind < *_other.functionKind;
405
406
  // Parameters do not matter for non-regular functions.
407
17.8k
  if (functionKind != Token::Function)
408
637
    return false;
409
410
17.2k
  if (!parameterTypes || !_other.parameterTypes)
411
0
    return false;
412
413
17.2k
  return boost::lexicographical_compare(*parameterTypes, *_other.parameterTypes);
414
17.2k
}
415
416
OverrideProxy::OverrideComparator const& OverrideProxy::overrideComparator() const
417
303k
{
418
303k
  if (!m_comparator)
419
38.5k
  {
420
38.5k
    m_comparator = std::make_shared<OverrideComparator>(std::visit(GenericVisitor{
421
38.5k
      [&](FunctionDefinition const* _function)
422
38.5k
      {
423
19.1k
        std::vector<std::string> paramTypes;
424
19.1k
        for (Type const* t: externalFunctionType()->parameterTypes())
425
10.5k
          paramTypes.emplace_back(t->richIdentifier());
426
19.1k
        return OverrideComparator{
427
19.1k
          _function->name(),
428
19.1k
          _function->kind(),
429
19.1k
          std::move(paramTypes)
430
19.1k
        };
431
19.1k
      },
432
38.5k
      [&](VariableDeclaration const* _var)
433
38.5k
      {
434
5.89k
        std::vector<std::string> paramTypes;
435
5.89k
        for (Type const* t: externalFunctionType()->parameterTypes())
436
970
          paramTypes.emplace_back(t->richIdentifier());
437
5.89k
        return OverrideComparator{
438
5.89k
          _var->name(),
439
5.89k
          Token::Function,
440
5.89k
          std::move(paramTypes)
441
5.89k
        };
442
5.89k
      },
443
38.5k
      [&](ModifierDefinition const* _mod)
444
38.5k
      {
445
13.4k
        return OverrideComparator{
446
13.4k
          _mod->name(),
447
13.4k
          {},
448
13.4k
          {}
449
13.4k
        };
450
13.4k
      }
451
38.5k
    }, m_item));
452
38.5k
  }
453
454
303k
  return *m_comparator;
455
303k
}
456
457
bool OverrideChecker::CompareByID::operator()(ContractDefinition const* _a, ContractDefinition const* _b) const
458
5.79k
{
459
5.79k
  if (!_a || !_b)
460
0
    return _a < _b;
461
462
5.79k
  return _a->id() < _b->id();
463
5.79k
}
464
465
void OverrideChecker::check(ContractDefinition const& _contract)
466
26.5k
{
467
26.5k
  checkIllegalOverrides(_contract);
468
26.5k
  checkAmbiguousOverrides(_contract);
469
26.5k
}
470
471
void OverrideChecker::checkIllegalOverrides(ContractDefinition const& _contract)
472
26.5k
{
473
26.5k
  OverrideProxyBySignatureMultiSet const& inheritedFuncs = inheritedFunctions(_contract);
474
26.5k
  OverrideProxyBySignatureMultiSet const& inheritedMods = inheritedModifiers(_contract);
475
476
26.5k
  for (ModifierDefinition const* modifier: _contract.functionModifiers())
477
2.88k
  {
478
2.88k
    if (contains_if(inheritedFuncs, MatchByName{modifier->name()}))
479
2
      m_errorReporter.typeError(
480
2
        5631_error,
481
2
        modifier->location(),
482
2
        "Override changes function or public state variable to modifier."
483
2
      );
484
485
2.88k
    checkOverrideList(OverrideProxy{modifier}, inheritedMods);
486
2.88k
  }
487
488
26.5k
  for (FunctionDefinition const* function: _contract.definedFunctions())
489
25.1k
  {
490
25.1k
    if (function->isConstructor())
491
2.26k
      continue;
492
493
22.8k
    if (contains_if(inheritedMods, MatchByName{function->name()}))
494
2
      m_errorReporter.typeError(1469_error, function->location(), "Override changes modifier to function.");
495
496
22.8k
    checkOverrideList(OverrideProxy{function}, inheritedFuncs);
497
22.8k
  }
498
26.5k
  for (auto const* stateVar: _contract.stateVariables())
499
12.3k
  {
500
12.3k
    if (!stateVar->isPublic())
501
8.07k
    {
502
8.07k
      if (stateVar->overrides())
503
2
        m_errorReporter.typeError(8022_error, stateVar->location(), "Override can only be used with public state variables.");
504
505
8.07k
      continue;
506
8.07k
    }
507
508
4.24k
    if (contains_if(inheritedMods, MatchByName{stateVar->name()}))
509
2
      m_errorReporter.typeError(1456_error, stateVar->location(), "Override changes modifier to public state variable.");
510
511
4.24k
    checkOverrideList(OverrideProxy{stateVar}, inheritedFuncs);
512
4.24k
  }
513
514
26.5k
}
515
516
void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverrideProxy const& _super)
517
1.90k
{
518
1.90k
  solAssert(_super.isModifier() == _overriding.isModifier(), "");
519
520
1.90k
  if (_super.isFunction() || _super.isModifier())
521
1.83k
    _overriding.storeBaseFunction(_super);
522
523
1.90k
  if (_overriding.isModifier() && *_overriding.modifierType() != *_super.modifierType())
524
47
    m_errorReporter.typeError(
525
47
      1078_error,
526
47
      _overriding.location(),
527
47
      "Override changes modifier signature."
528
47
    );
529
530
1.90k
  if (!_overriding.overrides() && !(_super.isFunction() && _super.contract().isInterface()))
531
853
    overrideError(
532
853
      _overriding,
533
853
      _super,
534
853
      9456_error,
535
853
      "Overriding " + _overriding.astNodeName() + " is missing \"override\" specifier.",
536
853
      "Overridden " + _overriding.astNodeName() + " is here:"
537
853
    );
538
539
1.90k
  if (_super.isVariable())
540
67
    overrideError(
541
67
      _super,
542
67
      _overriding,
543
67
      1452_error,
544
67
      "Cannot override public state variable.",
545
67
      "Overriding " + _overriding.astNodeName() + " is here:"
546
67
    );
547
1.83k
  else if (!_super.virtualSemantics())
548
779
    overrideError(
549
779
      _super,
550
779
      _overriding,
551
779
      4334_error,
552
779
      "Trying to override non-virtual " + _super.astNodeName() + ". Did you forget to add \"virtual\"?",
553
779
      "Overriding " + _overriding.astNodeName() + " is here:"
554
779
    );
555
556
1.90k
  if (_overriding.isVariable())
557
211
  {
558
211
    if (_super.visibility() != Visibility::External)
559
16
      overrideError(
560
16
        _overriding,
561
16
        _super,
562
16
        5225_error,
563
16
        "Public state variables can only override functions with external visibility.",
564
16
        "Overridden function is here:"
565
16
      );
566
211
    solAssert(_overriding.visibility() == Visibility::External, "");
567
211
  }
568
1.69k
  else if (_overriding.visibility() != _super.visibility())
569
138
  {
570
    // Visibility change from external to public is fine.
571
    // Any other change is disallowed.
572
138
    if (!(
573
138
      _super.visibility() == Visibility::External &&
574
138
      _overriding.visibility() == Visibility::Public
575
138
    ))
576
15
      overrideError(
577
15
        _overriding,
578
15
        _super,
579
15
        9098_error,
580
15
        "Overriding " + _overriding.astNodeName() + " visibility differs.",
581
15
        "Overridden " + _overriding.astNodeName() + " is here:"
582
15
      );
583
138
  }
584
585
1.90k
  if (_overriding.unimplemented() && !_super.unimplemented())
586
19
  {
587
19
    solAssert(!_overriding.isVariable() || !_overriding.unimplemented(), "");
588
19
    overrideError(
589
19
      _overriding,
590
19
      _super,
591
19
      4593_error,
592
19
      "Overriding an implemented " + _super.astNodeName() +
593
19
      " with an unimplemented " + _overriding.astNodeName() +
594
19
      " is not allowed."
595
19
    );
596
19
  }
597
598
1.90k
  if (_super.isFunction())
599
982
  {
600
982
    FunctionType const* functionType = _overriding.externalFunctionType();
601
982
    FunctionType const* superType = _super.externalFunctionType();
602
603
982
    bool returnTypesDifferAlready = false;
604
982
    if (_overriding.functionKind() != Token::Fallback)
605
948
    {
606
948
      solAssert(functionType->hasEqualParameterTypes(*superType), "Override doesn't have equal parameters!");
607
608
948
      if (!functionType->hasEqualReturnTypes(*superType))
609
14
      {
610
14
        returnTypesDifferAlready = true;
611
14
        overrideError(
612
14
          _overriding,
613
14
          _super,
614
14
          4822_error,
615
14
          "Overriding " + _overriding.astNodeName() + " return types differ.",
616
14
          "Overridden " + _overriding.astNodeName() + " is here:"
617
14
        );
618
14
      }
619
948
    }
620
621
    // The override proxy considers calldata and memory the same data location.
622
    // Here we do a more specific check:
623
    // Data locations of parameters and return variables have to match
624
    // unless we have a public function overriding an external one.
625
982
    if (
626
982
      _overriding.isFunction() &&
627
982
      !returnTypesDifferAlready &&
628
982
      _super.visibility() != Visibility::External &&
629
982
      _overriding.functionKind() != Token::Fallback
630
982
    )
631
358
    {
632
358
      if (!_overriding.originalFunctionType()->hasEqualParameterTypes(*_super.originalFunctionType()))
633
2
        overrideError(
634
2
          _overriding,
635
2
          _super,
636
2
          7723_error,
637
2
          "Data locations of parameters have to be the same when overriding non-external functions, but they differ.",
638
2
          "Overridden " + _overriding.astNodeName() + " is here:"
639
2
        );
640
358
      if (!_overriding.originalFunctionType()->hasEqualReturnTypes(*_super.originalFunctionType()))
641
2
        overrideError(
642
2
          _overriding,
643
2
          _super,
644
2
          1443_error,
645
2
          "Data locations of return variables have to be the same when overriding non-external functions, but they differ.",
646
2
          "Overridden " + _overriding.astNodeName() + " is here:"
647
2
        );
648
358
    }
649
650
    // Stricter mutability is always okay except when super is Payable
651
982
    if (
652
982
      (_overriding.isFunction() || _overriding.isVariable()) &&
653
982
      (
654
982
        _overriding.stateMutability() > _super.stateMutability() ||
655
982
        _super.stateMutability() == StateMutability::Payable
656
982
      ) &&
657
982
      _overriding.stateMutability() != _super.stateMutability()
658
982
    )
659
12
      overrideError(
660
12
        _overriding,
661
12
        _super,
662
12
        6959_error,
663
12
        "Overriding " +
664
12
        _overriding.astNodeName() +
665
12
        " changes state mutability from \"" +
666
12
        stateMutabilityToString(_super.stateMutability()) +
667
12
        "\" to \"" +
668
12
        stateMutabilityToString(_overriding.stateMutability()) +
669
12
        "\"."
670
12
      );
671
982
  }
672
1.90k
}
673
674
void OverrideChecker::overrideListError(
675
  OverrideProxy const& _item,
676
  std::set<ContractDefinition const*, CompareByID> _secondary,
677
  ErrorId _error,
678
  std::string const& _message1,
679
  std::string const& _message2
680
)
681
320
{
682
  // Using a set rather than a vector so the order is always the same
683
320
  std::set<std::string> names;
684
320
  SecondarySourceLocation ssl;
685
320
  for (Declaration const* c: _secondary)
686
665
  {
687
665
    ssl.append("This contract: ", c->location());
688
665
    names.insert("\"" + c->name() + "\"");
689
665
  }
690
320
  std::string contractSingularPlural = "contract ";
691
320
  if (_secondary.size() > 1)
692
213
    contractSingularPlural = "contracts ";
693
694
320
  m_errorReporter.typeError(
695
320
    _error,
696
320
    _item.overrides() ? _item.overrides()->location() : _item.location(),
697
320
    ssl,
698
320
    _message1 +
699
320
    contractSingularPlural +
700
320
    _message2 +
701
320
    joinHumanReadable(names, ", ", " and ") +
702
320
    "."
703
320
  );
704
320
}
705
706
void OverrideChecker::overrideError(
707
  OverrideProxy const& _overriding,
708
  OverrideProxy const& _super,
709
  ErrorId _error,
710
  std::string const& _message,
711
  std::optional<std::string> const& _secondaryMsg
712
)
713
1.77k
{
714
1.77k
  m_errorReporter.typeError(
715
1.77k
    _error,
716
1.77k
    _overriding.location(),
717
1.77k
    SecondarySourceLocation().append(
718
1.77k
      _secondaryMsg.value_or("Overridden " + _super.astNodeName() + " is here:"),
719
1.77k
      _super.location()
720
1.77k
    ),
721
1.77k
    _message
722
1.77k
  );
723
1.77k
}
724
725
void OverrideChecker::checkAmbiguousOverrides(ContractDefinition const& _contract) const
726
26.5k
{
727
26.5k
  {
728
    // Fetch inherited functions and sort them by signature.
729
    // We get at least one function per signature and direct base contract, which is
730
    // enough because we re-construct the inheritance graph later.
731
26.5k
    OverrideProxyBySignatureMultiSet nonOverriddenFunctions = inheritedFunctions(_contract);
732
733
    // Remove all functions that match the signature of a function in the current contract.
734
26.5k
    for (FunctionDefinition const* f: _contract.definedFunctions())
735
25.1k
      nonOverriddenFunctions.erase(OverrideProxy{f});
736
26.5k
    for (VariableDeclaration const* v: _contract.stateVariables())
737
12.3k
      if (v->isPublic())
738
4.24k
        nonOverriddenFunctions.erase(OverrideProxy{v});
739
740
    // Walk through the set of functions signature by signature.
741
28.6k
    for (auto it = nonOverriddenFunctions.cbegin(); it != nonOverriddenFunctions.cend();)
742
2.08k
    {
743
2.08k
      std::set<OverrideProxy> baseFunctions;
744
4.45k
      for (auto nextSignature = nonOverriddenFunctions.upper_bound(*it); it != nextSignature; ++it)
745
2.36k
        baseFunctions.insert(*it);
746
747
2.08k
      checkAmbiguousOverridesInternal(std::move(baseFunctions), _contract.location());
748
2.08k
    }
749
26.5k
  }
750
751
26.5k
  {
752
26.5k
    OverrideProxyBySignatureMultiSet modifiers = inheritedModifiers(_contract);
753
26.5k
    for (ModifierDefinition const* mod: _contract.functionModifiers())
754
2.88k
      modifiers.erase(OverrideProxy{mod});
755
756
29.7k
    for (auto it = modifiers.cbegin(); it != modifiers.cend();)
757
3.25k
    {
758
3.25k
      std::set<OverrideProxy> baseModifiers;
759
6.56k
      for (auto next = modifiers.upper_bound(*it); it != next; ++it)
760
3.31k
        baseModifiers.insert(*it);
761
762
3.25k
      checkAmbiguousOverridesInternal(std::move(baseModifiers), _contract.location());
763
3.25k
    }
764
765
26.5k
  }
766
26.5k
}
767
768
void OverrideChecker::checkAmbiguousOverridesInternal(std::set<OverrideProxy> _baseCallables, SourceLocation const& _location) const
769
5.33k
{
770
5.33k
  if (_baseCallables.size() <= 1)
771
5.18k
    return;
772
773
150
  OverrideGraph overrideGraph(_baseCallables);
774
150
  CutVertexFinder cutVertexFinder{overrideGraph};
775
776
  // Remove all base functions overridden by cut vertices (they don't need to be overridden).
777
150
  for (OverrideProxy const& function: cutVertexFinder.cutVertices())
778
86
  {
779
86
    std::set<OverrideProxy> toTraverse = function.baseFunctions();
780
101
    while (!toTraverse.empty())
781
15
    {
782
15
      OverrideProxy base = *toTraverse.begin();
783
15
      toTraverse.erase(toTraverse.begin());
784
15
      _baseCallables.erase(base);
785
15
      for (OverrideProxy const& f: base.baseFunctions())
786
0
        toTraverse.insert(f);
787
15
    }
788
    // Remove unimplemented base functions at the cut vertices itself as well.
789
86
    if (function.unimplemented())
790
78
      _baseCallables.erase(function);
791
86
  }
792
793
  // If more than one function is left, they have to be overridden.
794
150
  if (_baseCallables.size() <= 1)
795
70
    return;
796
797
80
  SecondarySourceLocation ssl;
798
80
  for (OverrideProxy const& baseFunction: _baseCallables)
799
165
    ssl.append("Definition in \"" + baseFunction.contractName() + "\": ", baseFunction.location());
800
801
80
  std::string callableName = _baseCallables.begin()->astNodeName();
802
80
  if (_baseCallables.begin()->isVariable())
803
8
    callableName = "function";
804
80
  std::string distinguishingProperty = _baseCallables.begin()->distinguishingProperty();
805
806
80
  bool foundVariable = false;
807
80
  for (auto const& base: _baseCallables)
808
165
    if (base.isVariable())
809
18
      foundVariable = true;
810
811
80
  std::string message =
812
80
    "Derived contract must override " + callableName + " \"" +
813
80
    _baseCallables.begin()->name() +
814
80
    "\". Two or more base classes define " + callableName + " with same " + distinguishingProperty + ".";
815
816
80
  if (foundVariable)
817
13
    message +=
818
13
      " Since one of the bases defines a public state variable which cannot be overridden, "
819
13
      "you have to change the inheritance layout or the names of the functions.";
820
821
80
  m_errorReporter.typeError(6480_error, _location, ssl, message);
822
80
}
823
824
std::set<ContractDefinition const*, OverrideChecker::CompareByID> OverrideChecker::resolveOverrideList(OverrideSpecifier const& _overrides) const
825
913
{
826
913
  std::set<ContractDefinition const*, CompareByID> resolved;
827
828
913
  for (ASTPointer<IdentifierPath> const& override: _overrides.overrides())
829
1.55k
  {
830
1.55k
    Declaration const* decl  = override->annotation().referencedDeclaration;
831
1.55k
    solAssert(decl, "Expected declaration to be resolved.");
832
833
    // If it's not a contract it will be caught
834
    // in the reference resolver
835
1.55k
    if (ContractDefinition const* contract = dynamic_cast<decltype(contract)>(decl))
836
1.55k
      resolved.insert(contract);
837
1.55k
  }
838
839
913
  return resolved;
840
913
}
841
842
void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySignatureMultiSet const& _inherited)
843
30.0k
{
844
30.0k
  std::set<ContractDefinition const*, CompareByID> specifiedContracts =
845
30.0k
    _item.overrides() ?
846
913
    resolveOverrideList(*_item.overrides()) :
847
30.0k
    decltype(specifiedContracts){};
848
849
  // Check for duplicates in override list
850
30.0k
  if (_item.overrides() && specifiedContracts.size() != _item.overrides()->overrides().size())
851
106
  {
852
    // Sort by contract id to find duplicate for error reporting
853
106
    std::vector<ASTPointer<IdentifierPath>> list =
854
106
      sortByContract(_item.overrides()->overrides());
855
856
    // Find duplicates and output error
857
1.00k
    for (size_t i = 1; i < list.size(); i++)
858
901
    {
859
901
      Declaration const* aDecl = list[i]->annotation().referencedDeclaration;
860
901
      Declaration const* bDecl = list[i-1]->annotation().referencedDeclaration;
861
901
      if (!aDecl || !bDecl)
862
0
        continue;
863
864
901
      if (aDecl->id() == bDecl->id())
865
665
      {
866
665
        SecondarySourceLocation ssl;
867
665
        ssl.append("First occurrence here: ", list[i-1]->location());
868
665
        m_errorReporter.typeError(
869
665
          4520_error,
870
665
          list[i]->location(),
871
665
          ssl,
872
665
          "Duplicate contract \"" +
873
665
          joinHumanReadable(list[i]->path(), ".") +
874
665
          "\" found in override list of \"" +
875
665
          _item.name() +
876
665
          "\"."
877
665
        );
878
665
      }
879
901
    }
880
106
  }
881
882
30.0k
  std::set<ContractDefinition const*, CompareByID> expectedContracts;
883
884
  // Build list of expected contracts
885
31.9k
  for (auto [begin, end] = _inherited.equal_range(_item); begin != end; begin++)
886
1.90k
  {
887
    // Validate the override
888
1.90k
    checkOverride(_item, *begin);
889
890
1.90k
    expectedContracts.insert(&begin->contract());
891
1.90k
  }
892
893
30.0k
  if (_item.overrides() && expectedContracts.empty())
894
266
    m_errorReporter.typeError(
895
266
      7792_error,
896
266
      _item.overrides()->location(),
897
266
      _item.astNodeNameCapitalized() + " has override specified but does not override anything."
898
266
    );
899
900
30.0k
  std::set<ContractDefinition const*, CompareByID> missingContracts;
901
  // If we expect only one contract, no contract needs to be specified
902
30.0k
  if (expectedContracts.size() > 1)
903
185
    missingContracts = expectedContracts - specifiedContracts;
904
905
30.0k
  if (!missingContracts.empty())
906
65
    overrideListError(
907
65
      _item,
908
65
      missingContracts,
909
65
      4327_error,
910
65
      _item.astNodeNameCapitalized() + " needs to specify overridden ",
911
65
      ""
912
65
    );
913
914
30.0k
  auto surplusContracts = specifiedContracts - expectedContracts;
915
30.0k
  if (!surplusContracts.empty())
916
255
    overrideListError(
917
255
      _item,
918
255
      surplusContracts,
919
255
      2353_error,
920
255
      "Invalid ",
921
255
      "specified in override list: "
922
255
    );
923
30.0k
}
924
925
OverrideChecker::OverrideProxyBySignatureMultiSet const& OverrideChecker::inheritedFunctions(ContractDefinition const& _contract) const
926
57.6k
{
927
57.6k
  if (!m_inheritedFunctions.count(&_contract))
928
26.5k
  {
929
26.5k
    OverrideProxyBySignatureMultiSet result;
930
931
26.5k
    for (auto const* base: resolveDirectBaseContracts(_contract))
932
4.56k
    {
933
4.56k
      std::set<OverrideProxy, OverrideProxy::CompareBySignature> functionsInBase;
934
4.56k
      for (FunctionDefinition const* fun: base->definedFunctions())
935
3.05k
        if (!fun->isConstructor())
936
2.35k
          functionsInBase.emplace(OverrideProxy{fun});
937
4.56k
      for (VariableDeclaration const* var: base->stateVariables())
938
1.16k
        if (var->isPublic())
939
865
          functionsInBase.emplace(OverrideProxy{var});
940
941
4.56k
      result += functionsInBase;
942
943
4.56k
      for (OverrideProxy const& func: inheritedFunctions(*base))
944
840
        if (!functionsInBase.count(func))
945
563
          result.insert(func);
946
4.56k
    }
947
948
26.5k
    m_inheritedFunctions[&_contract] = result;
949
26.5k
  }
950
951
57.6k
  return m_inheritedFunctions[&_contract];
952
57.6k
}
953
954
OverrideChecker::OverrideProxyBySignatureMultiSet const& OverrideChecker::inheritedModifiers(ContractDefinition const& _contract) const
955
57.6k
{
956
57.6k
  if (!m_inheritedModifiers.count(&_contract))
957
26.5k
  {
958
26.5k
    OverrideProxyBySignatureMultiSet result;
959
960
26.5k
    for (auto const* base: resolveDirectBaseContracts(_contract))
961
4.56k
    {
962
4.56k
      std::set<OverrideProxy, OverrideProxy::CompareBySignature> modifiersInBase;
963
4.56k
      for (ModifierDefinition const* mod: base->functionModifiers())
964
4.03k
        modifiersInBase.emplace(OverrideProxy{mod});
965
966
4.56k
      for (OverrideProxy const& mod: inheritedModifiers(*base))
967
682
        modifiersInBase.insert(mod);
968
969
4.56k
      result += modifiersInBase;
970
4.56k
    }
971
972
26.5k
    m_inheritedModifiers[&_contract] = result;
973
26.5k
  }
974
975
57.6k
  return m_inheritedModifiers[&_contract];
976
57.6k
}