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