File indexing completed on 2024-05-12 05:40:59
0001 /* 0002 SPDX-FileCopyrightText: 2016 Sergio Martins <smartins@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "ctor-missing-parent-argument.h" 0008 #include "QtUtils.h" 0009 #include "StringUtils.h" 0010 #include "TypeUtils.h" 0011 0012 #include <clang/AST/DeclBase.h> 0013 #include <clang/AST/DeclCXX.h> 0014 #include <clang/Basic/LLVM.h> 0015 #include <clang/Basic/SourceManager.h> 0016 #include <llvm/ADT/StringRef.h> 0017 #include <llvm/Support/Casting.h> 0018 0019 class ClazyContext; 0020 0021 using namespace clang; 0022 0023 CtorMissingParentArgument::CtorMissingParentArgument(const std::string &name, ClazyContext *context) 0024 : CheckBase(name, context) 0025 { 0026 } 0027 0028 static std::string expectedParentTypeFor(CXXRecordDecl *decl) 0029 { 0030 if (clazy::derivesFrom(decl, "QWidget")) { 0031 return "QWidget"; 0032 } 0033 if (clazy::derivesFrom(decl, "QQuickItem")) { 0034 return "QQuickItem"; 0035 } else if (clazy::derivesFrom(decl, "Qt3DCore::QEntity")) { 0036 return "Qt3DCore::QNode"; 0037 } 0038 0039 return "QObject"; 0040 } 0041 0042 void CtorMissingParentArgument::VisitDecl(Decl *decl) 0043 { 0044 auto *record = dyn_cast<CXXRecordDecl>(decl); 0045 bool ok = false; 0046 0047 if (!clazy::isQObject(record)) { 0048 return; 0049 } 0050 0051 if (record->hasInheritedConstructor()) { 0052 // When doing using QObject::QObject you inherit the ctors from QObject, so don't warn. 0053 // Would be nicer to check if the using directives really refer to QObject::QObject and not to 0054 // Some other non-object class, but I can't find a way to get to ConstructorUsingShadowDecl from the CxxRecordDecl 0055 // so we might miss some true-positives 0056 return; 0057 } 0058 0059 const bool hasCtors = record->ctor_begin() != record->ctor_end(); 0060 if (!hasCtors) { 0061 return; 0062 } 0063 0064 const std::string parentType = expectedParentTypeFor(record); 0065 int numCtors = 0; 0066 const bool hasQObjectParam = clazy::recordHasCtorWithParam(record, parentType, /*by-ref*/ ok, /*by-ref*/ numCtors); 0067 if (!ok) { 0068 return; 0069 } 0070 0071 if (numCtors > 0 && !hasQObjectParam) { 0072 clang::CXXRecordDecl *baseClass = clazy::getQObjectBaseClass(record); 0073 const bool baseHasQObjectParam = clazy::recordHasCtorWithParam(baseClass, parentType, /*by-ref*/ ok, /*by-ref*/ numCtors); 0074 if (ok && !baseHasQObjectParam && sm().isInSystemHeader(baseClass->getBeginLoc())) { 0075 // If the base class ctors don't accept QObject, and it's declared in a system header don't warn 0076 return; 0077 } 0078 0079 if (clazy::name(baseClass) == "QCoreApplication") { 0080 return; 0081 } 0082 0083 emitWarning(decl, record->getQualifiedNameAsString() + std::string(" should take ") + parentType + std::string(" parent argument in CTOR")); 0084 } 0085 }