Coverage Report

Created: 2022-08-24 06:55

/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
59.9k
{
44
59.9k
  for (auto const& statement: _ast.statements)
45
134k
    if (holds_alternative<FunctionDefinition>(statement))
46
74.8k
      m_namesToKeep.insert(std::get<FunctionDefinition>(statement).name);
47
59.9k
  m_usedNames = m_namesToKeep;
48
59.9k
}
49
50
void VarNameCleaner::operator()(FunctionDefinition& _funDef)
51
74.8k
{
52
74.8k
  yulAssert(!m_insideFunction, "");
53
74.8k
  m_insideFunction = true;
54
55
74.8k
  set<YulString> globalUsedNames = std::move(m_usedNames);
56
74.8k
  m_usedNames = m_namesToKeep;
57
74.8k
  map<YulString, YulString> globalTranslatedNames;
58
74.8k
  swap(globalTranslatedNames, m_translatedNames);
59
60
74.8k
  renameVariables(_funDef.parameters);
61
74.8k
  renameVariables(_funDef.returnVariables);
62
74.8k
  ASTModifier::operator()(_funDef);
63
64
74.8k
  swap(globalUsedNames, m_usedNames);
65
74.8k
  swap(globalTranslatedNames, m_translatedNames);
66
67
74.8k
  m_insideFunction = false;
68
74.8k
}
69
70
void VarNameCleaner::operator()(VariableDeclaration& _varDecl)
71
378k
{
72
378k
  renameVariables(_varDecl.variables);
73
378k
  ASTModifier::operator()(_varDecl);
74
378k
}
75
76
void VarNameCleaner::renameVariables(vector<TypedName>& _variables)
77
528k
{
78
528k
  for (TypedName& typedName: _variables)
79
448k
  {
80
448k
    auto newName = findCleanName(typedName.name);
81
448k
    if (newName != typedName.name)
82
411k
    {
83
411k
      m_translatedNames[typedName.name] = newName;
84
411k
      typedName.name = newName;
85
411k
    }
86
448k
    m_usedNames.insert(typedName.name);
87
448k
  }
88
528k
}
89
90
void VarNameCleaner::operator()(Identifier& _identifier)
91
1.25M
{
92
1.25M
  auto name = m_translatedNames.find(_identifier.name);
93
1.25M
  if (name != m_translatedNames.end())
94
1.16M
    _identifier.name = name->second;
95
1.25M
}
96
97
YulString VarNameCleaner::findCleanName(YulString const& _name) const
98
448k
{
99
448k
  auto newName = stripSuffix(_name);
100
448k
  if (!isUsedName(newName))
101
124k
    return newName;
102
103
  // create new name with suffix (by finding a free identifier)
104
1.53M
  for (size_t i = 1; i < numeric_limits<decltype(i)>::max(); ++i)
105
1.53M
  {
106
1.53M
    YulString newNameSuffixed = YulString{newName.str() + "_" + to_string(i)};
107
1.53M
    if (!isUsedName(newNameSuffixed))
108
324k
      return newNameSuffixed;
109
1.53M
  }
110
0
  yulAssert(false, "Exhausted by attempting to find an available suffix.");
111
0
}
112
113
bool VarNameCleaner::isUsedName(YulString const& _name) const
114
1.98M
{
115
1.98M
  return isRestrictedIdentifier(m_dialect, _name) || m_usedNames.count(_name);
116
1.98M
}
117
118
YulString VarNameCleaner::stripSuffix(YulString const& _name) const
119
448k
{
120
448k
  static regex const suffixRegex("(_+[0-9]+)+$");
121
122
448k
  smatch suffixMatch;
123
448k
  if (regex_search(_name.str(), suffixMatch, suffixRegex))
124
402k
    return {YulString{suffixMatch.prefix().str()}};
125
46.0k
  return _name;
126
448k
}