Coverage Report

Created: 2025-09-08 08:10

/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 solidity::yul;
33
34
VarNameCleaner::VarNameCleaner(
35
  Block const& _ast,
36
  Dialect const& _dialect,
37
  std::set<YulName> _namesToKeep
38
):
39
  m_dialect{_dialect},
40
  m_namesToKeep{std::move(_namesToKeep)},
41
  m_translatedNames{}
42
71.5k
{
43
71.5k
  for (auto const& statement: _ast.statements)
44
252k
    if (std::holds_alternative<FunctionDefinition>(statement))
45
180k
      m_namesToKeep.insert(std::get<FunctionDefinition>(statement).name);
46
71.5k
  m_usedNames = m_namesToKeep;
47
71.5k
}
48
49
void VarNameCleaner::operator()(FunctionDefinition& _funDef)
50
180k
{
51
180k
  yulAssert(!m_insideFunction, "");
52
180k
  m_insideFunction = true;
53
54
180k
  std::set<YulName> globalUsedNames = std::move(m_usedNames);
55
180k
  m_usedNames = m_namesToKeep;
56
180k
  std::map<YulName, YulName> globalTranslatedNames;
57
180k
  swap(globalTranslatedNames, m_translatedNames);
58
59
180k
  renameVariables(_funDef.parameters);
60
180k
  renameVariables(_funDef.returnVariables);
61
180k
  ASTModifier::operator()(_funDef);
62
63
180k
  swap(globalUsedNames, m_usedNames);
64
180k
  swap(globalTranslatedNames, m_translatedNames);
65
66
180k
  m_insideFunction = false;
67
180k
}
68
69
void VarNameCleaner::operator()(VariableDeclaration& _varDecl)
70
534k
{
71
534k
  renameVariables(_varDecl.variables);
72
534k
  ASTModifier::operator()(_varDecl);
73
534k
}
74
75
void VarNameCleaner::renameVariables(std::vector<NameWithDebugData>& _variables)
76
896k
{
77
896k
  for (NameWithDebugData& variable: _variables)
78
756k
  {
79
756k
    auto newName = findCleanName(variable.name);
80
756k
    if (newName != variable.name)
81
611k
    {
82
611k
      m_translatedNames[variable.name] = newName;
83
611k
      variable.name = newName;
84
611k
    }
85
756k
    m_usedNames.insert(variable.name);
86
756k
  }
87
896k
}
88
89
void VarNameCleaner::operator()(Identifier& _identifier)
90
1.35M
{
91
1.35M
  auto name = m_translatedNames.find(_identifier.name);
92
1.35M
  if (name != m_translatedNames.end())
93
1.08M
    _identifier.name = name->second;
94
1.35M
}
95
96
YulName VarNameCleaner::findCleanName(YulName const& _name) const
97
756k
{
98
756k
  auto newName = stripSuffix(_name);
99
756k
  if (!isUsedName(newName))
100
347k
    return newName;
101
102
  // create new name with suffix (by finding a free identifier)
103
2.49M
  for (size_t i = 1; i < std::numeric_limits<decltype(i)>::max(); ++i)
104
2.49M
  {
105
2.49M
    YulName newNameSuffixed = YulName{newName.str() + "_" + std::to_string(i)};
106
2.49M
    if (!isUsedName(newNameSuffixed))
107
409k
      return newNameSuffixed;
108
2.49M
  }
109
0
  yulAssert(false, "Exhausted by attempting to find an available suffix.");
110
0
}
111
112
bool VarNameCleaner::isUsedName(YulName const& _name) const
113
3.24M
{
114
3.24M
  return isRestrictedIdentifier(m_dialect, _name.str()) || m_usedNames.contains(_name);
115
3.24M
}
116
117
YulName VarNameCleaner::stripSuffix(YulName const& _name) const
118
756k
{
119
756k
  static std::regex const suffixRegex("(_+[0-9]+)+$");
120
121
756k
  std::smatch suffixMatch;
122
756k
  if (regex_search(_name.str(), suffixMatch, suffixRegex))
123
606k
    return {YulName{suffixMatch.prefix().str()}};
124
149k
  return _name;
125
756k
}