Coverage Report

Created: 2026-08-14 07:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libsolidity/codegen/ir/IRGeneratorForStatements.h
Line
Count
Source
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
 * Component that translates Solidity code into Yul at statement level and below.
20
 */
21
22
#pragma once
23
24
#include <libsolidity/ast/ASTVisitor.h>
25
#include <libsolidity/codegen/ir/IRLValue.h>
26
#include <libsolidity/codegen/ir/IRVariable.h>
27
#include <libsolidity/interface/OptimiserSettings.h>
28
29
#include <functional>
30
31
namespace solidity::frontend
32
{
33
34
class IRGenerationContext;
35
class YulUtilFunctions;
36
37
/**
38
 * Base class for the statement generator.
39
 * Encapsulates access to the yul code stream and handles source code locations.
40
 */
41
class IRGeneratorForStatementsBase: public ASTConstVisitor
42
{
43
public:
44
  IRGeneratorForStatementsBase(IRGenerationContext& _context):
45
15.6k
    m_context(_context)
46
15.6k
  {}
47
48
  virtual std::string code() const;
49
  std::ostringstream& appendCode(bool _addLocationComment = true);
50
protected:
51
  void setLocation(ASTNode const& _node);
52
  langutil::SourceLocation m_currentLocation = {};
53
  langutil::SourceLocation m_lastLocation = {};
54
  IRGenerationContext& m_context;
55
private:
56
  std::ostringstream m_code;
57
};
58
59
/**
60
 * Component that translates Solidity's AST into Yul at statement level and below.
61
 * It is an AST visitor that appends to an internal string buffer.
62
 */
63
class IRGeneratorForStatements: public IRGeneratorForStatementsBase
64
{
65
public:
66
  IRGeneratorForStatements(
67
    IRGenerationContext& _context,
68
    YulUtilFunctions& _utils,
69
    OptimiserSettings& _optimiserSettings,
70
    std::function<std::string()> _placeholderCallback = {}
71
  ):
72
15.6k
    IRGeneratorForStatementsBase(_context),
73
15.6k
    m_placeholderCallback(std::move(_placeholderCallback)),
74
15.6k
    m_utils(_utils),
75
15.6k
    m_optimiserSettings(_optimiserSettings)
76
15.6k
  {}
77
78
  std::string code() const override;
79
80
  /// Generate the code for the statements in the block;
81
  void generate(Block const& _block);
82
83
  /// Generates code to initialize the given state variable.
84
  void initializeStateVar(VariableDeclaration const& _varDecl);
85
  /// Generates code to initialize the given local variable.
86
  void initializeLocalVar(VariableDeclaration const& _varDecl);
87
88
  /// Calculates expression's value and returns variable where it was stored
89
  IRVariable evaluateExpression(Expression const& _expression, Type const& _to);
90
91
  /// Defines @a _var using the value of @a _value while performing type conversions, if required.
92
  void define(IRVariable const& _var, IRVariable const& _value)
93
45.3k
  {
94
45.3k
    bool _declare = true;
95
45.3k
    declareAssign(_var, _value, _declare);
96
45.3k
  }
97
98
  /// Defines @a _var using the value of @a _value while performing type conversions, if required.
99
  /// It also cleans the value of the variable.
100
  void defineAndCleanup(IRVariable const& _var, IRVariable const& _value)
101
0
  {
102
0
    bool _forceCleanup = true;
103
0
    bool _declare = true;
104
0
    declareAssign(_var, _value, _declare, _forceCleanup);
105
0
  }
106
107
  /// @returns the name of a function that computes the value of the given constant
108
  /// and also generates the function.
109
  std::string constantValueFunction(VariableDeclaration const& _constant);
110
111
  void endVisit(VariableDeclarationStatement const& _variableDeclaration) override;
112
  bool visit(Conditional const& _conditional) override;
113
  bool visit(Assignment const& _assignment) override;
114
  bool visit(TupleExpression const& _tuple) override;
115
  void endVisit(PlaceholderStatement const& _placeholder) override;
116
  bool visit(Block const& _block) override;
117
  void endVisit(Block const& _block) override;
118
  bool visit(IfStatement const& _ifStatement) override;
119
  bool visit(ForStatement const& _forStatement) override;
120
  bool visit(WhileStatement const& _whileStatement) override;
121
  bool visit(Continue const& _continueStatement) override;
122
  bool visit(Break const& _breakStatement) override;
123
  void endVisit(Return const& _return) override;
124
  bool visit(UnaryOperation const& _unaryOperation) override;
125
  bool visit(BinaryOperation const& _binOp) override;
126
  void endVisit(FunctionCall const& _funCall) override;
127
  void endVisit(FunctionCallOptions const& _funCallOptions) override;
128
  bool visit(MemberAccess const& _memberAccess) override;
129
  void endVisit(MemberAccess const& _memberAccess) override;
130
  bool visit(InlineAssembly const& _inlineAsm) override;
131
  void endVisit(IndexAccess const& _indexAccess) override;
132
  void endVisit(IndexRangeAccess const& _indexRangeAccess) override;
133
  void endVisit(Identifier const& _identifier) override;
134
  bool visit(Literal const& _literal) override;
135
  void endVisit(RevertStatement const& _revertStatement) override;
136
137
  bool visit(TryStatement const& _tryStatement) override;
138
  bool visit(TryCatchClause const& _tryCatchClause) override;
139
140
private:
141
  /// Handles all catch cases of a try statement, except the success-case.
142
  void handleCatch(TryStatement const& _tryStatement);
143
  void handleCatchFallback(TryCatchClause const& _fallback);
144
145
  /// Generates code to revert with an error. The error arguments are assumed to
146
  /// be already evaluated and available in local IRVariables, but not yet
147
  /// converted.
148
  void revertWithError(
149
    std::string const& _signature,
150
    std::vector<Type const*> const& _parameterTypes,
151
    std::vector<ASTPointer<Expression const>> const& _errorArguments
152
  );
153
154
  void handleVariableReference(
155
    VariableDeclaration const& _variable,
156
    Expression const& _referencingExpression
157
  );
158
159
  /// Appends code to call an external function with the given arguments.
160
  /// All involved expressions have already been visited.
161
  void appendExternalFunctionCall(
162
    FunctionCall const& _functionCall,
163
    std::vector<ASTPointer<Expression const>> const& _arguments
164
  );
165
166
  /// Appends code for .call / .delegatecall / .staticcall.
167
  /// All involved expressions have already been visited.
168
  void appendBareCall(
169
    FunctionCall const& _functionCall,
170
    std::vector<ASTPointer<Expression const>> const& _arguments
171
  );
172
173
  /// Requests and assigns the internal ID of the referenced function to the referencing
174
  /// expression and adds the function to the internal dispatch.
175
  /// If the function is called right away, it does nothing.
176
  void assignInternalFunctionIDIfNotCalledDirectly(
177
    Expression const& _expression,
178
    FunctionDefinition const& _referencedFunction
179
  );
180
181
  /// Generates the required conversion code and @returns an IRVariable referring to the value of @a _variable
182
  IRVariable convert(IRVariable const& _variable, Type const& _to);
183
184
  /// Generates the required conversion code and @returns an IRVariable referring to the value of @a _variable
185
  /// It also cleans the value of the variable.
186
  IRVariable convertAndCleanup(IRVariable const& _from, Type const& _to);
187
188
  /// @returns a Yul expression representing the current value of @a _expression,
189
  /// converted to type @a _to if it does not yet have that type.
190
  std::string expressionAsType(Expression const& _expression, Type const& _to);
191
192
  /// @returns a Yul expression representing the current value of @a _expression,
193
  /// converted to type @a _to if it does not yet have that type.
194
  /// It also cleans the value, in case it already has type @a _to.
195
  std::string expressionAsCleanedType(Expression const& _expression, Type const& _to);
196
197
  /// @returns an output stream that can be used to define @a _var using a function call or
198
  /// single stack slot expression.
199
  std::ostream& define(IRVariable const& _var);
200
201
  /// Assigns @a _var to the value of @a _value while performing type conversions, if required.
202
7.57k
  void assign(IRVariable const& _var, IRVariable const& _value) { declareAssign(_var, _value, false); }
203
  /// Declares variable @a _var.
204
  void declare(IRVariable const& _var);
205
206
  void declareAssign(IRVariable const& _var, IRVariable const& _value, bool _define, bool _forceCleanup = false);
207
208
  /// @returns an IRVariable with the zero
209
  /// value of @a _type.
210
  /// @param _splitFunctionTypes if false, returns two zeroes
211
  IRVariable zeroValue(Type const& _type, bool _splitFunctionTypes = true);
212
213
  void appendAndOrOperatorCode(BinaryOperation const& _binOp);
214
  void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr);
215
216
  /// @returns code to perform the given binary operation in the given type on the two values.
217
  std::string binaryOperation(
218
    langutil::Token _op,
219
    Type const& _type,
220
    std::string const& _left,
221
    std::string const& _right
222
  );
223
224
  /// @returns code to perform the given shift operation.
225
  /// The operation itself will be performed in the type of the value,
226
  /// while the amount to shift can have its own type.
227
  std::string shiftOperation(langutil::Token _op, IRVariable const& _value, IRVariable const& _shiftAmount);
228
229
  /// Assigns the value of @a _value to the lvalue @a _lvalue.
230
  void writeToLValue(IRLValue const& _lvalue, IRVariable const& _value);
231
232
  /// @returns a fresh IR variable containing the value of the lvalue @a _lvalue.
233
  IRVariable readFromLValue(IRLValue const& _lvalue);
234
235
  /// Stores the given @a _lvalue in m_currentLValue, if it will be written to (willBeWrittenTo). Otherwise
236
  /// defines the expression @a _expression by reading the value from @a _lvalue.
237
  void setLValue(Expression const& _expression, IRLValue _lvalue);
238
  void generateLoop(
239
    Statement const& _body,
240
    Expression const* _conditionExpression,
241
    Statement const*  _initExpression = nullptr,
242
    ExpressionStatement const* _loopExpression = nullptr,
243
    bool _isDoWhile = false,
244
    bool _isSimpleCounterLoop = false
245
  );
246
247
  static Type const& type(Expression const& _expression);
248
249
  std::string linkerSymbol(ContractDefinition const& _library) const;
250
251
  std::function<std::string()> m_placeholderCallback;
252
  YulUtilFunctions& m_utils;
253
  std::optional<IRLValue> m_currentLValue;
254
  OptimiserSettings m_optimiserSettings;
255
};
256
257
}