File indexing completed on 2024-04-14 05:32:08

0001 /*
0002     SPDX-FileCopyrightText: 2015 Klarälvdalens Datakonsult AB a KDAB Group company info@kdab.com
0003     SPDX-FileContributor: SĂ©rgio Martins <sergio.martins@kdab.com>
0004 
0005     SPDX-FileCopyrightText: 2015 Sergio Martins <smartins@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #ifndef CLANG_LAZY_STRING_UTILS_H
0011 #define CLANG_LAZY_STRING_UTILS_H
0012 
0013 #include "Utils.h"
0014 #include "clazy_stl.h"
0015 
0016 #include <clang/AST/Decl.h>
0017 #include <clang/AST/DeclCXX.h>
0018 #include <clang/AST/DeclarationName.h>
0019 #include <clang/AST/Expr.h>
0020 #include <clang/AST/ExprCXX.h>
0021 #include <clang/AST/PrettyPrinter.h>
0022 #include <clang/AST/Stmt.h>
0023 #include <clang/AST/Type.h>
0024 #include <clang/Basic/LLVM.h>
0025 #include <clang/Basic/LangOptions.h>
0026 #include <clang/Basic/OperatorKinds.h>
0027 #include <clang/Basic/SourceLocation.h>
0028 #include <clang/Basic/Specifiers.h>
0029 #include <llvm/ADT/ArrayRef.h>
0030 #include <llvm/ADT/StringRef.h>
0031 #include <llvm/Support/Casting.h>
0032 #include <llvm/Support/raw_ostream.h>
0033 
0034 #include <string>
0035 #include <vector>
0036 
0037 namespace clang
0038 {
0039 class LangOpts;
0040 class SourceManager;
0041 }
0042 
0043 namespace clazy
0044 {
0045 // Returns the class name.
0046 // The name will not include any templates, so  "QVector::iterator" would be returned for QVector<int>::iterator
0047 // Use record->getQualifiedNameAsString() if you want the templates.
0048 
0049 inline std::string classNameFor(const clang::CXXRecordDecl *record)
0050 {
0051     if (!record) {
0052         return {};
0053     }
0054 
0055     const std::string name = record->getNameAsString();
0056 
0057     if (const auto *p = record->getParent()) {
0058         // TODO: Also append the namespace, when needed.
0059         auto parentName = classNameFor(llvm::dyn_cast<clang::CXXRecordDecl>(p));
0060         if (!parentName.empty()) {
0061             return parentName + "::" + name;
0062         }
0063     }
0064 
0065     return name;
0066 }
0067 
0068 inline std::string classNameFor(clang::CXXConstructorDecl *ctorDecl)
0069 {
0070     return classNameFor(ctorDecl->getParent());
0071 }
0072 
0073 inline std::string classNameFor(clang::CXXMethodDecl *method)
0074 {
0075     return method ? classNameFor(method->getParent()) : std::string();
0076 }
0077 
0078 inline std::string classNameFor(clang::CXXConstructExpr *expr)
0079 {
0080     return classNameFor(expr->getConstructor());
0081 }
0082 
0083 inline std::string classNameFor(clang::CXXOperatorCallExpr *call)
0084 {
0085     return call ? classNameFor(llvm::dyn_cast_or_null<clang::CXXMethodDecl>(call->getDirectCallee())) : std::string();
0086 }
0087 
0088 inline std::string classNameFor(clang::QualType qt)
0089 {
0090     qt = qt.getNonReferenceType().getUnqualifiedType();
0091     const clang::Type *t = qt.getTypePtrOrNull();
0092     if (!t) {
0093         return {};
0094     }
0095 
0096     if (clang::ElaboratedType::classof(t)) {
0097         return classNameFor(static_cast<const clang::ElaboratedType *>(t)->getNamedType());
0098     }
0099 
0100     const clang::CXXRecordDecl *record = t->isRecordType() ? t->getAsCXXRecordDecl() : t->getPointeeCXXRecordDecl();
0101     return classNameFor(record);
0102 }
0103 
0104 inline std::string classNameFor(clang::ParmVarDecl *param)
0105 {
0106     if (!param) {
0107         return {};
0108     }
0109 
0110     return classNameFor(param->getType());
0111 }
0112 
0113 inline llvm::StringRef name(const clang::NamedDecl *decl)
0114 {
0115     if (decl->getDeclName().isIdentifier()) {
0116         return decl->getName();
0117     }
0118 
0119     return "";
0120 }
0121 
0122 inline llvm::StringRef name(const clang::CXXMethodDecl *method)
0123 {
0124     auto op = method->getOverloadedOperator();
0125     if (op == clang::OO_Subscript) {
0126         return "operator[]";
0127     }
0128     if (op == clang::OO_LessLess) {
0129         return "operator<<";
0130     }
0131     if (op == clang::OO_PlusEqual) {
0132         return "operator+=";
0133     }
0134 
0135     return name(static_cast<const clang::NamedDecl *>(method));
0136 }
0137 
0138 inline llvm::StringRef name(const clang::CXXConstructorDecl *decl)
0139 {
0140     return name(decl->getParent());
0141 }
0142 
0143 inline llvm::StringRef name(const clang::CXXDestructorDecl *decl)
0144 {
0145     return name(decl->getParent());
0146 }
0147 
0148 // Returns the type name with or without namespace, depending on how it was written by the user.
0149 // If the user omitted the namespace then the return won't have namespace
0150 inline std::string name(clang::QualType t, const clang::LangOptions &lo, bool asWritten)
0151 {
0152     clang::PrintingPolicy p(lo);
0153     p.SuppressScope = asWritten;
0154     return t.getAsString(p);
0155 }
0156 
0157 template<typename T>
0158 inline bool isOfClass(T *node, llvm::StringRef className)
0159 {
0160     return node && classNameFor(node) == className;
0161 }
0162 
0163 inline bool functionIsOneOf(clang::FunctionDecl *func, const std::vector<llvm::StringRef> &functionNames)
0164 {
0165     return func && clazy::contains(functionNames, clazy::name(func));
0166 }
0167 
0168 inline bool classIsOneOf(clang::CXXRecordDecl *record, const std::vector<llvm::StringRef> &classNames)
0169 {
0170     return record && clazy::contains(classNames, clazy::name(record));
0171 }
0172 
0173 inline void printLocation(const clang::SourceManager &sm, clang::SourceLocation loc, bool newLine = true)
0174 {
0175     llvm::errs() << loc.printToString(sm);
0176     if (newLine) {
0177         llvm::errs() << "\n";
0178     }
0179 }
0180 
0181 inline void printRange(const clang::SourceManager &sm, clang::SourceRange range, bool newLine = true)
0182 {
0183     printLocation(sm, range.getBegin(), false);
0184     llvm::errs() << '-';
0185     printLocation(sm, range.getEnd(), newLine);
0186 }
0187 
0188 inline void printLocation(const clang::SourceManager &sm, const clang::Stmt *s, bool newLine = true)
0189 {
0190     if (s) {
0191         printLocation(sm, s->getBeginLoc(), newLine);
0192     }
0193 }
0194 
0195 inline void printLocation(const clang::PresumedLoc &loc, bool newLine = true)
0196 {
0197     llvm::errs() << loc.getFilename() << ' ' << loc.getLine() << ':' << loc.getColumn();
0198     if (newLine) {
0199         llvm::errs() << "\n";
0200     }
0201 }
0202 
0203 inline std::string qualifiedMethodName(clang::FunctionDecl *func)
0204 {
0205     if (!func) {
0206         return {};
0207     }
0208 
0209     auto *method = clang::dyn_cast<clang::CXXMethodDecl>(func);
0210     if (!method) {
0211         return func->getQualifiedNameAsString();
0212     }
0213 
0214     // method->getQualifiedNameAsString() returns the name with template arguments, so do a little hack here
0215     if (!method || !method->getParent()) {
0216         return "";
0217     }
0218 
0219     return method->getParent()->getNameAsString() + "::" + method->getNameAsString();
0220 }
0221 
0222 inline std::string qualifiedMethodName(clang::CallExpr *call)
0223 {
0224     return call ? qualifiedMethodName(call->getDirectCallee()) : std::string();
0225 }
0226 
0227 inline std::string accessString(clang::AccessSpecifier s)
0228 {
0229     switch (s) {
0230     case clang::AccessSpecifier::AS_public:
0231         return "public";
0232     case clang::AccessSpecifier::AS_private:
0233         return "private";
0234     case clang::AccessSpecifier::AS_protected:
0235         return "protected";
0236     case clang::AccessSpecifier::AS_none:
0237         return {};
0238     }
0239     return {};
0240 }
0241 
0242 /**
0243  * Returns the type of qt without CV qualifiers or references.
0244  * "const QString &" -> "QString"
0245  */
0246 inline std::string simpleTypeName(clang::QualType qt, const clang::LangOptions &lo)
0247 {
0248     const auto *t = qt.getTypePtrOrNull();
0249     if (!t) {
0250         return {};
0251     }
0252 
0253     if (clang::ElaboratedType::classof(t)) {
0254         qt = static_cast<const clang::ElaboratedType *>(t)->getNamedType();
0255     }
0256 
0257     return qt.getNonReferenceType().getUnqualifiedType().getAsString(clang::PrintingPolicy(lo));
0258 }
0259 
0260 inline std::string simpleTypeName(clang::ParmVarDecl *p, const clang::LangOptions &lo)
0261 {
0262     return p ? simpleTypeName(p->getType(), lo) : std::string();
0263 }
0264 
0265 inline std::string typeName(clang::QualType qt, const clang::LangOptions &lo, bool simpleName)
0266 {
0267     return simpleName ? simpleTypeName(qt, lo) : qt.getAsString(lo);
0268 }
0269 
0270 /**
0271  * Returns the type name of the return type.
0272  * If \a simpleName is true, any cv qualifications, ref or pointer are not taken into account, so
0273  * const Foo & would be equal to Foo.
0274  */
0275 inline std::string returnTypeName(clang::CallExpr *call, const clang::LangOptions &lo, bool simpleName = true)
0276 {
0277     if (!call) {
0278         return {};
0279     }
0280 
0281     clang::FunctionDecl *func = call->getDirectCallee();
0282     return func ? clazy::typeName(func->getReturnType(), lo, simpleName) : std::string();
0283 }
0284 
0285 inline bool hasArgumentOfType(clang::FunctionDecl *func, llvm::StringRef typeName, const clang::LangOptions &lo, bool simpleName = true)
0286 {
0287     return clazy::any_of(Utils::functionParameters(func), [simpleName, lo, typeName](clang::ParmVarDecl *param) {
0288         return clazy::typeName(param->getType(), lo, simpleName) == typeName;
0289     });
0290 }
0291 
0292 /**
0293  * Returns the type of an argument at index index without CV qualifiers or references.
0294  * void foo(int a, const QString &);
0295  * simpleArgTypeName(foo, 1, lo) would return "QString"
0296  */
0297 std::string simpleArgTypeName(clang::FunctionDecl *func, unsigned int index, const clang::LangOptions &);
0298 
0299 /**
0300  * Returns true if any of the function's arguments if of type simpleType
0301  * By "simple" we mean without const or &, *
0302  */
0303 bool anyArgIsOfSimpleType(clang::FunctionDecl *func, const std::string &simpleType, const clang::LangOptions &);
0304 
0305 /**
0306  * Returns true if any of the function's arguments if of any of the types in simpleTypes
0307  * By "simple" we mean without const or &, *
0308  */
0309 bool anyArgIsOfAnySimpleType(clang::FunctionDecl *func, const std::vector<std::string> &simpleTypes, const clang::LangOptions &);
0310 
0311 inline void dump(const clang::SourceManager &sm, clang::Stmt *s)
0312 {
0313     if (!s) {
0314         return;
0315     }
0316 
0317     llvm::errs() << "Start=" << s->getBeginLoc().printToString(sm) << "; end=" << s->getBeginLoc().printToString(sm) << "\n";
0318 
0319     for (auto *child : s->children()) {
0320         dump(sm, child);
0321     }
0322 }
0323 
0324 }
0325 
0326 #endif