forked from ethereum/solidity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathASTUtils.cpp
140 lines (115 loc) · 4.41 KB
/
ASTUtils.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ASTUtils.h>
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolutil/Algorithms.h>
namespace solidity::frontend
{
ASTNode const* locateInnermostASTNode(int _offsetInFile, SourceUnit const& _sourceUnit)
{
ASTNode const* innermostMatch = nullptr;
auto locator = SimpleASTVisitor(
[&](ASTNode const& _node) -> bool
{
// In the AST parent location always covers the whole child location.
// The parent is visited first so to get the innermost node we simply
// take the last one that still contains the offset.
if (!_node.location().containsOffset(_offsetInFile))
return false;
innermostMatch = &_node;
return true;
},
[](ASTNode const&) {}
);
_sourceUnit.accept(locator);
return innermostMatch;
}
bool isConstantVariableRecursive(VariableDeclaration const& _varDecl)
{
solAssert(_varDecl.isConstant(), "Constant variable expected");
auto visitor = [](VariableDeclaration const& _variable, util::CycleDetector<VariableDeclaration>& _cycleDetector, size_t _depth)
{
solAssert(_depth < 256, "Recursion depth limit reached");
if (!_variable.value())
// This should result in an error later on.
return;
if (auto referencedVarDecl = dynamic_cast<VariableDeclaration const*>(
ASTNode::referencedDeclaration(*_variable.value()))
)
if (referencedVarDecl->isConstant())
_cycleDetector.run(*referencedVarDecl);
};
return util::CycleDetector<VariableDeclaration>(visitor).run(_varDecl) != nullptr;
}
VariableDeclaration const* rootConstVariableDeclaration(VariableDeclaration const& _varDecl)
{
solAssert(_varDecl.isConstant(), "Constant variable expected");
solAssert(!isConstantVariableRecursive(_varDecl), "Recursive declaration");
VariableDeclaration const* rootDecl = &_varDecl;
Identifier const* identifier;
while ((identifier = dynamic_cast<Identifier const*>(rootDecl->value().get())))
{
auto referencedVarDecl = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration);
if (!referencedVarDecl || !referencedVarDecl->isConstant())
return nullptr;
rootDecl = referencedVarDecl;
}
return rootDecl;
}
Expression const* resolveOuterUnaryTuples(Expression const* _expr)
{
while (auto const* tupleExpression = dynamic_cast<TupleExpression const*>(_expr))
if (tupleExpression->components().size() == 1)
_expr = tupleExpression->components().front().get();
else
break;
return _expr;
}
Type const* type(Expression const& _expression)
{
solAssert(!!_expression.annotation().type, "Type requested but not present.");
return _expression.annotation().type;
}
Type const* type(VariableDeclaration const& _variable)
{
solAssert(!!_variable.annotation().type, "Type requested but not present.");
return _variable.annotation().type;
}
bigint contractStorageSizeUpperBound(ContractDefinition const& _contract, VariableDeclaration::Location _location)
{
solAssert(_location == VariableDeclaration::Location::Unspecified || _location == VariableDeclaration::Location::Transient);
bigint size = 0;
for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
for (VariableDeclaration const* variable: contract->stateVariables())
if (
!(variable->isConstant() || variable->immutable()) &&
variable->referenceLocation() == _location
)
size += variable->annotation().type->storageSizeUpperBound();
return size;
}
u256 layoutBaseForInheritanceHierarchy(ContractDefinition const& _topLevelContract, DataLocation _location)
{
if (_location != DataLocation::Storage)
{
solAssert(_location == DataLocation::Transient);
return 0;
}
if (auto const* storageLayoutSpecifier = _topLevelContract.storageLayoutSpecifier())
return *storageLayoutSpecifier->annotation().baseSlot;
return 0;
}
}