/* 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 Copyright (C) 2015-2016 Sergio Martins 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 #include #include #include #include #include #include #include #include // 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 f;", returns the template specialization QList 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 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 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 &anyOf); CLAZYLIB_EXPORT bool insideCTORCall(clang::ParentMap *map, clang::Stmt *s, const std::vector &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 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 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 list = getList(); // true * QList list = list2; // true * QList list = {1, 2, 3}; // false * QList 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 #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 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 &); /** * 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