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