File: checkclass.h

package info (click to toggle)
cppcheck 2.17.1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 25,384 kB
  • sloc: cpp: 263,341; python: 19,737; ansic: 7,953; sh: 1,018; makefile: 996; xml: 994; cs: 291
file content (342 lines) | stat: -rw-r--r-- 16,833 bytes parent folder | download
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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/* -*- C++ -*-
 * Cppcheck - A tool for static C/C++ code analysis
 * Copyright (C) 2007-2025 Cppcheck team.
 *
 * This program 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.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */

//---------------------------------------------------------------------------
#ifndef checkclassH
#define checkclassH
//---------------------------------------------------------------------------

#include "check.h"
#include "config.h"
#include "symboldatabase.h"

#include <cstdint>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>

class ErrorLogger;
class Settings;
class Tokenizer;
class Token;

/// @addtogroup Checks
/// @{


/** @brief %Check classes. Uninitialized member variables, non-conforming operators, missing virtual destructor, etc */
class CPPCHECKLIB CheckClass : public Check {
    friend class TestClass;
    friend class TestConstructors;
    friend class TestUnusedPrivateFunction;

public:
    /** @brief This constructor is used when registering the CheckClass */
    CheckClass() : Check(myName()) {}

    /** @brief Set of the STL types whose operator[] is not const */
    static const std::set<std::string> stl_containers_not_const;

private:
    /** @brief This constructor is used when running checks. */
    CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger);

    /** @brief Run checks on the normal token list */
    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;

    /** @brief %Check that all class constructors are ok */
    void constructors();

    /** @brief %Check that constructors with single parameter are explicit,
     *  if they has to be.*/
    void checkExplicitConstructors();

    /** @brief %Check that all private functions are called */
    void privateFunctions();

    /**
     * @brief %Check that the memsets are valid.
     * The 'memset' function can do dangerous things if used wrong. If it
     * is used on STL containers for instance it will clear all its data
     * and then the STL container may leak memory or worse have an invalid state.
     * It can also overwrite the virtual table.
     * Important: The checking doesn't work on simplified tokens list.
     */
    void checkMemset();
    void checkMemsetType(const Scope *start, const Token *tok, const Scope *type, bool allocation, std::set<const Scope *> parsedTypes);

    /** @brief 'operator=' should return reference to *this */
    void operatorEqRetRefThis();    // Warning upon no "return *this;"

    /** @brief 'operator=' should check for assignment to self */
    void operatorEqToSelf();    // Warning upon no check for assignment to self

    /** @brief The destructor in a base class should be virtual */
    void virtualDestructor();

    /** @brief warn for "this-x". The indented code may be "this->x"  */
    void thisSubtraction();

    /** @brief can member function be const? */
    void checkConst();

    /** @brief Check initializer list order */
    void initializerListOrder();

    /** @brief Suggest using initialization list */
    void initializationListUsage();

    /** @brief Check for initialization of a member with itself */
    void checkSelfInitialization();

    void copyconstructors();

    /** @brief call of virtual function in constructor/destructor */
    void checkVirtualFunctionCallInConstructor();

    /** @brief Check duplicated inherited members */
    void checkDuplInheritedMembers();

    /** @brief Check that copy constructor and operator defined together */
    void checkCopyCtorAndEqOperator();

    /** @brief Check that the override keyword is used when overriding virtual functions */
    void checkOverride();

    /** @brief Check that the overriden function is not identical to the base function */
    void checkUselessOverride();

    /** @brief Check that large members are returned by reference from getter function */
    void checkReturnByReference();

    /** @brief When "self pointer" is destroyed, 'this' might become invalid. */
    void checkThisUseAfterFree();

    /** @brief Unsafe class check - const reference member */
    void checkUnsafeClassRefMember();

    /** @brief Parse current TU and extract file info */
    Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings) const override;

    Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override;

    /** @brief Analyse all file infos for all TU */
    bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override;

    const SymbolDatabase* mSymbolDatabase{};

    // Reporting errors..
    void noConstructorError(const Token *tok, const std::string &classname, bool isStruct);
    void noExplicitConstructorError(const Token *tok, const std::string &classname, bool isStruct);
    //void copyConstructorMallocError(const Token *cctor, const Token *alloc, const std::string& var_name);
    void copyConstructorShallowCopyError(const Token *tok, const std::string& varname);
    void noCopyConstructorError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive);
    void noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive);
    void noDestructorError(const Scope *scope, bool isdefault, const Token *alloc);
    void uninitVarError(const Token *tok, bool isprivate, Function::Type functionType, const std::string &classname, const std::string &varname, bool derived, bool inconclusive);
    void uninitVarError(const Token *tok, const std::string &classname, const std::string &varname);
    void missingMemberCopyError(const Token *tok, Function::Type functionType, const std::string& classname, const std::string& varname);
    void operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive);
    void unusedPrivateFunctionError(const Token *tok, const std::string &classname, const std::string &funcname);
    void memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type, bool isContainer = false);
    void memsetErrorReference(const Token *tok, const std::string &memfunc, const std::string &type);
    void memsetErrorFloat(const Token *tok, const std::string &type);
    void mallocOnClassError(const Token* tok, const std::string &memfunc, const Token* classTok, const std::string &classname);
    void mallocOnClassWarning(const Token* tok, const std::string &memfunc, const Token* classTok);
    void virtualDestructorError(const Token *tok, const std::string &Base, const std::string &Derived, bool inconclusive);
    void thisSubtractionError(const Token *tok);
    void operatorEqRetRefThisError(const Token *tok);
    void operatorEqShouldBeLeftUnimplementedError(const Token *tok);
    void operatorEqMissingReturnStatementError(const Token *tok, bool error);
    void operatorEqToSelfError(const Token *tok);
    void checkConstError(const Token *tok, const std::string &classname, const std::string &funcname, bool suggestStatic, bool foundAllBaseClasses = true);
    void checkConstError2(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &funcname, bool suggestStatic, bool foundAllBaseClasses = true);
    void initializerListError(const Token *tok1,const Token *tok2, const std::string & classname, const std::string &varname, const std::string& argname = {});
    void suggestInitializationList(const Token *tok, const std::string& varname);
    void selfInitializationError(const Token* tok, const std::string& varname);
    void pureVirtualFunctionCallInConstructorError(const Function * scopeFunction, const std::list<const Token *> & tokStack, const std::string &purefuncname);
    void virtualFunctionCallInConstructorError(const Function * scopeFunction, const std::list<const Token *> & tokStack, const std::string &funcname);
    void duplInheritedMembersError(const Token* tok1, const Token* tok2, const std::string &derivedName, const std::string &baseName, const std::string &memberName, bool derivedIsStruct, bool baseIsStruct, bool isFunction = false);
    void copyCtorAndEqOperatorError(const Token *tok, const std::string &classname, bool isStruct, bool hasCopyCtor);
    void overrideError(const Function *funcInBase, const Function *funcInDerived);
    void uselessOverrideError(const Function *funcInBase, const Function *funcInDerived, bool isSameCode = false);
    void returnByReferenceError(const Function *func, const Variable* var);
    void thisUseAfterFree(const Token *self, const Token *free, const Token *use);
    void unsafeClassRefMemberError(const Token *tok, const std::string &varname);
    void checkDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase);

    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;

    static std::string myName() {
        return "Class";
    }

    std::string classInfo() const override {
        return "Check the code for each class.\n"
               "- Missing constructors and copy constructors\n"
               //"- Missing allocation of memory in copy constructor\n"
               "- Constructors which should be explicit\n"
               "- Are all variables initialized by the constructors?\n"
               "- Are all variables assigned by 'operator='?\n"
               "- Warn if memset, memcpy etc are used on a class\n"
               "- Warn if memory for classes is allocated with malloc()\n"
               "- If it's a base class, check that the destructor is virtual\n"
               "- Are there unused private functions?\n"
               "- 'operator=' should check for assignment to self\n"
               "- Constness for member functions\n"
               "- Order of initializations\n"
               "- Suggest usage of initialization list\n"
               "- Initialization of a member with itself\n"
               "- Suspicious subtraction from 'this'\n"
               "- Call of pure virtual function in constructor/destructor\n"
               "- Duplicated inherited data members\n"
               // disabled for now "- If 'copy constructor' defined, 'operator=' also should be defined and vice versa\n"
               "- Check that arbitrary usage of public interface does not result in division by zero\n"
               "- Delete \"self pointer\" and then access 'this'\n"
               "- Check that the 'override' keyword is used when overriding virtual functions\n"
               "- Check that the 'one definition rule' is not violated\n";
    }

    // operatorEqRetRefThis helper functions
    void checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last);
    void checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last, std::set<const Function*>& analyzedFunctions);

    // operatorEqToSelf helper functions
    bool hasAllocation(const Function *func, const Scope* scope) const;
    bool hasAllocation(const Function *func, const Scope* scope, const Token *start, const Token *end) const;
    bool hasAllocationInIfScope(const Function *func, const Scope* scope, const Token *ifStatementScopeStart) const;
    static bool hasAssignSelf(const Function *func, const Token *rhs, const Token *&out_ifStatementScopeStart);
    enum class Bool : std::uint8_t { TRUE, FALSE, BAILOUT };
    static Bool isInverted(const Token *tok, const Token *rhs);
    static const Token * getIfStmtBodyStart(const Token *tok, const Token *rhs);

    // checkConst helper functions
    bool isMemberVar(const Scope *scope, const Token *tok) const;
    static bool isMemberFunc(const Scope *scope, const Token *tok);
    static bool isConstMemberFunc(const Scope *scope, const Token *tok);
    enum class MemberAccess : std::uint8_t { NONE, SELF, MEMBER };
    bool checkConstFunc(const Scope *scope, const Function *func, MemberAccess& memberAccessed) const;

    // constructors helper function
    /** @brief Information about a member variable. Used when checking for uninitialized variables */
    struct Usage {
        explicit Usage(const Variable *var) : var(var) {}

        /** Variable that this usage is for */
        const Variable *var;

        /** @brief has this variable been assigned? */
        bool assign{};

        /** @brief has this variable been initialized? */
        bool init{};
    };

    static bool isBaseClassMutableMemberFunc(const Token *tok, const Scope *scope);

    /**
     * @brief Create usage list that contains all scope members and also members
     * of base classes without constructors.
     * @param scope current class scope
     */
    static std::vector<Usage> createUsageList(const Scope *scope);

    /**
     * @brief assign a variable in the varlist
     * @param usageList reference to usage vector
     * @param varid id of variable to mark assigned
     */
    static void assignVar(std::vector<Usage> &usageList, nonneg int varid);

    /**
     * @brief assign a variable in the varlist
     * @param usageList reference to usage vector
     * @param vartok variable token
     */
    static void assignVar(std::vector<Usage> &usageList, const Token *vartok);

    /**
     * @brief initialize a variable in the varlist
     * @param usageList reference to usage vector
     * @param varid id of variable to mark initialized
     */
    static void initVar(std::vector<Usage> &usageList, nonneg int varid);

    /**
     * @brief set all variables in list assigned
     * @param usageList reference to usage vector
     */
    static void assignAllVar(std::vector<Usage> &usageList);

    /**
     * @brief set all variable in list assigned, if visible from given scope
     * @param usageList reference to usage vector
     * @param scope scope from which usages must be visible
     */
    static void assignAllVarsVisibleFromScope(std::vector<Usage> &usageList, const Scope *scope);

    /**
     * @brief set all variables in list not assigned and not initialized
     * @param usageList reference to usage vector
     */
    static void clearAllVar(std::vector<Usage> &usageList);

    /**
     * @brief parse a scope for a constructor or member function and set the "init" flags in the provided varlist
     * @param func reference to the function that should be checked
     * @param callstack the function doesn't look into recursive function calls.
     * @param scope pointer to variable Scope
     * @param usage reference to usage vector
     */
    void initializeVarList(const Function &func, std::list<const Function *> &callstack, const Scope *scope, std::vector<Usage> &usage) const;

    /**
     * @brief gives a list of tokens where virtual functions are called directly or indirectly
     * @param function function to be checked
     * @param virtualFunctionCallsMap map of results for already checked functions
     * @return list of tokens where pure virtual functions are called
     */
    const std::list<const Token *> & getVirtualFunctionCalls(
        const Function & function,
        std::map<const Function *, std::list<const Token *>> & virtualFunctionCallsMap);

    /**
     * @brief looks for the first virtual function call stack
     * @param virtualFunctionCallsMap map of results obtained from getVirtualFunctionCalls
     * @param callToken token where pure virtual function is called directly or indirectly
     * @param[in,out] pureFuncStack list to append the stack
     */
    static void getFirstVirtualFunctionCallStack(
        std::map<const Function *, std::list<const Token *>> & virtualFunctionCallsMap,
        const Token *callToken,
        std::list<const Token *> & pureFuncStack);

    static bool canNotCopy(const Scope *scope);

    static bool canNotMove(const Scope *scope);

    /**
     * @brief Helper for checkThisUseAfterFree
     */
    bool checkThisUseAfterFreeRecursive(const Scope *classScope, const Function *func, const Variable *selfPointer, std::set<const Function *> callstack, const Token *&freeToken);
};
/// @}
//---------------------------------------------------------------------------
#endif // checkclassH