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