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 <libsolidity/ast/AST.h>
20 #include <libsolidity/ast/ASTUtils.h>
21
22 #include <libsolutil/Algorithms.h>
23
24 namespace solidity::frontend
25 {
26
isConstantVariableRecursive(VariableDeclaration const & _varDecl)27 bool isConstantVariableRecursive(VariableDeclaration const& _varDecl)
28 {
29 solAssert(_varDecl.isConstant(), "Constant variable expected");
30
31 auto visitor = [](VariableDeclaration const& _variable, util::CycleDetector<VariableDeclaration>& _cycleDetector, size_t _depth)
32 {
33 solAssert(_depth < 256, "Recursion depth limit reached");
34 if (!_variable.value())
35 // This should result in an error later on.
36 return;
37
38 if (auto referencedVarDecl = dynamic_cast<VariableDeclaration const*>(
39 ASTNode::referencedDeclaration(*_variable.value()))
40 )
41 if (referencedVarDecl->isConstant())
42 _cycleDetector.run(*referencedVarDecl);
43 };
44
45 return util::CycleDetector<VariableDeclaration>(visitor).run(_varDecl) != nullptr;
46 }
47
rootConstVariableDeclaration(VariableDeclaration const & _varDecl)48 VariableDeclaration const* rootConstVariableDeclaration(VariableDeclaration const& _varDecl)
49 {
50 solAssert(_varDecl.isConstant(), "Constant variable expected");
51 solAssert(!isConstantVariableRecursive(_varDecl), "Recursive declaration");
52
53 VariableDeclaration const* rootDecl = &_varDecl;
54 Identifier const* identifier;
55 while ((identifier = dynamic_cast<Identifier const*>(rootDecl->value().get())))
56 {
57 auto referencedVarDecl = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration);
58 if (!referencedVarDecl || !referencedVarDecl->isConstant())
59 return nullptr;
60 rootDecl = referencedVarDecl;
61 }
62 return rootDecl;
63 }
64
65 }
66