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