aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/formal/VariableUsage.cpp
blob: 4e96059da0b91ce07c1f4b28cf174958bd0e090e (plain) (blame)
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
/*
    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/>.
*/

#include <libsolidity/formal/VariableUsage.h>

#include <libsolidity/ast/ASTVisitor.h>

using namespace std;
using namespace dev;
using namespace dev::solidity;

VariableUsage::VariableUsage(ASTNode const& _node)
{
    auto nodeFun = [&](ASTNode const& n) -> bool
    {
        if (Identifier const* identifier = dynamic_cast<decltype(identifier)>(&n))
        {
            Declaration const* declaration = identifier->annotation().referencedDeclaration;
            solAssert(declaration, "");
            if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
                if (
                    varDecl->isLocalVariable() &&
                    identifier->annotation().lValueRequested &&
                    varDecl->annotation().type->isValueType()
                )
                    m_touchedVariable[&n] = varDecl;
        }
        return true;
    };
    auto edgeFun = [&](ASTNode const& _parent, ASTNode const& _child)
    {
        if (m_touchedVariable.count(&_child) || m_children.count(&_child))
            m_children[&_parent].push_back(&_child);
    };

    ASTReduce reducer(nodeFun, edgeFun);
    _node.accept(reducer);
}

vector<Declaration const*> VariableUsage::touchedVariables(ASTNode const& _node) const
{
    if (!m_children.count(&_node) && !m_touchedVariable.count(&_node))
        return {};

    set<Declaration const*> touched;
    vector<ASTNode const*> toVisit;
    toVisit.push_back(&_node);

    while (!toVisit.empty())
    {
        ASTNode const* n = toVisit.back();
        toVisit.pop_back();
        if (m_children.count(n))
        {
            solAssert(!m_touchedVariable.count(n), "");
            toVisit += m_children.at(n);
        }
        else
        {
            solAssert(m_touchedVariable.count(n), "");
            touched.insert(m_touchedVariable.at(n));
        }
    }

    return {touched.begin(), touched.end()};
}