File indexing completed on 2024-04-21 05:38:49

0001 /*
0002     SPDX-FileCopyrightText: 2015 Klarälvdalens Datakonsult AB a KDAB Group company info@kdab.com
0003     SPDX-FileCopyrightText: 2015-2016 Sergio Martins <smartins@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #ifndef MOREWARNINGS_UTILS_H
0009 #define MOREWARNINGS_UTILS_H
0010 
0011 #include <clang/AST/DeclCXX.h>
0012 #include <clang/AST/DeclTemplate.h>
0013 #include <clang/AST/Expr.h>
0014 #include <clang/AST/ExprCXX.h>
0015 #include <clang/AST/Stmt.h>
0016 #include <clang/Basic/SourceLocation.h>
0017 #include <clang/Basic/SourceManager.h>
0018 #include <llvm/ADT/ArrayRef.h>
0019 #include <llvm/ADT/StringRef.h>
0020 #include <llvm/Config/llvm-config.h>
0021 
0022 #include <string>
0023 #include <vector>
0024 
0025 // TODO: this is a dumping ground, most of these functions should be moved to the other *Utils classes
0026 
0027 namespace clang
0028 {
0029 class CXXNamedCastExpr;
0030 class CXXRecordDecl;
0031 class CXXMemberCallExpr;
0032 class CXXConstructExpr;
0033 class CompilerInstance;
0034 class ClassTemplateSpecializationDecl;
0035 class Decl;
0036 class ParentMap;
0037 class SourceManager;
0038 class Stmt;
0039 class SourceLocation;
0040 class ExprWithCleanups;
0041 class ValueDecl;
0042 class ConditionalOperator;
0043 class CXXMethodDecl;
0044 class BinaryOperator;
0045 class CXXOperatorCallExpr;
0046 class CallExpr;
0047 class DeclStmt;
0048 class Expr;
0049 class FunctionDecl;
0050 class LangOptions;
0051 class ParmVarDecl;
0052 class StringLiteral;
0053 class UserDefinedLiteral;
0054 class VarDecl;
0055 }
0056 
0057 struct StmtBodyRange;
0058 
0059 namespace Utils
0060 {
0061 /// Returns true if the class has at least one constexpr ctor
0062 bool hasConstexprCtor(clang::CXXRecordDecl *decl);
0063 
0064 /// Returns the type we're casting *from*
0065 clang::CXXRecordDecl *namedCastInnerDecl(clang::CXXNamedCastExpr *staticOrDynamicCast);
0066 
0067 /// Returns the type we're casting *to*
0068 clang::CXXRecordDecl *namedCastOuterDecl(clang::CXXNamedCastExpr *staticOrDynamicCast);
0069 
0070 /// Returns the class declaration from a variable declaration
0071 // So, if the var decl is "Foo f"; it returns the declaration of Foo
0072 clang::CXXRecordDecl *recordFromVarDecl(clang::Decl *);
0073 
0074 /// Returns the template specialization from a variable declaration
0075 // So, if the var decl is "QList<Foo> f;", returns the template specialization QList<Foo>
0076 clang::ClassTemplateSpecializationDecl *templateSpecializationFromVarDecl(clang::Decl *);
0077 
0078 /// Returns true if all the child member function calls are const functions.
0079 bool allChildrenMemberCallsConst(clang::Stmt *stm);
0080 
0081 /// Returns true if at least a UnaryOperator, BinaryOperator or non-const function call is found
0082 bool childsHaveSideEffects(clang::Stmt *stm);
0083 
0084 /// Receives a member call, such as "list.reserve()" and returns the declaration of the variable list
0085 // such as "QList<F> list"
0086 clang::ValueDecl *valueDeclForMemberCall(clang::CXXMemberCallExpr *);
0087 
0088 /// Receives an operator call, such as "list << fooo" and returns the declaration of the variable list
0089 // such as "QList<F> list"
0090 clang::ValueDecl *valueDeclForOperatorCall(clang::CXXOperatorCallExpr *);
0091 
0092 // overload
0093 clang::ValueDecl *valueDeclForCallExpr(clang::CallExpr *);
0094 
0095 // Returns true of this value decl is a member variable of a class or struct
0096 // returns null if not
0097 clang::CXXRecordDecl *isMemberVariable(clang::ValueDecl *);
0098 
0099 // Returns true if a body of statements contains a non const member call on object declared by varDecl
0100 // For example:
0101 // Foo foo; // this is the varDecl
0102 // while (bar) { foo.setValue(); // non-const call }
0103 bool containsNonConstMemberCall(clang::ParentMap *map, clang::Stmt *body, const clang::VarDecl *varDecl);
0104 
0105 // Returns true if there's an assignment to varDecl in body
0106 // Example: our_var = something_else
0107 bool isAssignedFrom(clang::Stmt *body, const clang::VarDecl *varDecl);
0108 
0109 // Returns true if varDecl is assigned to something
0110 // Example: something_else = our_var
0111 bool isAssignedTo(clang::Stmt *body, const clang::VarDecl *varDecl);
0112 
0113 // Returns whether the variable is returned in body
0114 bool isReturned(clang::Stmt *body, const clang::VarDecl *varDecl);
0115 
0116 // Returns true if a body of statements contains a function call that takes our variable (varDecl)
0117 // By ref or pointer
0118 bool isPassedToFunction(const StmtBodyRange &bodyRange, const clang::VarDecl *varDecl, bool byRefOrPtrOnly);
0119 
0120 // Returns true if we take the address of varDecl, such as: &foo
0121 bool addressIsTaken(const clang::CompilerInstance &ci, clang::Stmt *body, const clang::ValueDecl *valDecl);
0122 
0123 // QString::fromLatin1("foo")    -> true
0124 // QString::fromLatin1("foo", 1) -> false
0125 bool callHasDefaultArguments(clang::CallExpr *expr);
0126 
0127 // If there's a child of type StringLiteral, returns true
0128 // if allowEmpty is false, "" will be ignored
0129 bool containsStringLiteral(clang::Stmt *, bool allowEmpty = true, int depth = -1);
0130 
0131 bool isInsideOperatorCall(clang::ParentMap *map, clang::Stmt *s, const std::vector<llvm::StringRef> &anyOf);
0132 
0133 bool insideCTORCall(clang::ParentMap *map, clang::Stmt *s, const std::vector<llvm::StringRef> &anyOf);
0134 
0135 // returns true if the ternary operator has two string literal arguments, such as:
0136 // foo ? "bar" : "baz"
0137 bool ternaryOperatorIsOfStringLiteral(clang::ConditionalOperator *);
0138 
0139 bool isAssignOperator(clang::CXXOperatorCallExpr *op, llvm::StringRef className, llvm::StringRef argumentType, const clang::LangOptions &lo);
0140 
0141 bool isImplicitCastTo(clang::Stmt *, const std::string &);
0142 
0143 bool presumedLocationsEqual(const clang::PresumedLoc &l1, const clang::PresumedLoc &l2);
0144 
0145 // Returns the list of methods with name methodName that the class/struct record contains
0146 std::vector<clang::CXXMethodDecl *> methodsFromString(const clang::CXXRecordDecl *record, const std::string &methodName);
0147 
0148 // Returns the most derived class. (CXXMemberCallExpr::getRecordDecl() return the first base class with the method)
0149 // The returned callee is the name of the variable on which the member call was made:
0150 // o1->foo() => "o1"
0151 // foo() => "this"
0152 const clang::CXXRecordDecl *recordForMemberCall(clang::CXXMemberCallExpr *call, std::string &implicitCallee);
0153 
0154 bool isAscii(clang::StringLiteral *lt);
0155 
0156 // Checks if Statement s inside an operator* call
0157 bool isInDerefExpression(clang::Stmt *s, clang::ParentMap *map);
0158 
0159 // For a a chain called expression like foo().bar().baz() returns a list of calls
0160 // {baz(), bar(), foo()}
0161 
0162 // the parameter lastCallExpr to pass would be baz()
0163 // No need to specify the other callexprs, they are children of the first one, since the AST looks like:
0164 // - baz
0165 // -- bar
0166 // --- foo
0167 std::vector<clang::CallExpr *> callListForChain(clang::CallExpr *lastCallExpr);
0168 
0169 // Returns the first base class
0170 clang::CXXRecordDecl *rootBaseClass(clang::CXXRecordDecl *derived);
0171 
0172 // Returns the copy ctor for this class
0173 clang::CXXConstructorDecl *copyCtor(const clang::CXXRecordDecl *);
0174 
0175 // Returns the copy-assignment operator for this class
0176 clang::CXXMethodDecl *copyAssign(const clang::CXXRecordDecl *);
0177 
0178 bool hasMember(clang::CXXRecordDecl *record, const std::string &memberTypeName);
0179 
0180 /**
0181  * Returns true if record is a shared pointer (boost, Qt or stl only).
0182  */
0183 bool isSharedPointer(clang::CXXRecordDecl *record);
0184 
0185 /**
0186  * Returns true if varDecl is initialized externally.
0187  * Example:
0188  *     QList<Foo> list = getList(); // true
0189  *     QList<int> list = list2;     // true
0190  *     QList<int> list = {1, 2, 3}; // false
0191  *     QList<int> list;             // false
0192  */
0193 bool isInitializedExternally(clang::VarDecl *varDecl);
0194 
0195 /**
0196  * Returns true if declStmt refers to varDecl
0197  */
0198 bool referencesVarDecl(clang::DeclStmt *declStmt, clang::VarDecl *varDecl);
0199 
0200 /**
0201  * Returns true if the body of a function is empty.
0202  * Returns false if either function or it's body are null.
0203  */
0204 bool functionHasEmptyBody(clang::FunctionDecl *func);
0205 
0206 /**
0207  * If stm is an UnaryOperator or BinaryOperator that writes to the variable it returns the expression
0208  * that represents the variable (Usually a MemberExpr or DeclRefExpr for local variables).
0209  *
0210  * Otherwise returns nullptr.
0211  *
0212  * The operators that write to the variable are operator=, operator+=, operator++, etc.
0213  */
0214 clang::Expr *isWriteOperator(clang::Stmt *stm);
0215 
0216 /**
0217  * Gets the UserDefinedLiteral of type @p type which is somewhere in the ast of @p stm.
0218  * Returns nullptr if there's no such UserDefinedLiteral.
0219  */
0220 clang::UserDefinedLiteral *userDefinedLiteral(clang::Stmt *stm, const std::string &type, const clang::LangOptions &lo);
0221 
0222 /**
0223  * Returns the function parameters fom @p func
0224  * This should be used instead of calling FunctionDecl::params() since it changed signature in
0225  * clang 3.9.
0226  */
0227 clang::ArrayRef<clang::ParmVarDecl *> functionParameters(clang::FunctionDecl *func);
0228 
0229 /**
0230  * For the given ctor, and ctor param, returns the ctor member initializers that used that param.
0231  * Example:
0232  * MyCtor(int a, int b) : c(a), d(b) {}
0233  * auto result = Utils::ctorInitializer(MyCtor, b); // Result is the statement "d(b)"
0234  */
0235 std::vector<clang::CXXCtorInitializer *> ctorInitializer(clang::CXXConstructorDecl *ctor, clang::ParmVarDecl *param);
0236 
0237 /**
0238  * Returns true if a ctor initializer contains a std::move()
0239  * Example
0240  * MyCtor(Foo a) : c(move(a)) {} // Would return true for this init list
0241  */
0242 bool ctorInitializerContainsMove(clang::CXXCtorInitializer *);
0243 
0244 // Overload that recieves a vector and returns true if any ctor initializer contains a move()
0245 bool ctorInitializerContainsMove(const std::vector<clang::CXXCtorInitializer *> &);
0246 
0247 /**
0248  * Returns the filename for the source location loc
0249  */
0250 std::string filenameForLoc(clang::SourceLocation loc, const clang::SourceManager &sm);
0251 
0252 /**
0253  * Returns the location after the lexer token that is at loc.
0254  * For example:
0255  *     emit sig();
0256  * If loc refers to the location of 'emit', then this function will return the source location if
0257  * the sig() call.
0258  */
0259 clang::SourceLocation locForNextToken(clang::SourceLocation loc, const clang::SourceManager &sm, const clang::LangOptions &lo);
0260 
0261 inline bool isMainFile(const clang::SourceManager &sm, clang::SourceLocation loc)
0262 {
0263     if (loc.isMacroID()) {
0264         loc = sm.getExpansionLoc(loc);
0265     }
0266 
0267     return sm.isInFileID(loc, sm.getMainFileID());
0268 }
0269 
0270 /**
0271  * Returns true if the string literal contains escaped bytes, such as \x12, \123, \u00F6.
0272  */
0273 bool literalContainsEscapedBytes(clang::StringLiteral *lt, const clang::SourceManager &sm, const clang::LangOptions &lo);
0274 
0275 /**
0276  * Returns true if this method overrides one from the base class
0277  */
0278 inline bool methodOverrides(clang::CXXMethodDecl *method)
0279 {
0280     return method && method->isVirtual() && method->size_overridden_methods() > 0;
0281 }
0282 }
0283 
0284 #endif