File indexing completed on 2024-05-12 05:40:55
0001 /* 0002 SPDX-FileCopyrightText: 2017 Klarälvdalens Datakonsult AB a KDAB Group company info@kdab.com 0003 SPDX-FileContributor: Sérgio Martins <sergio.martins@kdab.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "connect-not-normalized.h" 0009 #include "ClazyContext.h" 0010 #include "HierarchyUtils.h" 0011 #include "NormalizedSignatureUtils.h" 0012 #include "StringUtils.h" 0013 0014 #include <clang/AST/Decl.h> 0015 #include <clang/AST/DeclCXX.h> 0016 #include <clang/AST/Expr.h> 0017 #include <clang/AST/ExprCXX.h> 0018 #include <clang/AST/ParentMap.h> 0019 #include <clang/AST/Stmt.h> 0020 #include <clang/Basic/LLVM.h> 0021 #include <llvm/ADT/StringRef.h> 0022 #include <llvm/Support/Casting.h> 0023 0024 using namespace clang; 0025 0026 ConnectNotNormalized::ConnectNotNormalized(const std::string &name, ClazyContext *context) 0027 : CheckBase(name, context, Option_CanIgnoreIncludes) 0028 { 0029 } 0030 0031 void ConnectNotNormalized::VisitStmt(clang::Stmt *stmt) 0032 { 0033 handleQ_ARG(stmt) || handleConnect(dyn_cast<CallExpr>(stmt)); 0034 } 0035 0036 bool ConnectNotNormalized::handleQ_ARG(clang::Stmt *stmt) 0037 { 0038 if (auto *casted = dyn_cast<CallExpr>(stmt); casted && casted->getNumArgs() == 2) { 0039 if (auto *func = casted->getDirectCallee()) { 0040 const std::string retTypeName = func->getReturnType().getAsString(lo()); 0041 if (retTypeName == "QMetaMethodArgument" || retTypeName == "QMetaMethodReturnArgument") { 0042 auto *literal = clazy::getFirstChildOfType2<StringLiteral>(casted->getArg(0)); 0043 return literal ? checkNormalizedLiteral(literal, casted) : false; 0044 } 0045 } 0046 } 0047 auto *expr = dyn_cast<CXXConstructExpr>(stmt); 0048 if (!expr || expr->getNumArgs() != 2) { 0049 return false; 0050 } 0051 0052 CXXConstructorDecl *ctor = expr->getConstructor(); 0053 if (!ctor) { 0054 return false; 0055 } 0056 0057 auto name = ctor->getNameAsString(); 0058 if (name != "QArgument" && name != "QReturnArgument") { 0059 return false; 0060 } 0061 0062 auto *sl = clazy::getFirstChildOfType2<clang::StringLiteral>(expr->getArg(0)); 0063 return sl && checkNormalizedLiteral(sl, expr); 0064 } 0065 bool ConnectNotNormalized::checkNormalizedLiteral(clang::StringLiteral *sl, clang::Expr *expr) 0066 { 0067 const std::string original = sl->getString().str(); 0068 const std::string normalized = clazy::normalizedType(original.c_str()); 0069 0070 if (original == normalized) { 0071 return false; 0072 } 0073 0074 emitWarning(expr, "Signature is not normalized. Use " + normalized + " instead of " + original); 0075 return true; 0076 } 0077 0078 bool ConnectNotNormalized::handleConnect(CallExpr *callExpr) 0079 { 0080 if (!callExpr) { 0081 return false; 0082 } 0083 0084 FunctionDecl *func = callExpr->getDirectCallee(); 0085 if (!func || func->getNumParams() != 1 || clazy::name(func) != "qFlagLocation") { 0086 return false; 0087 } 0088 0089 { 0090 // Only warn in connect statements, not disconnect, since there there's no optimization in Qt's side 0091 auto *parentCallExpr = clazy::getFirstParentOfType<CallExpr>(m_context->parentMap, m_context->parentMap->getParent(callExpr), -1); 0092 if (!parentCallExpr) { 0093 return false; 0094 } 0095 0096 FunctionDecl *parentFunc = parentCallExpr->getDirectCallee(); 0097 if (!parentFunc || clazy::name(parentFunc) != "connect") { 0098 return false; 0099 } 0100 } 0101 0102 Expr *arg1 = callExpr->getArg(0); 0103 auto *sl = clazy::getFirstChildOfType2<clang::StringLiteral>(arg1); 0104 if (!sl) { 0105 return false; 0106 } 0107 std::string original = sl->getString().str(); 0108 std::string normalized = clazy::normalizedSignature(original.c_str()); 0109 0110 // discard the junk after '\0' 0111 normalized = std::string(normalized.c_str()); 0112 original = std::string(original.c_str()); 0113 0114 if (original == normalized) { 0115 return false; 0116 } 0117 0118 // Remove first digit 0119 normalized.erase(0, 1); 0120 original.erase(0, 1); 0121 0122 emitWarning(callExpr->getBeginLoc(), "Signature is not normalized. Use " + normalized + " instead of " + original); 0123 return true; 0124 }