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