aboutsummaryrefslogtreecommitdiffstats
path: root/src/Utils.h
blob: dd92a961a98e0c7f05eb74df3dc4b25b0f722043 (plain)
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/*
   This file is part of the clazy static checker.

  Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
  Author: Sérgio Martins <sergio.martins@kdab.com>

  Copyright (C) 2015-2016 Sergio Martins <smartins@kde.org>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library 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
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public License
  along with this library; see the file COPYING.LIB.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#ifndef MOREWARNINGS_UTILS_H
#define MOREWARNINGS_UTILS_H

#include "clazy_export.h"
#include "SourceCompatibilityHelpers.h"

#include <clang/Basic/SourceManager.h>
#include <clang/AST/DeclCXX.h>
#include <clang/AST/Expr.h>
#include <clang/AST/ExprCXX.h>
#include <clang/AST/Stmt.h>
#include <clang/AST/DeclTemplate.h>

#include <string>
#include <vector>
#include <map>

// TODO: this is a dumping ground, most of these functions should be moved to the other *Utils classes

namespace clang {
    class CXXNamedCastExpr;
    class CXXRecordDecl;
    class CXXMemberCallExpr;
    class CXXConstructExpr;
    class CompilerInstance;
    class ClassTemplateSpecializationDecl;
    class Decl;
    class ParentMap;
    class SourceManager;
    class Stmt;
    class SourceLocation;
    class ExprWithCleanups;
    class ValueDecl;
    class ConditionalOperator;
    class CXXMethodDecl;
    class BinaryOperator;
}

struct StmtBodyRange;

namespace Utils {
    /// Returns true if the class has at least one constexpr ctor
    CLAZYLIB_EXPORT bool hasConstexprCtor(clang::CXXRecordDecl *decl);

    /// Returns the type we're casting *from*
    CLAZYLIB_EXPORT clang::CXXRecordDecl * namedCastInnerDecl(clang::CXXNamedCastExpr *staticOrDynamicCast);

    /// Returns the type we're casting *to*
    CLAZYLIB_EXPORT clang::CXXRecordDecl * namedCastOuterDecl(clang::CXXNamedCastExpr *staticOrDynamicCast);

    /// Returns the class declaration from a variable declaration
    // So, if the var decl is "Foo f"; it returns the declaration of Foo
    CLAZYLIB_EXPORT clang::CXXRecordDecl * recordFromVarDecl(clang::Decl *);

    /// Returns the template specialization from a variable declaration
    // So, if the var decl is "QList<Foo> f;", returns the template specialization QList<Foo>
    CLAZYLIB_EXPORT clang::ClassTemplateSpecializationDecl * templateSpecializationFromVarDecl(clang::Decl *);

    /// Returns true if all the child member function calls are const functions.
    CLAZYLIB_EXPORT bool allChildrenMemberCallsConst(clang::Stmt *stm);

    /// Returns true if at least a UnaryOperator, BinaryOperator or non-const function call is found
    CLAZYLIB_EXPORT bool childsHaveSideEffects(clang::Stmt *stm);

    /// Receives a member call, such as "list.reserve()" and returns the declaration of the variable list
    // such as "QList<F> list"
    CLAZYLIB_EXPORT clang::ValueDecl * valueDeclForMemberCall(clang::CXXMemberCallExpr *);

    /// Receives an operator call, such as "list << fooo" and returns the declaration of the variable list
    // such as "QList<F> list"
    CLAZYLIB_EXPORT clang::ValueDecl * valueDeclForOperatorCall(clang::CXXOperatorCallExpr *);

    // overload
    CLAZYLIB_EXPORT clang::ValueDecl * valueDeclForCallExpr(clang::CallExpr *);

    // Returns true of this value decl is a member variable of a class or struct
    // returns null if not
    CLAZYLIB_EXPORT clang::CXXRecordDecl* isMemberVariable(clang::ValueDecl *);

    // Returns true if a body of statements contains a non const member call on object declared by varDecl
    // For example:
    // Foo foo; // this is the varDecl
    // while (bar) { foo.setValue(); // non-const call }
    CLAZYLIB_EXPORT bool containsNonConstMemberCall(clang::ParentMap *map, clang::Stmt *body, const clang::VarDecl *varDecl);

    // Returns true if there's an assignment to varDecl in body
    // Example: our_var = something_else
    CLAZYLIB_EXPORT bool isAssignedTo(clang::Stmt *body, const clang::VarDecl *varDecl);

    // Returns true if a body of statements contains a function call that takes our variable (varDecl)
    // By ref or pointer
    CLAZYLIB_EXPORT bool isPassedToFunction(const StmtBodyRange &bodyRange, const clang::VarDecl *varDecl,
                                            bool byRefOrPtrOnly);

    // Returns true if we take the address of varDecl, such as: &foo
    CLAZYLIB_EXPORT bool addressIsTaken(const clang::CompilerInstance &ci, clang::Stmt *body,
                                        const clang::ValueDecl *valDecl);

    // QString::fromLatin1("foo")    -> true
    // QString::fromLatin1("foo", 1) -> false
    CLAZYLIB_EXPORT bool callHasDefaultArguments(clang::CallExpr *expr);

    // If there's a child of type StringLiteral, returns true
    // if allowEmpty is false, "" will be ignored
    CLAZYLIB_EXPORT bool containsStringLiteral(clang::Stmt *, bool allowEmpty = true, int depth = -1);

    CLAZYLIB_EXPORT bool isInsideOperatorCall(clang::ParentMap *map, clang::Stmt *s,
                                              const std::vector<llvm::StringRef> &anyOf);

    CLAZYLIB_EXPORT bool insideCTORCall(clang::ParentMap *map, clang::Stmt *s,
                                        const std::vector<llvm::StringRef> &anyOf);

    // returns true if the ternary operator has two string literal arguments, such as:
    // foo ? "bar" : "baz"
    CLAZYLIB_EXPORT bool ternaryOperatorIsOfStringLiteral(clang::ConditionalOperator*);

    CLAZYLIB_EXPORT bool isAssignOperator(clang::CXXOperatorCallExpr *op,
                                          llvm::StringRef className,
                                          llvm::StringRef argumentType, const clang::LangOptions &lo);

    CLAZYLIB_EXPORT bool isImplicitCastTo(clang::Stmt *, const std::string &);

    CLAZYLIB_EXPORT bool presumedLocationsEqual(const clang::PresumedLoc &l1, const clang::PresumedLoc &l2);


    // Returns the list of methods with name methodName that the class/struct record contains
    CLAZYLIB_EXPORT std::vector<clang::CXXMethodDecl*> methodsFromString(const clang::CXXRecordDecl *record,
                                                                         const std::string &methodName);

    // Returns the most derived class. (CXXMemberCallExpr::getRecordDecl() return the first base class with the method)
    // The returned callee is the name of the variable on which the member call was made:
    // o1->foo() => "o1"
    // foo() => "this"
    CLAZYLIB_EXPORT const clang::CXXRecordDecl* recordForMemberCall(clang::CXXMemberCallExpr *call,
                                                                    std::string &implicitCallee);

    CLAZYLIB_EXPORT bool isAscii(clang::StringLiteral *lt);

    // Checks if Statement s inside an operator* call
    CLAZYLIB_EXPORT bool isInDerefExpression(clang::Stmt *s, clang::ParentMap *map);

    // For a a chain called expression like foo().bar().baz() returns a list of calls
    // {baz(), bar(), foo()}

    // the parameter lastCallExpr to pass would be baz()
    // No need to specify the other callexprs, they are children of the first one, since the AST looks like:
    // - baz
    // -- bar
    // --- foo
    CLAZYLIB_EXPORT std::vector<clang::CallExpr *> callListForChain(clang::CallExpr *lastCallExpr);

    // Returns the first base class
    CLAZYLIB_EXPORT clang::CXXRecordDecl * rootBaseClass(clang::CXXRecordDecl *derived);

    // Returns the copy ctor for this class
    CLAZYLIB_EXPORT clang::CXXConstructorDecl *copyCtor(clang::CXXRecordDecl *);

    // Returns the copy-assignment operator for this class
    CLAZYLIB_EXPORT clang::CXXMethodDecl *copyAssign(clang::CXXRecordDecl *);

    CLAZYLIB_EXPORT bool hasMember(clang::CXXRecordDecl *record, const std::string &memberTypeName);

    /**
     * Returns true if record is a shared pointer (boost, Qt or stl only).
     */
    CLAZYLIB_EXPORT bool isSharedPointer(clang::CXXRecordDecl *record);

    /**
     * Returns true if varDecl is initialized externally.
     * Example:
     *     QList<Foo> list = getList(); // true
     *     QList<int> list = list2;     // true
     *     QList<int> list = {1, 2, 3}; // false
     *     QList<int> list;             // false
     */
    CLAZYLIB_EXPORT bool isInitializedExternally(clang::VarDecl *varDecl);

    /**
     * Returns true if declStmt refers to varDecl
     */
    CLAZYLIB_EXPORT bool referencesVarDecl(clang::DeclStmt *declStmt, clang::VarDecl *varDecl);

    /**
     * Returns true if the body of a function is empty.
     * Returns false if either function or it's body are null.
     */
    CLAZYLIB_EXPORT bool functionHasEmptyBody(clang::FunctionDecl *func);

    /**
     * If stm is an UnaryOperator or BinaryOperator that writes to the variable it returns the expression
     * that represents the variable (Usually a MemberExpr or DeclRefExpr for local variables).
     *
     * Otherwise returns nullptr.
     *
     * The operators that write to the variable are operator=, operator+=, operator++, etc.
     */
    CLAZYLIB_EXPORT clang::Expr* isWriteOperator(clang::Stmt *stm);

    /**
     * Gets the UserDefinedLiteral of type @p type which is somewhere in the ast of @p stm.
     * Returns nullptr if there's no such UserDefinedLiteral.
     */
    CLAZYLIB_EXPORT clang::UserDefinedLiteral* userDefinedLiteral(clang::Stmt *stm, const std::string &type,
                                                                  const clang::LangOptions &lo);

    /**
     * Returns the function parameters fom @p func
     * This should be used instead of calling FunctionDecl::params() since it changed signature in
     * clang 3.9.
     */
    CLAZYLIB_EXPORT
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 8
    clang::FunctionDecl::param_range
#else
    clang::ArrayRef<clang::ParmVarDecl *>
#endif
    functionParameters(clang::FunctionDecl *func);


    /**
     * For the given ctor, and ctor param, returns the ctor member initializers that used that param.
     * Example:
     * MyCtor(int a, int b) : c(a), d(b) {}
     * auto result = Utils::ctorInitializer(MyCtor, b); // Result is the statement "d(b)"
     */
    CLAZYLIB_EXPORT std::vector<clang::CXXCtorInitializer*> ctorInitializer(clang::CXXConstructorDecl *ctor,
                                                                            clang::ParmVarDecl *param);

   /**
    * Returns true if a ctor initializer contains a std::move()
    * Example
    * MyCtor(Foo a) : c(move(a)) {} // Would return true for this init list
    */
    CLAZYLIB_EXPORT bool ctorInitializerContainsMove(clang::CXXCtorInitializer*);

    // Overload that recieves a vector and returns true if any ctor initializer contains a move()
    CLAZYLIB_EXPORT bool ctorInitializerContainsMove(const std::vector<clang::CXXCtorInitializer*> &);

    /**
     * Returns the filename for the source location loc
     */
    CLAZYLIB_EXPORT std::string filenameForLoc(clang::SourceLocation loc, const clang::SourceManager &sm);

    /**
     * Returns the location after the lexer token that is at loc.
     * For example:
     *     emit sig();
     * If loc refers to the location of 'emit', then this function will return the source location if
     * the sig() call.
     */
    CLAZYLIB_EXPORT clang::SourceLocation locForNextToken(clang::SourceLocation loc,
                                                          const clang::SourceManager &sm,
                                                          const clang::LangOptions &lo);

    inline bool isMainFile(const clang::SourceManager &sm, clang::SourceLocation loc)
    {
        if (loc.isMacroID())
            loc = sm.getExpansionLoc(loc);

        return sm.isInFileID(loc, sm.getMainFileID());
    }

    /**
     * Returns true if the string literal contains escaped bytes, such as \x12, \123, \u00F6.
     */
    bool literalContainsEscapedBytes(clang::StringLiteral *lt, const clang::SourceManager &sm, const clang::LangOptions &lo);

    /**
     * Returns true if this method overrides one from the base class
     */
    inline bool methodOverrides(clang::CXXMethodDecl *method)
    {
        return method && method->isVirtual() && method->size_overridden_methods() > 0;
    }
}

#endif