Coverage Report

Created: 2022-08-24 06:52

/src/solidity/libsolidity/analysis/ContractLevelChecker.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/ContractLevelChecker.h>
24
25
#include <libsolidity/ast/AST.h>
26
#include <libsolidity/ast/TypeProvider.h>
27
#include <libsolidity/analysis/TypeChecker.h>
28
#include <libsolutil/FunctionSelector.h>
29
#include <liblangutil/ErrorReporter.h>
30
31
#include <range/v3/view/reverse.hpp>
32
33
using namespace std;
34
using namespace solidity;
35
using namespace solidity::langutil;
36
using namespace solidity::frontend;
37
38
namespace
39
{
40
41
template <class T, class B>
42
bool hasEqualExternalCallableParameters(T const& _a, B const& _b)
43
0
{
44
0
  return FunctionType(_a).asExternallyCallableFunction(false)->hasEqualParameterTypes(
45
0
    *FunctionType(_b).asExternallyCallableFunction(false)
46
0
  );
47
0
}
Unexecuted instantiation: ContractLevelChecker.cpp:bool (anonymous namespace)::hasEqualExternalCallableParameters<solidity::frontend::FunctionDefinition, solidity::frontend::FunctionDefinition>(solidity::frontend::FunctionDefinition const&, solidity::frontend::FunctionDefinition const&)
Unexecuted instantiation: ContractLevelChecker.cpp:bool (anonymous namespace)::hasEqualExternalCallableParameters<solidity::frontend::EventDefinition, solidity::frontend::EventDefinition>(solidity::frontend::EventDefinition const&, solidity::frontend::EventDefinition const&)
48
49
template<typename T>
50
map<ASTString, vector<T const*>> filterDeclarations(
51
  map<ASTString, vector<Declaration const*>> const& _declarations)
52
7.21k
{
53
7.21k
  map<ASTString, vector<T const*>> filteredDeclarations;
54
7.21k
  for (auto const& [name, overloads]: _declarations)
55
7.21k
    for (auto const* declaration: overloads)
56
7.21k
      if (auto typedDeclaration = dynamic_cast<T const*>(declaration))
57
0
        filteredDeclarations[name].push_back(typedDeclaration);
58
7.21k
  return filteredDeclarations;
59
7.21k
}
ContractLevelChecker.cpp:std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<solidity::frontend::FunctionDefinition const*, std::__1::allocator<solidity::frontend::FunctionDefinition const*> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::vector<solidity::frontend::FunctionDefinition const*, std::__1::allocator<solidity::frontend::FunctionDefinition const*> > > > > (anonymous namespace)::filterDeclarations<solidity::frontend::FunctionDefinition>(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<solidity::frontend::Declaration const*, std::__1::allocator<solidity::frontend::Declaration const*> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::vector<solidity::frontend::Declaration const*, std::__1::allocator<solidity::frontend::Declaration const*> > > > > const&)
Line
Count
Source
52
3.60k
{
53
3.60k
  map<ASTString, vector<T const*>> filteredDeclarations;
54
3.60k
  for (auto const& [name, overloads]: _declarations)
55
3.60k
    for (auto const* declaration: overloads)
56
3.60k
      if (auto typedDeclaration = dynamic_cast<T const*>(declaration))
57
0
        filteredDeclarations[name].push_back(typedDeclaration);
58
3.60k
  return filteredDeclarations;
59
3.60k
}
ContractLevelChecker.cpp:std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<solidity::frontend::EventDefinition const*, std::__1::allocator<solidity::frontend::EventDefinition const*> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::vector<solidity::frontend::EventDefinition const*, std::__1::allocator<solidity::frontend::EventDefinition const*> > > > > (anonymous namespace)::filterDeclarations<solidity::frontend::EventDefinition>(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<solidity::frontend::Declaration const*, std::__1::allocator<solidity::frontend::Declaration const*> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::vector<solidity::frontend::Declaration const*, std::__1::allocator<solidity::frontend::Declaration const*> > > > > const&)
Line
Count
Source
52
3.60k
{
53
3.60k
  map<ASTString, vector<T const*>> filteredDeclarations;
54
3.60k
  for (auto const& [name, overloads]: _declarations)
55
3.60k
    for (auto const* declaration: overloads)
56
3.60k
      if (auto typedDeclaration = dynamic_cast<T const*>(declaration))
57
0
        filteredDeclarations[name].push_back(typedDeclaration);
58
3.60k
  return filteredDeclarations;
59
3.60k
}
60
61
}
62
63
bool ContractLevelChecker::check(SourceUnit const& _sourceUnit)
64
3.60k
{
65
3.60k
  bool noErrors = true;
66
3.60k
  findDuplicateDefinitions(
67
3.60k
    filterDeclarations<FunctionDefinition>(*_sourceUnit.annotation().exportedSymbols)
68
3.60k
  );
69
  // This check flags duplicate free events when free events become
70
  // a Solidity feature
71
3.60k
  findDuplicateDefinitions(
72
3.60k
    filterDeclarations<EventDefinition>(*_sourceUnit.annotation().exportedSymbols)
73
3.60k
  );
74
3.60k
  if (Error::containsErrors(m_errorReporter.errors()))
75
0
    noErrors = false;
76
3.60k
  for (ASTPointer<ASTNode> const& node: _sourceUnit.nodes())
77
10.8k
    if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
78
3.60k
      if (!check(*contract))
79
0
        noErrors = false;
80
3.60k
  return noErrors;
81
3.60k
}
82
83
bool ContractLevelChecker::check(ContractDefinition const& _contract)
84
3.60k
{
85
3.60k
  _contract.annotation().unimplementedDeclarations = std::vector<Declaration const*>();
86
87
3.60k
  checkDuplicateFunctions(_contract);
88
3.60k
  checkDuplicateEvents(_contract);
89
3.60k
  checkReceiveFunction(_contract);
90
3.60k
  m_overrideChecker.check(_contract);
91
3.60k
  checkBaseConstructorArguments(_contract);
92
3.60k
  checkAbstractDefinitions(_contract);
93
3.60k
  checkExternalTypeClashes(_contract);
94
3.60k
  checkHashCollisions(_contract);
95
3.60k
  checkLibraryRequirements(_contract);
96
3.60k
  checkBaseABICompatibility(_contract);
97
3.60k
  checkPayableFallbackWithoutReceive(_contract);
98
3.60k
  checkStorageSize(_contract);
99
100
3.60k
  return !Error::containsErrors(m_errorReporter.errors());
101
3.60k
}
102
103
void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _contract)
104
3.60k
{
105
  /// Checks that two functions with the same name defined in this contract have different
106
  /// argument types and that there is at most one constructor.
107
3.60k
  map<string, vector<FunctionDefinition const*>> functions;
108
3.60k
  FunctionDefinition const* constructor = nullptr;
109
3.60k
  FunctionDefinition const* fallback = nullptr;
110
3.60k
  FunctionDefinition const* receive = nullptr;
111
3.60k
  for (FunctionDefinition const* function: _contract.definedFunctions())
112
39.6k
    if (function->isConstructor())
113
0
    {
114
0
      if (constructor)
115
0
        m_errorReporter.declarationError(
116
0
          7997_error,
117
0
          function->location(),
118
0
          SecondarySourceLocation().append("Another declaration is here:", constructor->location()),
119
0
          "More than one constructor defined."
120
0
        );
121
0
      constructor = function;
122
0
    }
123
39.6k
    else if (function->isFallback())
124
0
    {
125
0
      if (fallback)
126
0
        m_errorReporter.declarationError(
127
0
          7301_error,
128
0
          function->location(),
129
0
          SecondarySourceLocation().append("Another declaration is here:", fallback->location()),
130
0
          "Only one fallback function is allowed."
131
0
        );
132
0
      fallback = function;
133
0
    }
134
39.6k
    else if (function->isReceive())
135
0
    {
136
0
      if (receive)
137
0
        m_errorReporter.declarationError(
138
0
          4046_error,
139
0
          function->location(),
140
0
          SecondarySourceLocation().append("Another declaration is here:", receive->location()),
141
0
          "Only one receive function is allowed."
142
0
        );
143
0
      receive = function;
144
0
    }
145
39.6k
    else
146
39.6k
    {
147
39.6k
      solAssert(!function->name().empty(), "");
148
39.6k
      functions[function->name()].push_back(function);
149
39.6k
    }
150
151
3.60k
  findDuplicateDefinitions(functions);
152
3.60k
}
153
154
void ContractLevelChecker::checkDuplicateEvents(ContractDefinition const& _contract)
155
3.60k
{
156
  /// Checks that two events with the same name defined in this contract have different
157
  /// argument types
158
3.60k
  map<string, vector<EventDefinition const*>> events;
159
3.60k
  for (auto const* contract: _contract.annotation().linearizedBaseContracts)
160
3.60k
    for (EventDefinition const* event: contract->events())
161
0
      events[event->name()].push_back(event);
162
163
3.60k
  findDuplicateDefinitions(events);
164
3.60k
}
165
166
void ContractLevelChecker::checkReceiveFunction(ContractDefinition const& _contract)
167
3.60k
{
168
3.60k
  for (FunctionDefinition const* function: _contract.definedFunctions())
169
39.6k
  {
170
39.6k
    solAssert(function, "");
171
39.6k
    if (function->isReceive())
172
0
    {
173
0
      if (function->libraryFunction())
174
0
        m_errorReporter.declarationError(4549_error, function->location(), "Libraries cannot have receive ether functions.");
175
176
0
      if (function->stateMutability() != StateMutability::Payable)
177
0
        m_errorReporter.declarationError(
178
0
          7793_error,
179
0
          function->location(),
180
0
          "Receive ether function must be payable, but is \"" +
181
0
          stateMutabilityToString(function->stateMutability()) +
182
0
          "\"."
183
0
        );
184
0
      if (function->visibility() != Visibility::External)
185
0
        m_errorReporter.declarationError(4095_error, function->location(), "Receive ether function must be defined as \"external\".");
186
187
0
      if (!function->returnParameters().empty())
188
0
        m_errorReporter.fatalDeclarationError(6899_error, function->returnParameterList()->location(), "Receive ether function cannot return values.");
189
0
      if (!function->parameters().empty())
190
0
        m_errorReporter.fatalDeclarationError(6857_error, function->parameterList().location(), "Receive ether function cannot take parameters.");
191
0
    }
192
39.6k
  }
193
3.60k
}
194
195
template <class T>
196
void ContractLevelChecker::findDuplicateDefinitions(map<string, vector<T>> const& _definitions)
197
14.4k
{
198
14.4k
  for (auto const& it: _definitions)
199
39.6k
  {
200
39.6k
    vector<T> const& overloads = it.second;
201
39.6k
    set<size_t> reported;
202
79.3k
    for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i)
203
39.6k
    {
204
39.6k
      SecondarySourceLocation ssl;
205
206
39.6k
      for (size_t j = i + 1; j < overloads.size(); ++j)
207
0
        if (hasEqualExternalCallableParameters(*overloads[i], *overloads[j]))
208
0
        {
209
0
          solAssert(
210
0
            (
211
0
              dynamic_cast<ContractDefinition const*>(overloads[i]->scope()) &&
212
0
              dynamic_cast<ContractDefinition const*>(overloads[j]->scope()) &&
213
0
              overloads[i]->name() == overloads[j]->name()
214
0
            ) ||
215
0
            (
216
0
              dynamic_cast<SourceUnit const*>(overloads[i]->scope()) &&
217
0
              dynamic_cast<SourceUnit const*>(overloads[j]->scope())
218
0
            ),
219
0
            "Override is neither a namesake function/event in contract scope nor "
220
0
            "a free function/event (alias)."
221
0
          );
222
0
          ssl.append("Other declaration is here:", overloads[j]->location());
223
0
          reported.insert(j);
224
0
        }
225
226
39.6k
      if (ssl.infos.size() > 0)
227
0
      {
228
0
        ErrorId error;
229
0
        string message;
230
0
        if constexpr (is_same_v<T, FunctionDefinition const*>)
231
0
        {
232
0
          error = 1686_error;
233
0
          message = "Function with same name and parameter types defined twice.";
234
0
        }
235
0
        else
236
0
        {
237
0
          static_assert(is_same_v<T, EventDefinition const*>, "Expected \"FunctionDefinition const*\" or \"EventDefinition const*\"");
238
0
          error = 5883_error;
239
0
          message = "Event with same name and parameter types defined twice.";
240
0
        }
241
242
0
        ssl.limitSize(message);
243
244
0
        m_errorReporter.declarationError(
245
0
          error,
246
0
          overloads[i]->location(),
247
0
          ssl,
248
0
          message
249
0
        );
250
0
      }
251
39.6k
    }
252
39.6k
  }
253
14.4k
}
void solidity::frontend::ContractLevelChecker::findDuplicateDefinitions<solidity::frontend::FunctionDefinition const*>(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<solidity::frontend::FunctionDefinition const*, std::__1::allocator<solidity::frontend::FunctionDefinition const*> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::vector<solidity::frontend::FunctionDefinition const*, std::__1::allocator<solidity::frontend::FunctionDefinition const*> > > > > const&)
Line
Count
Source
197
7.21k
{
198
7.21k
  for (auto const& it: _definitions)
199
39.6k
  {
200
39.6k
    vector<T> const& overloads = it.second;
201
39.6k
    set<size_t> reported;
202
79.3k
    for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i)
203
39.6k
    {
204
39.6k
      SecondarySourceLocation ssl;
205
206
39.6k
      for (size_t j = i + 1; j < overloads.size(); ++j)
207
0
        if (hasEqualExternalCallableParameters(*overloads[i], *overloads[j]))
208
0
        {
209
0
          solAssert(
210
0
            (
211
0
              dynamic_cast<ContractDefinition const*>(overloads[i]->scope()) &&
212
0
              dynamic_cast<ContractDefinition const*>(overloads[j]->scope()) &&
213
0
              overloads[i]->name() == overloads[j]->name()
214
0
            ) ||
215
0
            (
216
0
              dynamic_cast<SourceUnit const*>(overloads[i]->scope()) &&
217
0
              dynamic_cast<SourceUnit const*>(overloads[j]->scope())
218
0
            ),
219
0
            "Override is neither a namesake function/event in contract scope nor "
220
0
            "a free function/event (alias)."
221
0
          );
222
0
          ssl.append("Other declaration is here:", overloads[j]->location());
223
0
          reported.insert(j);
224
0
        }
225
226
39.6k
      if (ssl.infos.size() > 0)
227
0
      {
228
0
        ErrorId error;
229
0
        string message;
230
0
        if constexpr (is_same_v<T, FunctionDefinition const*>)
231
0
        {
232
0
          error = 1686_error;
233
0
          message = "Function with same name and parameter types defined twice.";
234
0
        }
235
0
        else
236
0
        {
237
0
          static_assert(is_same_v<T, EventDefinition const*>, "Expected \"FunctionDefinition const*\" or \"EventDefinition const*\"");
238
0
          error = 5883_error;
239
0
          message = "Event with same name and parameter types defined twice.";
240
0
        }
241
242
0
        ssl.limitSize(message);
243
244
0
        m_errorReporter.declarationError(
245
0
          error,
246
0
          overloads[i]->location(),
247
0
          ssl,
248
0
          message
249
0
        );
250
0
      }
251
39.6k
    }
252
39.6k
  }
253
7.21k
}
void solidity::frontend::ContractLevelChecker::findDuplicateDefinitions<solidity::frontend::EventDefinition const*>(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<solidity::frontend::EventDefinition const*, std::__1::allocator<solidity::frontend::EventDefinition const*> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::vector<solidity::frontend::EventDefinition const*, std::__1::allocator<solidity::frontend::EventDefinition const*> > > > > const&)
Line
Count
Source
197
7.21k
{
198
7.21k
  for (auto const& it: _definitions)
199
0
  {
200
0
    vector<T> const& overloads = it.second;
201
0
    set<size_t> reported;
202
0
    for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i)
203
0
    {
204
0
      SecondarySourceLocation ssl;
205
206
0
      for (size_t j = i + 1; j < overloads.size(); ++j)
207
0
        if (hasEqualExternalCallableParameters(*overloads[i], *overloads[j]))
208
0
        {
209
0
          solAssert(
210
0
            (
211
0
              dynamic_cast<ContractDefinition const*>(overloads[i]->scope()) &&
212
0
              dynamic_cast<ContractDefinition const*>(overloads[j]->scope()) &&
213
0
              overloads[i]->name() == overloads[j]->name()
214
0
            ) ||
215
0
            (
216
0
              dynamic_cast<SourceUnit const*>(overloads[i]->scope()) &&
217
0
              dynamic_cast<SourceUnit const*>(overloads[j]->scope())
218
0
            ),
219
0
            "Override is neither a namesake function/event in contract scope nor "
220
0
            "a free function/event (alias)."
221
0
          );
222
0
          ssl.append("Other declaration is here:", overloads[j]->location());
223
0
          reported.insert(j);
224
0
        }
225
226
0
      if (ssl.infos.size() > 0)
227
0
      {
228
0
        ErrorId error;
229
0
        string message;
230
0
        if constexpr (is_same_v<T, FunctionDefinition const*>)
231
0
        {
232
0
          error = 1686_error;
233
0
          message = "Function with same name and parameter types defined twice.";
234
0
        }
235
0
        else
236
0
        {
237
0
          static_assert(is_same_v<T, EventDefinition const*>, "Expected \"FunctionDefinition const*\" or \"EventDefinition const*\"");
238
0
          error = 5883_error;
239
0
          message = "Event with same name and parameter types defined twice.";
240
0
        }
241
242
0
        ssl.limitSize(message);
243
244
0
        m_errorReporter.declarationError(
245
0
          error,
246
0
          overloads[i]->location(),
247
0
          ssl,
248
0
          message
249
0
        );
250
0
      }
251
0
    }
252
0
  }
253
7.21k
}
254
255
void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _contract)
256
3.60k
{
257
  // Collects functions, static variable getters and modifiers. If they
258
  // override (unimplemented) base class ones, they are replaced.
259
3.60k
  set<OverrideProxy, OverrideProxy::CompareBySignature> proxies;
260
261
3.60k
  auto registerProxy = [&proxies](OverrideProxy const& _overrideProxy)
262
39.6k
  {
263
    // Overwrite an existing proxy, if it exists.
264
39.6k
    if (!_overrideProxy.unimplemented())
265
39.6k
      proxies.erase(_overrideProxy);
266
267
39.6k
    proxies.insert(_overrideProxy);
268
39.6k
  };
269
270
  // Search from base to derived, collect all functions and modifiers and
271
  // update proxies.
272
3.60k
  for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts | ranges::views::reverse)
273
3.60k
  {
274
3.60k
    for (VariableDeclaration const* v: contract->stateVariables())
275
2.94k
      if (v->isPartOfExternalInterface())
276
0
        registerProxy(OverrideProxy(v));
277
278
3.60k
    for (FunctionDefinition const* function: contract->definedFunctions())
279
39.6k
      if (!function->isConstructor())
280
39.6k
        registerProxy(OverrideProxy(function));
281
282
3.60k
    for (ModifierDefinition const* modifier: contract->functionModifiers())
283
0
      registerProxy(OverrideProxy(modifier));
284
3.60k
  }
285
286
  // Set to not fully implemented if at least one flag is false.
287
  // Note that `_contract.annotation().unimplementedDeclarations` has already been
288
  // pre-filled by `checkBaseConstructorArguments`.
289
  //
290
3.60k
  for (auto const& proxy: proxies)
291
39.6k
    if (proxy.unimplemented())
292
0
      _contract.annotation().unimplementedDeclarations->push_back(proxy.declaration());
293
294
3.60k
  if (_contract.abstract())
295
0
  {
296
0
    if (_contract.contractKind() == ContractKind::Interface)
297
0
      m_errorReporter.typeError(9348_error, _contract.location(), "Interfaces do not need the \"abstract\" keyword, they are abstract implicitly.");
298
0
    else if (_contract.contractKind() == ContractKind::Library)
299
0
      m_errorReporter.typeError(9571_error, _contract.location(), "Libraries cannot be abstract.");
300
0
    else
301
0
      solAssert(_contract.contractKind() == ContractKind::Contract, "");
302
0
  }
303
304
  // For libraries, we emit errors on function-level, so this is fine as long as we do
305
  // not have inheritance for libraries.
306
3.60k
  if (
307
3.60k
    _contract.contractKind() == ContractKind::Contract &&
308
3.60k
    !_contract.abstract() &&
309
3.60k
    !_contract.annotation().unimplementedDeclarations->empty()
310
3.60k
  )
311
0
  {
312
0
    SecondarySourceLocation ssl;
313
0
    for (auto declaration: *_contract.annotation().unimplementedDeclarations)
314
0
      ssl.append("Missing implementation: ", declaration->location());
315
0
    m_errorReporter.typeError(
316
0
      3656_error,
317
0
      _contract.location(),
318
0
      ssl,
319
0
      "Contract \"" + *_contract.annotation().canonicalName + "\" should be marked as abstract."
320
0
    );
321
0
  }
322
3.60k
}
323
324
325
void ContractLevelChecker::checkBaseConstructorArguments(ContractDefinition const& _contract)
326
3.60k
{
327
3.60k
  vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
328
329
  // Determine the arguments that are used for the base constructors.
330
3.60k
  for (ContractDefinition const* contract: bases)
331
3.60k
  {
332
3.60k
    if (FunctionDefinition const* constructor = contract->constructor())
333
0
      for (auto const& modifier: constructor->modifiers())
334
0
        if (auto baseContract = dynamic_cast<ContractDefinition const*>(
335
0
          modifier->name().annotation().referencedDeclaration
336
0
        ))
337
0
        {
338
0
          if (modifier->arguments())
339
0
          {
340
0
            if (baseContract->constructor())
341
0
              annotateBaseConstructorArguments(_contract, baseContract->constructor(), modifier.get());
342
0
          }
343
0
          else
344
0
            m_errorReporter.declarationError(
345
0
              1563_error,
346
0
              modifier->location(),
347
0
              "Modifier-style base constructor call without arguments."
348
0
            );
349
0
        }
350
351
3.60k
    for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
352
0
    {
353
0
      ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
354
0
        base->name().annotation().referencedDeclaration
355
0
      );
356
0
      solAssert(baseContract, "");
357
358
0
      if (baseContract->constructor() && base->arguments() && !base->arguments()->empty())
359
0
        annotateBaseConstructorArguments(_contract, baseContract->constructor(), base.get());
360
0
    }
361
3.60k
  }
362
363
  // check that we get arguments for all base constructors that need it.
364
  // If not mark the contract as abstract (not fully implemented)
365
3.60k
  for (ContractDefinition const* contract: bases)
366
3.60k
    if (FunctionDefinition const* constructor = contract->constructor())
367
0
      if (contract != &_contract && !constructor->parameters().empty())
368
0
        if (!_contract.annotation().baseConstructorArguments.count(constructor))
369
0
          _contract.annotation().unimplementedDeclarations->push_back(constructor);
370
3.60k
}
371
372
void ContractLevelChecker::annotateBaseConstructorArguments(
373
  ContractDefinition const& _currentContract,
374
  FunctionDefinition const* _baseConstructor,
375
  ASTNode const* _argumentNode
376
)
377
0
{
378
0
  solAssert(_baseConstructor, "");
379
0
  solAssert(_argumentNode, "");
380
381
0
  auto insertionResult = _currentContract.annotation().baseConstructorArguments.insert(
382
0
    std::make_pair(_baseConstructor, _argumentNode)
383
0
  );
384
0
  if (!insertionResult.second)
385
0
  {
386
0
    ASTNode const* previousNode = insertionResult.first->second;
387
388
0
    SourceLocation const* mainLocation = nullptr;
389
0
    SecondarySourceLocation ssl;
390
391
0
    if (
392
0
      _currentContract.location().contains(previousNode->location()) ||
393
0
      _currentContract.location().contains(_argumentNode->location())
394
0
    )
395
0
    {
396
0
      mainLocation = &previousNode->location();
397
0
      ssl.append("Second constructor call is here:", _argumentNode->location());
398
0
    }
399
0
    else
400
0
    {
401
0
      mainLocation = &_currentContract.location();
402
0
      ssl.append("First constructor call is here:", _argumentNode->location());
403
0
      ssl.append("Second constructor call is here:", previousNode->location());
404
0
    }
405
406
0
    m_errorReporter.declarationError(
407
0
      3364_error,
408
0
      *mainLocation,
409
0
      ssl,
410
0
      "Base constructor arguments given twice."
411
0
    );
412
0
  }
413
414
0
}
415
416
void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _contract)
417
3.60k
{
418
3.60k
  map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations;
419
3.60k
  for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
420
3.60k
  {
421
3.60k
    for (FunctionDefinition const* f: contract->definedFunctions())
422
39.6k
      if (f->isPartOfExternalInterface())
423
28.8k
      {
424
28.8k
        auto functionType = TypeProvider::function(*f);
425
        // under non error circumstances this should be true
426
28.8k
        if (functionType->interfaceFunctionType())
427
28.8k
          externalDeclarations[functionType->externalSignature()].emplace_back(
428
28.8k
            f, functionType->asExternallyCallableFunction(false)
429
28.8k
          );
430
28.8k
      }
431
3.60k
    for (VariableDeclaration const* v: contract->stateVariables())
432
2.94k
      if (v->isPartOfExternalInterface())
433
0
      {
434
0
        auto functionType = TypeProvider::function(*v);
435
        // under non error circumstances this should be true
436
0
        if (functionType->interfaceFunctionType())
437
0
          externalDeclarations[functionType->externalSignature()].emplace_back(
438
0
            v, functionType->asExternallyCallableFunction(false)
439
0
          );
440
0
      }
441
3.60k
  }
442
3.60k
  for (auto const& it: externalDeclarations)
443
57.7k
    for (size_t i = 0; i < it.second.size(); ++i)
444
28.8k
      for (size_t j = i + 1; j < it.second.size(); ++j)
445
0
        if (!it.second[i].second->hasEqualParameterTypes(*it.second[j].second))
446
0
          m_errorReporter.typeError(
447
0
            9914_error,
448
0
            it.second[j].first->location(),
449
0
            "Function overload clash during conversion to external types for arguments."
450
0
          );
451
3.60k
}
452
453
void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contract)
454
3.60k
{
455
3.60k
  set<util::FixedHash<4>> hashes;
456
3.60k
  for (auto const& it: _contract.interfaceFunctionList())
457
28.8k
  {
458
28.8k
    util::FixedHash<4> const& hash = it.first;
459
28.8k
    if (hashes.count(hash))
460
0
      m_errorReporter.fatalTypeError(
461
0
        1860_error,
462
0
        _contract.location(),
463
0
        string("Function signature hash collision for ") + it.second->externalSignature()
464
0
      );
465
28.8k
    hashes.insert(hash);
466
28.8k
  }
467
3.60k
}
468
469
void ContractLevelChecker::checkLibraryRequirements(ContractDefinition const& _contract)
470
3.60k
{
471
3.60k
  if (!_contract.isLibrary())
472
3.60k
    return;
473
474
0
  if (!_contract.baseContracts().empty())
475
0
    m_errorReporter.typeError(9469_error, _contract.location(), "Library is not allowed to inherit.");
476
477
0
  for (auto const& var: _contract.stateVariables())
478
0
    if (!var->isConstant())
479
0
      m_errorReporter.typeError(9957_error, var->location(), "Library cannot have non-constant state variables");
480
0
}
481
482
void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _contract)
483
3.60k
{
484
3.60k
  if (*_contract.sourceUnit().annotation().useABICoderV2)
485
3.60k
    return;
486
487
0
  if (_contract.isLibrary())
488
0
  {
489
0
    solAssert(
490
0
      _contract.baseContracts().empty() || m_errorReporter.hasErrors(),
491
0
      "Library is not allowed to inherit"
492
0
    );
493
0
    return;
494
0
  }
495
496
0
  SecondarySourceLocation errors;
497
498
  // interfaceFunctionList contains all inherited functions as well
499
0
  for (auto const& func: _contract.interfaceFunctionList())
500
0
  {
501
0
    solAssert(func.second->hasDeclaration(), "Function has no declaration?!");
502
503
0
    if (!*func.second->declaration().sourceUnit().annotation().useABICoderV2)
504
0
      continue;
505
506
0
    auto const& currentLoc = func.second->declaration().location();
507
508
0
    for (Type const* paramType: func.second->parameterTypes() + func.second->returnParameterTypes())
509
0
      if (!TypeChecker::typeSupportedByOldABIEncoder(*paramType, false))
510
0
      {
511
0
        errors.append("Type only supported by ABIEncoderV2", currentLoc);
512
0
        break;
513
0
      }
514
0
  }
515
516
0
  if (!errors.infos.empty())
517
0
    m_errorReporter.fatalTypeError(
518
0
      6594_error,
519
0
      _contract.location(),
520
0
      errors,
521
0
      std::string("Contract \"") +
522
0
      _contract.name() +
523
0
      "\" does not use ABI coder v2 but wants to inherit from a contract " +
524
0
      "which uses types that require it. " +
525
0
      "Use \"pragma abicoder v2;\" for the inheriting contract as well to enable the feature."
526
0
    );
527
528
0
}
529
530
void ContractLevelChecker::checkPayableFallbackWithoutReceive(ContractDefinition const& _contract)
531
3.60k
{
532
3.60k
  if (auto const* fallback = _contract.fallbackFunction())
533
0
    if (fallback->isPayable() && !_contract.interfaceFunctionList().empty() && !_contract.receiveFunction())
534
0
      m_errorReporter.warning(
535
0
        3628_error,
536
0
        _contract.location(),
537
0
        "This contract has a payable fallback function, but no receive ether function. Consider adding a receive ether function.",
538
0
        SecondarySourceLocation{}.append("The payable fallback function is defined here.", fallback->location())
539
0
      );
540
3.60k
}
541
542
void ContractLevelChecker::checkStorageSize(ContractDefinition const& _contract)
543
3.60k
{
544
3.60k
  bigint size = 0;
545
3.60k
  for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts | ranges::views::reverse)
546
3.60k
    for (VariableDeclaration const* variable: contract->stateVariables())
547
2.94k
      if (!(variable->isConstant() || variable->immutable()))
548
2.94k
      {
549
2.94k
        size += variable->annotation().type->storageSizeUpperBound();
550
2.94k
        if (size >= bigint(1) << 256)
551
0
        {
552
0
          m_errorReporter.typeError(7676_error, _contract.location(), "Contract requires too much storage.");
553
0
          break;
554
0
        }
555
2.94k
      }
556
3.60k
}