Coverage Report

Created: 2022-08-24 06:43

/src/solidity/libyul/ScopeFiller.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
 * Module responsible for registering identifiers inside their scopes.
20
 */
21
22
#include <libyul/ScopeFiller.h>
23
24
#include <libyul/AST.h>
25
#include <libyul/Scope.h>
26
#include <libyul/AsmAnalysisInfo.h>
27
#include <libyul/Exceptions.h>
28
29
#include <liblangutil/ErrorReporter.h>
30
31
#include <libsolutil/CommonData.h>
32
33
#include <memory>
34
#include <functional>
35
36
using namespace std;
37
using namespace solidity;
38
using namespace solidity::yul;
39
using namespace solidity::util;
40
using namespace solidity::langutil;
41
42
ScopeFiller::ScopeFiller(AsmAnalysisInfo& _info, ErrorReporter& _errorReporter):
43
  m_info(_info), m_errorReporter(_errorReporter)
44
63.5k
{
45
63.5k
  m_currentScope = &scope(nullptr);
46
63.5k
}
47
48
bool ScopeFiller::operator()(ExpressionStatement const& _expr)
49
513k
{
50
513k
  return std::visit(*this, _expr.expression);
51
513k
}
52
53
bool ScopeFiller::operator()(VariableDeclaration const& _varDecl)
54
326k
{
55
326k
  for (auto const& variable: _varDecl.variables)
56
330k
    if (!registerVariable(variable, nativeLocationOf(_varDecl), *m_currentScope))
57
15
      return false;
58
326k
  return true;
59
326k
}
60
61
bool ScopeFiller::operator()(FunctionDefinition const& _funDef)
62
271k
{
63
271k
  auto virtualBlock = m_info.virtualBlocks[&_funDef] = make_shared<Block>();
64
271k
  Scope& varScope = scope(virtualBlock.get());
65
271k
  varScope.superScope = m_currentScope;
66
271k
  m_currentScope = &varScope;
67
271k
  varScope.functionScope = true;
68
69
271k
  bool success = true;
70
271k
  for (auto const& var: _funDef.parameters + _funDef.returnVariables)
71
512k
    if (!registerVariable(var, nativeLocationOf(_funDef), varScope))
72
1
      success = false;
73
74
271k
  if (!(*this)(_funDef.body))
75
0
    success = false;
76
77
271k
  yulAssert(m_currentScope == &varScope, "");
78
271k
  m_currentScope = m_currentScope->superScope;
79
80
271k
  return success;
81
271k
}
82
83
bool ScopeFiller::operator()(If const& _if)
84
182k
{
85
182k
  return (*this)(_if.body);
86
182k
}
87
88
bool ScopeFiller::operator()(Switch const& _switch)
89
9.58k
{
90
9.58k
  bool success = true;
91
9.58k
  for (auto const& _case: _switch.cases)
92
19.9k
    if (!(*this)(_case.body))
93
0
      success = false;
94
9.58k
  return success;
95
9.58k
}
96
97
bool ScopeFiller::operator()(ForLoop const& _forLoop)
98
28.8k
{
99
28.8k
  Scope* originalScope = m_currentScope;
100
101
28.8k
  bool success = true;
102
28.8k
  if (!(*this)(_forLoop.pre))
103
0
    success = false;
104
28.8k
  m_currentScope = &scope(&_forLoop.pre);
105
28.8k
  if (!std::visit(*this, *_forLoop.condition))
106
0
    success = false;
107
28.8k
  if (!(*this)(_forLoop.body))
108
0
    success = false;
109
28.8k
  if (!(*this)(_forLoop.post))
110
0
    success = false;
111
112
28.8k
  m_currentScope = originalScope;
113
114
28.8k
  return success;
115
28.8k
}
116
117
bool ScopeFiller::operator()(Block const& _block)
118
654k
{
119
654k
  bool success = true;
120
654k
  scope(&_block).superScope = m_currentScope;
121
654k
  m_currentScope = &scope(&_block);
122
123
  // First visit all functions to make them create
124
  // an entry in the scope according to their visibility.
125
654k
  for (auto const& s: _block.statements)
126
1.76M
    if (holds_alternative<FunctionDefinition>(s))
127
271k
      if (!registerFunction(std::get<FunctionDefinition>(s)))
128
0
        success = false;
129
654k
  for (auto const& s: _block.statements)
130
1.76M
    if (!std::visit(*this, s))
131
17
      success = false;
132
133
654k
  m_currentScope = m_currentScope->superScope;
134
654k
  return success;
135
654k
}
136
137
bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const& _location, Scope& _scope)
138
843k
{
139
843k
  if (!_scope.registerVariable(_name.name, _name.type))
140
16
  {
141
    //@TODO secondary location
142
16
    m_errorReporter.declarationError(
143
16
      1395_error,
144
16
      _location,
145
16
      "Variable name " + _name.name.str() + " already taken in this scope."
146
16
    );
147
16
    return false;
148
16
  }
149
843k
  return true;
150
843k
}
151
152
bool ScopeFiller::registerFunction(FunctionDefinition const& _funDef)
153
271k
{
154
271k
  vector<Scope::YulType> parameters;
155
271k
  for (auto const& parameter: _funDef.parameters)
156
313k
    parameters.emplace_back(parameter.type);
157
271k
  vector<Scope::YulType> returns;
158
271k
  for (auto const& returnVariable: _funDef.returnVariables)
159
199k
    returns.emplace_back(returnVariable.type);
160
271k
  if (!m_currentScope->registerFunction(_funDef.name, std::move(parameters), std::move(returns)))
161
0
  {
162
    //@TODO secondary location
163
0
    m_errorReporter.declarationError(
164
0
      6052_error,
165
0
      nativeLocationOf(_funDef),
166
0
      "Function name " + _funDef.name.str() + " already taken in this scope."
167
0
    );
168
0
    return false;
169
0
  }
170
271k
  return true;
171
271k
}
172
173
Scope& ScopeFiller::scope(Block const* _block)
174
1.67M
{
175
1.67M
  auto& scope = m_info.scopes[_block];
176
1.67M
  if (!scope)
177
989k
    scope = make_shared<Scope>();
178
1.67M
  return *scope;
179
1.67M
}