File indexing completed on 2024-04-28 16:57:50
0001 /* 0002 This file is part of the clazy static checker. 0003 0004 Copyright (C) 2016 Sergio Martins <smartins@kde.org> 0005 0006 This library is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU Library General Public 0008 License as published by the Free Software Foundation; either 0009 version 2 of the License, or (at your option) any later version. 0010 0011 This library is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 Library General Public License for more details. 0015 0016 You should have received a copy of the GNU Library General Public License 0017 along with this library; see the file COPYING.LIB. If not, write to 0018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 Boston, MA 02110-1301, USA. 0020 */ 0021 0022 #ifndef CLAZY_CONTEXT_UTILS_H 0023 #define CLAZY_CONTEXT_UTILS_H 0024 0025 #include "TypeUtils.h" 0026 0027 #include <clang/AST/DeclBase.h> 0028 #include <clang/AST/Decl.h> 0029 #include <clang/AST/DeclCXX.h> 0030 #include <clang/AST/Stmt.h> 0031 #include <clang/AST/Type.h> 0032 #include <llvm/Support/Casting.h> 0033 0034 #include <vector> 0035 #include <string> 0036 0037 namespace clang { 0038 class ValueDecl; 0039 class DeclContext; 0040 class SourceManager; 0041 class SourceLocation; 0042 class CXXMethodDecl; 0043 class ParentMap; 0044 } 0045 0046 namespace clazy 0047 { 0048 0049 /** 0050 * Returns true if a decl is inside a function, instead of say a class field. 0051 * This returns true if "QList<int> l;" is a local variable, instead of being a class field such 0052 * as struct Foo { QList<int> l; } 0053 */ 0054 inline bool isValueDeclInFunctionContext(const clang::ValueDecl *valueDecl) 0055 { 0056 auto context = valueDecl ? valueDecl->getDeclContext() : nullptr; 0057 return context && llvm::isa<clang::FunctionDecl>(context) && !llvm::isa<clang::ParmVarDecl>(valueDecl); 0058 } 0059 0060 /** 0061 * Returns the list of scopes for a decl context (namespaces, classes, inner classes, etc) 0062 * The inner ones are at the beginning of the list 0063 */ 0064 std::vector<clang::DeclContext *> contextsForDecl(clang::DeclContext *); 0065 0066 /** 0067 * Returns the first context for a decl. 0068 */ 0069 inline clang::DeclContext * contextForDecl(clang::Decl *decl) 0070 { 0071 if (!decl) 0072 return nullptr; 0073 0074 if (auto context = llvm::dyn_cast<clang::DeclContext>(decl)) 0075 return context; 0076 0077 return decl->getDeclContext(); 0078 } 0079 0080 inline clang::NamespaceDecl *namespaceForDecl(clang::Decl *decl) 0081 { 0082 if (!decl) 0083 return nullptr; 0084 0085 clang::DeclContext *declContext = decl->getDeclContext(); 0086 while (declContext) { 0087 if (auto ns = llvm::dyn_cast<clang::NamespaceDecl>(declContext)) 0088 return ns; 0089 0090 declContext = declContext->getParent(); 0091 } 0092 0093 return nullptr; 0094 } 0095 0096 inline clang::NamespaceDecl *namespaceForType(clang::QualType q) 0097 { 0098 if (q.isNull()) 0099 return nullptr; 0100 0101 q = clazy::pointeeQualType(q); 0102 // Check if it's a class, struct, union or enum 0103 clang::TagDecl *rec = q->getAsTagDecl(); 0104 if (rec) 0105 return namespaceForDecl(rec); 0106 0107 // Or maybe it's a typedef to a builtin type: 0108 auto typeDefType = q->getAs<clang::TypedefType>(); 0109 if (typeDefType) { 0110 clang::TypedefNameDecl* typedeff = typeDefType->getDecl(); 0111 return namespaceForDecl(typedeff); 0112 } 0113 0114 return nullptr; 0115 } 0116 0117 inline clang::NamespaceDecl *namespaceForFunction(clang::FunctionDecl *func) 0118 { 0119 if (auto ns = llvm::dyn_cast<clang::NamespaceDecl>(func->getDeclContext())) 0120 return ns; 0121 0122 return namespaceForDecl(func); 0123 } 0124 0125 /** 0126 * Returns the first context of type T in which the specified context is in. 0127 * Contexts are namespaces, classes, inner classes, functions, etc. 0128 0129 */ 0130 template <typename T> 0131 T* firstContextOfType(clang::DeclContext *context) 0132 { 0133 if (!context) 0134 return nullptr; 0135 0136 if (llvm::isa<T>(context)) 0137 return llvm::cast<T>(context); 0138 0139 return clazy::firstContextOfType<T>(context->getParent()); 0140 } 0141 0142 0143 /** 0144 * Returns fully/semi-fully qualified name for a method, but doesn't over-qualify with namespaces 0145 * which we're already in. 0146 * 0147 * if currentScope == nullptr will return a fully qualified name 0148 */ 0149 0150 std::string getMostNeededQualifiedName(const clang::SourceManager &sourceManager, 0151 clang::CXXMethodDecl *method, 0152 clang::DeclContext *currentScope, 0153 clang::SourceLocation usageLoc, 0154 bool honourUsingDirectives); 0155 0156 /** 0157 * Returns true, if in a specific context, we can take the address of a method 0158 * for example doing &ClassName::SomePrivateMember might not be possible if the member is private 0159 * but might be possible if we're in a context which is friend of ClassName 0160 * Or it might be protected but context is a derived class 0161 * 0162 * When inside a derived class scope it's possible to take the address of a protected base method 0163 * but only if you qualify it with the derived class name, so &Derived::baseMethod, instead of &Base::baseMethod 0164 * If this was the case then isSpecialProtectedCase will be true 0165 */ 0166 bool canTakeAddressOf(clang::CXXMethodDecl *method, 0167 clang::DeclContext *context, 0168 bool &isSpecialProtectedCase); 0169 0170 } 0171 0172 #endif