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