Coverage Report

Created: 2022-08-24 06:52

/src/solidity/libsolidity/analysis/ReferencesResolver.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
 * @author Christian <c@ethdev.com>
20
 * @date 2015
21
 * Component that resolves type names to types and annotates the AST accordingly.
22
 */
23
24
#include <libsolidity/analysis/ReferencesResolver.h>
25
#include <libsolidity/analysis/NameAndTypeResolver.h>
26
#include <libsolidity/ast/AST.h>
27
28
#include <libyul/AsmAnalysis.h>
29
#include <libyul/AsmAnalysisInfo.h>
30
#include <libyul/AST.h>
31
#include <libyul/backends/evm/EVMDialect.h>
32
33
#include <liblangutil/ErrorReporter.h>
34
#include <liblangutil/Exceptions.h>
35
36
#include <libsolutil/StringUtils.h>
37
#include <libsolutil/CommonData.h>
38
39
#include <boost/algorithm/string.hpp>
40
#include <boost/algorithm/string/split.hpp>
41
42
using namespace std;
43
using namespace solidity;
44
using namespace solidity::langutil;
45
using namespace solidity::frontend;
46
47
48
bool ReferencesResolver::resolve(ASTNode const& _root)
49
112k
{
50
112k
  auto errorWatcher = m_errorReporter.errorWatcher();
51
112k
  _root.accept(*this);
52
112k
  return errorWatcher.ok();
53
112k
}
54
55
bool ReferencesResolver::visit(Block const& _block)
56
79.3k
{
57
79.3k
  if (!m_resolveInsideCode)
58
39.6k
    return false;
59
39.6k
  m_resolver.setScope(&_block);
60
39.6k
  return true;
61
79.3k
}
62
63
void ReferencesResolver::endVisit(Block const& _block)
64
79.3k
{
65
79.3k
  if (!m_resolveInsideCode)
66
39.6k
    return;
67
68
39.6k
  m_resolver.setScope(_block.scope());
69
39.6k
}
70
71
bool ReferencesResolver::visit(TryCatchClause const& _tryCatchClause)
72
0
{
73
0
  if (!m_resolveInsideCode)
74
0
    return false;
75
0
  m_resolver.setScope(&_tryCatchClause);
76
0
  return true;
77
0
}
78
79
void ReferencesResolver::endVisit(TryCatchClause const& _tryCatchClause)
80
0
{
81
0
  if (!m_resolveInsideCode)
82
0
    return;
83
84
0
  m_resolver.setScope(_tryCatchClause.scope());
85
0
}
86
87
bool ReferencesResolver::visit(ForStatement const& _for)
88
37.2k
{
89
37.2k
  if (!m_resolveInsideCode)
90
0
    return false;
91
37.2k
  m_resolver.setScope(&_for);
92
37.2k
  return true;
93
37.2k
}
94
95
void ReferencesResolver::endVisit(ForStatement const& _for)
96
37.2k
{
97
37.2k
  if (!m_resolveInsideCode)
98
0
    return;
99
37.2k
  m_resolver.setScope(_for.scope());
100
37.2k
}
101
102
void ReferencesResolver::endVisit(VariableDeclarationStatement const& _varDeclStatement)
103
68.4k
{
104
68.4k
  if (!m_resolveInsideCode)
105
0
    return;
106
68.4k
  for (auto const& var: _varDeclStatement.declarations())
107
75.7k
    if (var)
108
75.7k
      m_resolver.activateVariable(var->name());
109
68.4k
}
110
111
bool ReferencesResolver::visit(VariableDeclaration const& _varDecl)
112
372k
{
113
372k
  if (_varDecl.documentation())
114
0
    resolveInheritDoc(*_varDecl.documentation(), _varDecl.annotation());
115
116
372k
  return true;
117
372k
}
118
119
bool ReferencesResolver::visit(Identifier const& _identifier)
120
1.13M
{
121
1.13M
  auto declarations = m_resolver.nameFromCurrentScope(_identifier.name());
122
1.13M
  if (declarations.empty())
123
0
  {
124
0
    string suggestions = m_resolver.similarNameSuggestions(_identifier.name());
125
0
    string errorMessage = "Undeclared identifier.";
126
0
    if (!suggestions.empty())
127
0
    {
128
0
      if ("\"" + _identifier.name() + "\"" == suggestions)
129
0
        errorMessage += " " + std::move(suggestions) + " is not (or not yet) visible at this point.";
130
0
      else
131
0
        errorMessage += " Did you mean " + std::move(suggestions) + "?";
132
0
    }
133
0
    m_errorReporter.declarationError(7576_error, _identifier.location(), errorMessage);
134
0
  }
135
1.13M
  else if (declarations.size() == 1)
136
1.13M
    _identifier.annotation().referencedDeclaration = declarations.front();
137
0
  else
138
0
    _identifier.annotation().candidateDeclarations = declarations;
139
1.13M
  return false;
140
1.13M
}
141
142
bool ReferencesResolver::visit(FunctionDefinition const& _functionDefinition)
143
79.3k
{
144
79.3k
  m_returnParameters.push_back(_functionDefinition.returnParameterList().get());
145
146
79.3k
  if (_functionDefinition.documentation())
147
21.6k
    resolveInheritDoc(*_functionDefinition.documentation(), _functionDefinition.annotation());
148
149
79.3k
  return true;
150
79.3k
}
151
152
void ReferencesResolver::endVisit(FunctionDefinition const&)
153
79.3k
{
154
79.3k
  solAssert(!m_returnParameters.empty(), "");
155
79.3k
  m_returnParameters.pop_back();
156
79.3k
}
157
158
bool ReferencesResolver::visit(ModifierDefinition const& _modifierDefinition)
159
0
{
160
0
  m_returnParameters.push_back(nullptr);
161
162
0
  if (_modifierDefinition.documentation())
163
0
    resolveInheritDoc(*_modifierDefinition.documentation(), _modifierDefinition.annotation());
164
165
0
  return true;
166
0
}
167
168
void ReferencesResolver::endVisit(ModifierDefinition const&)
169
0
{
170
0
  solAssert(!m_returnParameters.empty(), "");
171
0
  m_returnParameters.pop_back();
172
0
}
173
174
void ReferencesResolver::endVisit(IdentifierPath const& _path)
175
63.6k
{
176
63.6k
  std::vector<Declaration const*> declarations = m_resolver.pathFromCurrentScopeWithAllDeclarations(_path.path());
177
63.6k
  if (declarations.empty())
178
0
  {
179
0
    m_errorReporter.fatalDeclarationError(7920_error, _path.location(), "Identifier not found or not unique.");
180
0
    return;
181
0
  }
182
183
63.6k
  _path.annotation().referencedDeclaration = declarations.back();
184
63.6k
  _path.annotation().pathDeclarations = std::move(declarations);
185
63.6k
}
186
187
bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
188
0
{
189
0
  m_yulAnnotation = &_inlineAssembly.annotation();
190
0
  (*this)(_inlineAssembly.operations());
191
0
  m_yulAnnotation = nullptr;
192
193
0
  return false;
194
0
}
195
196
bool ReferencesResolver::visit(Return const& _return)
197
539k
{
198
539k
  solAssert(!m_returnParameters.empty(), "");
199
539k
  _return.annotation().functionReturnParameters = m_returnParameters.back();
200
539k
  return true;
201
539k
}
202
203
void ReferencesResolver::operator()(yul::FunctionDefinition const& _function)
204
0
{
205
0
  solAssert(nativeLocationOf(_function) == originLocationOf(_function), "");
206
0
  validateYulIdentifierName(_function.name, nativeLocationOf(_function));
207
0
  for (yul::TypedName const& varName: _function.parameters + _function.returnVariables)
208
0
  {
209
0
    solAssert(nativeLocationOf(varName) == originLocationOf(varName), "");
210
0
    validateYulIdentifierName(varName.name, nativeLocationOf(varName));
211
0
  }
212
213
0
  bool wasInsideFunction = m_yulInsideFunction;
214
0
  m_yulInsideFunction = true;
215
0
  this->operator()(_function.body);
216
0
  m_yulInsideFunction = wasInsideFunction;
217
0
}
218
219
void ReferencesResolver::operator()(yul::Identifier const& _identifier)
220
0
{
221
0
  solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), "");
222
223
0
  static set<string> suffixes{"slot", "offset", "length", "address", "selector"};
224
0
  string suffix;
225
0
  for (string const& s: suffixes)
226
0
    if (boost::algorithm::ends_with(_identifier.name.str(), "." + s))
227
0
      suffix = s;
228
229
  // Could also use `pathFromCurrentScope`, split by '.'.
230
  // If we do that, suffix should only be set for when it has a special
231
  // meaning, not for normal identifierPaths.
232
0
  auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str());
233
0
  if (!suffix.empty())
234
0
  {
235
    // special mode to access storage variables
236
0
    if (!declarations.empty())
237
      // the special identifier exists itself, we should not allow that.
238
0
      return;
239
0
    string realName = _identifier.name.str().substr(0, _identifier.name.str().size() - suffix.size() - 1);
240
0
    solAssert(!realName.empty(), "Empty name.");
241
0
    declarations = m_resolver.nameFromCurrentScope(realName);
242
0
    if (!declarations.empty())
243
      // To support proper path resolution, we have to use pathFromCurrentScope.
244
0
      solAssert(!util::contains(realName, '.'), "");
245
0
  }
246
0
  if (declarations.size() > 1)
247
0
  {
248
0
    m_errorReporter.declarationError(
249
0
      4718_error,
250
0
      nativeLocationOf(_identifier),
251
0
      "Multiple matching identifiers. Resolving overloaded identifiers is not supported."
252
0
    );
253
0
    return;
254
0
  }
255
0
  else if (declarations.size() == 0)
256
0
  {
257
0
    if (
258
0
      boost::algorithm::ends_with(_identifier.name.str(), "_slot") ||
259
0
      boost::algorithm::ends_with(_identifier.name.str(), "_offset")
260
0
    )
261
0
      m_errorReporter.declarationError(
262
0
        9467_error,
263
0
        nativeLocationOf(_identifier),
264
0
        "Identifier not found. Use \".slot\" and \".offset\" to access storage variables."
265
0
      );
266
0
    return;
267
0
  }
268
0
  if (auto var = dynamic_cast<VariableDeclaration const*>(declarations.front()))
269
0
    if (var->isLocalVariable() && m_yulInsideFunction)
270
0
    {
271
0
      m_errorReporter.declarationError(
272
0
        6578_error,
273
0
        nativeLocationOf(_identifier),
274
0
        "Cannot access local Solidity variables from inside an inline assembly function."
275
0
      );
276
0
      return;
277
0
    }
278
279
0
  m_yulAnnotation->externalReferences[&_identifier].suffix = move(suffix);
280
0
  m_yulAnnotation->externalReferences[&_identifier].declaration = declarations.front();
281
0
}
282
283
void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
284
0
{
285
0
  for (auto const& identifier: _varDecl.variables)
286
0
  {
287
0
    solAssert(nativeLocationOf(identifier) == originLocationOf(identifier), "");
288
0
    validateYulIdentifierName(identifier.name, nativeLocationOf(identifier));
289
290
0
    if (
291
0
      auto declarations = m_resolver.nameFromCurrentScope(identifier.name.str());
292
0
      !declarations.empty()
293
0
    )
294
0
    {
295
0
      SecondarySourceLocation ssl;
296
0
      for (auto const* decl: declarations)
297
0
        ssl.append("The shadowed declaration is here:", decl->location());
298
0
      if (!ssl.infos.empty())
299
0
        m_errorReporter.declarationError(
300
0
          3859_error,
301
0
          nativeLocationOf(identifier),
302
0
          ssl,
303
0
          "This declaration shadows a declaration outside the inline assembly block."
304
0
        );
305
0
    }
306
0
  }
307
308
0
  if (_varDecl.value)
309
0
    visit(*_varDecl.value);
310
0
}
311
312
void ReferencesResolver::resolveInheritDoc(StructuredDocumentation const& _documentation, StructurallyDocumentedAnnotation& _annotation)
313
21.6k
{
314
21.6k
  switch (_annotation.docTags.count("inheritdoc"))
315
21.6k
  {
316
21.6k
  case 0:
317
21.6k
    break;
318
0
  case 1:
319
0
  {
320
0
    string const& name = _annotation.docTags.find("inheritdoc")->second.content;
321
0
    if (name.empty())
322
0
    {
323
0
      m_errorReporter.docstringParsingError(
324
0
        1933_error,
325
0
        _documentation.location(),
326
0
        "Expected contract name following documentation tag @inheritdoc."
327
0
      );
328
0
      return;
329
0
    }
330
331
0
    vector<string> path;
332
0
    boost::split(path, name, boost::is_any_of("."));
333
0
    if (any_of(path.begin(), path.end(), [](auto& _str) { return _str.empty(); }))
334
0
    {
335
0
      m_errorReporter.docstringParsingError(
336
0
        5967_error,
337
0
        _documentation.location(),
338
0
        "Documentation tag @inheritdoc reference \"" +
339
0
        name +
340
0
        "\" is malformed."
341
0
      );
342
0
      return;
343
0
    }
344
0
    Declaration const* result = m_resolver.pathFromCurrentScope(path);
345
346
0
    if (result == nullptr)
347
0
    {
348
0
      m_errorReporter.docstringParsingError(
349
0
        9397_error,
350
0
        _documentation.location(),
351
0
        "Documentation tag @inheritdoc references inexistent contract \"" +
352
0
        name +
353
0
        "\"."
354
0
      );
355
0
      return;
356
0
    }
357
0
    else
358
0
    {
359
0
      _annotation.inheritdocReference = dynamic_cast<ContractDefinition const*>(result);
360
361
0
      if (!_annotation.inheritdocReference)
362
0
        m_errorReporter.docstringParsingError(
363
0
          1430_error,
364
0
          _documentation.location(),
365
0
          "Documentation tag @inheritdoc reference \"" +
366
0
          name +
367
0
          "\" is not a contract."
368
0
        );
369
0
    }
370
0
    break;
371
0
  }
372
0
  default:
373
0
    m_errorReporter.docstringParsingError(
374
0
      5142_error,
375
0
      _documentation.location(),
376
0
      "Documentation tag @inheritdoc can only be given once."
377
0
    );
378
0
    break;
379
21.6k
  }
380
21.6k
}
381
382
void ReferencesResolver::validateYulIdentifierName(yul::YulString _name, SourceLocation const& _location)
383
0
{
384
0
  if (util::contains(_name.str(), '.'))
385
0
    m_errorReporter.declarationError(
386
0
      3927_error,
387
0
      _location,
388
0
      "User-defined identifiers in inline assembly cannot contain '.'."
389
0
    );
390
391
0
  if (set<string>{"this", "super", "_"}.count(_name.str()))
392
0
    m_errorReporter.declarationError(
393
0
      4113_error,
394
0
      _location,
395
0
      "The identifier name \"" + _name.str() + "\" is reserved."
396
0
    );
397
0
}