Coverage Report

Created: 2022-08-24 06:31

/src/solidity/libyul/optimiser/VarNameCleaner.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
#include <libyul/optimiser/VarNameCleaner.h>
20
#include <libyul/optimiser/OptimizerUtilities.h>
21
#include <libyul/AST.h>
22
#include <libyul/Dialect.h>
23
24
#include <algorithm>
25
#include <cctype>
26
#include <climits>
27
#include <iterator>
28
#include <string>
29
#include <regex>
30
#include <limits>
31
32
using namespace std;
33
using namespace solidity::yul;
34
35
VarNameCleaner::VarNameCleaner(
36
  Block const& _ast,
37
  Dialect const& _dialect,
38
  set<YulString> _namesToKeep
39
):
40
  m_dialect{_dialect},
41
  m_namesToKeep{std::move(_namesToKeep)},
42
  m_translatedNames{}
43
0
{
44
0
  for (auto const& statement: _ast.statements)
45
0
    if (holds_alternative<FunctionDefinition>(statement))
46
0
      m_namesToKeep.insert(std::get<FunctionDefinition>(statement).name);
47
0
  m_usedNames = m_namesToKeep;
48
0
}
49
50
void VarNameCleaner::operator()(FunctionDefinition& _funDef)
51
0
{
52
0
  yulAssert(!m_insideFunction, "");
53
0
  m_insideFunction = true;
54
55
0
  set<YulString> globalUsedNames = std::move(m_usedNames);
56
0
  m_usedNames = m_namesToKeep;
57
0
  map<YulString, YulString> globalTranslatedNames;
58
0
  swap(globalTranslatedNames, m_translatedNames);
59
60
0
  renameVariables(_funDef.parameters);
61
0
  renameVariables(_funDef.returnVariables);
62
0
  ASTModifier::operator()(_funDef);
63
64
0
  swap(globalUsedNames, m_usedNames);
65
0
  swap(globalTranslatedNames, m_translatedNames);
66
67
0
  m_insideFunction = false;
68
0
}
69
70
void VarNameCleaner::operator()(VariableDeclaration& _varDecl)
71
0
{
72
0
  renameVariables(_varDecl.variables);
73
0
  ASTModifier::operator()(_varDecl);
74
0
}
75
76
void VarNameCleaner::renameVariables(vector<TypedName>& _variables)
77
0
{
78
0
  for (TypedName& typedName: _variables)
79
0
  {
80
0
    auto newName = findCleanName(typedName.name);
81
0
    if (newName != typedName.name)
82
0
    {
83
0
      m_translatedNames[typedName.name] = newName;
84
0
      typedName.name = newName;
85
0
    }
86
0
    m_usedNames.insert(typedName.name);
87
0
  }
88
0
}
89
90
void VarNameCleaner::operator()(Identifier& _identifier)
91
0
{
92
0
  auto name = m_translatedNames.find(_identifier.name);
93
0
  if (name != m_translatedNames.end())
94
0
    _identifier.name = name->second;
95
0
}
96
97
YulString VarNameCleaner::findCleanName(YulString const& _name) const
98
0
{
99
0
  auto newName = stripSuffix(_name);
100
0
  if (!isUsedName(newName))
101
0
    return newName;
102
103
  // create new name with suffix (by finding a free identifier)
104
0
  for (size_t i = 1; i < numeric_limits<decltype(i)>::max(); ++i)
105
0
  {
106
0
    YulString newNameSuffixed = YulString{newName.str() + "_" + to_string(i)};
107
0
    if (!isUsedName(newNameSuffixed))
108
0
      return newNameSuffixed;
109
0
  }
110
0
  yulAssert(false, "Exhausted by attempting to find an available suffix.");
111
0
}
112
113
bool VarNameCleaner::isUsedName(YulString const& _name) const
114
0
{
115
0
  return isRestrictedIdentifier(m_dialect, _name) || m_usedNames.count(_name);
116
0
}
117
118
YulString VarNameCleaner::stripSuffix(YulString const& _name) const
119
0
{
120
0
  static regex const suffixRegex("(_+[0-9]+)+$");
121
122
0
  smatch suffixMatch;
123
0
  if (regex_search(_name.str(), suffixMatch, suffixRegex))
124
0
    return {YulString{suffixMatch.prefix().str()}};
125
0
  return _name;
126
0
}