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