aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/analysis/TypeChecker.h
blob: 7d718ff90d2085ff2d0309a4831e69691b18a05c (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
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
    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/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2015
 * Type analyzer and checker.
 */

#pragma once

#include <liblangutil/EVMVersion.h>

#include <libsolidity/ast/Types.h>
#include <libsolidity/ast/ASTAnnotations.h>
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTVisitor.h>

namespace langutil
{
class ErrorReporter;
}

namespace dev
{
namespace solidity
{

/**
 * The module that performs type analysis on the AST, checks the applicability of operations on
 * those types and stores errors for invalid operations.
 * Provides a way to retrieve the type of an AST node.
 */
class TypeChecker: private ASTConstVisitor
{
public:
    /// @param _errorReporter provides the error logging functionality.
    TypeChecker(EVMVersion _evmVersion, langutil::ErrorReporter& _errorReporter):
        m_evmVersion(_evmVersion),
        m_errorReporter(_errorReporter)
    {}

    /// Performs type checking on the given contract and all of its sub-nodes.
    /// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
    bool checkTypeRequirements(ASTNode const& _contract);

    /// @returns the type of an expression and asserts that it is present.
    TypePointer const& type(Expression const& _expression) const;
    /// @returns the type of the given variable and throws if the type is not present
    /// (this can happen for variables with non-explicit types before their types are resolved)
    TypePointer const& type(VariableDeclaration const& _variable) const;

private:

    bool visit(ContractDefinition const& _contract) override;
    void checkContractAbstractFunctions(ContractDefinition const& _contract);
    void checkContractBaseConstructorArguments(ContractDefinition const& _contract);
    void annotateBaseConstructorArguments(
        ContractDefinition const& _currentContract,
        FunctionDefinition const* _baseConstructor,
        ASTNode const* _argumentNode
    );
    /// Checks that different functions with external visibility end up having different
    /// external argument types (i.e. different signature).
    void checkContractExternalTypeClashes(ContractDefinition const& _contract);
    /// Checks that all requirements for a library are fulfilled if this is a library.
    void checkLibraryRequirements(ContractDefinition const& _contract);
    /// Checks (and warns) if a tuple assignment might cause unexpected overwrites in storage.
    /// Should only be called if the left hand side is tuple-typed.
    void checkDoubleStorageAssignment(Assignment const& _assignment);
    // Checks whether the expression @arg _expression can be assigned from type @arg _type
    // and reports an error, if not.
    void checkExpressionAssignment(Type const& _type, Expression const& _expression);

    /// Performs type checks for ``abi.decode(bytes memory, (...))`` and returns the
    /// vector of return types (which is basically the second argument) if successful. It returns
    /// the empty vector on error.
    TypePointers typeCheckABIDecodeAndRetrieveReturnType(
        FunctionCall const& _functionCall,
        bool _abiEncoderV2
    );

    /// Performs type checks and determines result types for type conversion FunctionCall nodes.
    TypePointer typeCheckTypeConversionAndRetrieveReturnType(
        FunctionCall const& _functionCall
    );

    /// Performs type checks on function call and struct ctor FunctionCall nodes (except for kind ABIDecode).
    void typeCheckFunctionCall(
        FunctionCall const& _functionCall,
        FunctionTypePointer _functionType
    );

    /// Performs general number and type checks of arguments against function call and struct ctor FunctionCall node parameters.
    void typeCheckFunctionGeneralChecks(
        FunctionCall const& _functionCall,
        FunctionTypePointer _functionType
    );

    /// Performs general checks and checks specific to ABI encode functions
    void typeCheckABIEncodeFunctions(
        FunctionCall const& _functionCall,
        FunctionTypePointer _functionType
    );

    void endVisit(InheritanceSpecifier const& _inheritance) override;
    void endVisit(UsingForDirective const& _usingFor) override;
    bool visit(StructDefinition const& _struct) override;
    bool visit(FunctionDefinition const& _function) override;
    bool visit(VariableDeclaration const& _variable) override;
    /// We need to do this manually because we want to pass the bases of the current contract in
    /// case this is a base constructor call.
    void visitManually(ModifierInvocation const& _modifier, std::vector<ContractDefinition const*> const& _bases);
    bool visit(EventDefinition const& _eventDef) override;
    void endVisit(FunctionTypeName const& _funType) override;
    bool visit(InlineAssembly const& _inlineAssembly) override;
    bool visit(IfStatement const& _ifStatement) override;
    bool visit(WhileStatement const& _whileStatement) override;
    bool visit(ForStatement const& _forStatement) override;
    void endVisit(Return const& _return) override;
    bool visit(EmitStatement const&) override { m_insideEmitStatement = true; return true; }
    void endVisit(EmitStatement const& _emit) override;
    bool visit(VariableDeclarationStatement const& _variable) override;
    void endVisit(ExpressionStatement const& _statement) override;
    bool visit(Conditional const& _conditional) override;
    bool visit(Assignment const& _assignment) override;
    bool visit(TupleExpression const& _tuple) override;
    void endVisit(BinaryOperation const& _operation) override;
    bool visit(UnaryOperation const& _operation) override;
    bool visit(FunctionCall const& _functionCall) override;
    void endVisit(NewExpression const& _newExpression) override;
    bool visit(MemberAccess const& _memberAccess) override;
    bool visit(IndexAccess const& _indexAccess) override;
    bool visit(Identifier const& _identifier) override;
    void endVisit(ElementaryTypeNameExpression const& _expr) override;
    void endVisit(Literal const& _literal) override;

    bool contractDependenciesAreCyclic(
        ContractDefinition const& _contract,
        std::set<ContractDefinition const*> const& _seenContracts = std::set<ContractDefinition const*>()
    ) const;

    /// @returns the referenced declaration and throws on error.
    Declaration const& dereference(Identifier const& _identifier) const;
    /// @returns the referenced declaration and throws on error.
    Declaration const& dereference(UserDefinedTypeName const& _typeName) const;

    /// Runs type checks on @a _expression to infer its type and then checks that it is implicitly
    /// convertible to @a _expectedType.
    bool expectType(Expression const& _expression, Type const& _expectedType);
    /// Runs type checks on @a _expression to infer its type and then checks that it is an LValue.
    void requireLValue(Expression const& _expression);

    ContractDefinition const* m_scope = nullptr;

    EVMVersion m_evmVersion;

    /// Flag indicating whether we are currently inside an EmitStatement.
    bool m_insideEmitStatement = false;

    /// Flag indicating whether we are currently inside a StructDefinition.
    bool m_insideStruct = false;

    langutil::ErrorReporter& m_errorReporter;
};

}
}