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