File indexing completed on 2024-05-12 05:41:00

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-2016 Sergio Martins <smartins@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "missing-typeinfo.h"
0011 #include "QtUtils.h"
0012 #include "StringUtils.h"
0013 #include "TemplateUtils.h"
0014 #include "TypeUtils.h"
0015 
0016 #include <clang/AST/DeclCXX.h>
0017 #include <clang/AST/DeclTemplate.h>
0018 #include <clang/AST/Type.h>
0019 #include <clang/Basic/SourceManager.h>
0020 #include <llvm/ADT/StringRef.h>
0021 
0022 class ClazyContext;
0023 namespace clang
0024 {
0025 class Decl;
0026 } // namespace clang
0027 
0028 using namespace clang;
0029 
0030 /**
0031  * Returns true if the call is on a java-style iterator class.
0032  * Returns if sizeof(T) > sizeof(void*), which would make QList<T> inefficient
0033  */
0034 inline bool checkTooBigForQList(clang::QualType qt, const clang::ASTContext *context)
0035 {
0036     return (int)context->getTypeSize(qt) <= clazy::sizeOfPointer(context, qt);
0037 }
0038 
0039 MissingTypeInfo::MissingTypeInfo(const std::string &name, ClazyContext *context)
0040     : CheckBase(name, context)
0041 {
0042 }
0043 
0044 void MissingTypeInfo::VisitDecl(clang::Decl *decl)
0045 {
0046     ClassTemplateSpecializationDecl *tstdecl = clazy::templateDecl(decl);
0047     if (!tstdecl) {
0048         return;
0049     }
0050 
0051     const bool isQList = clazy::name(tstdecl) == "QList";
0052     const bool isQVector = isQList ? false : clazy::name(tstdecl) == "QVector";
0053 
0054     if (!isQList && !isQVector) {
0055         registerQTypeInfo(tstdecl);
0056         return;
0057     }
0058 
0059     QualType qt2 = clazy::getTemplateArgumentType(tstdecl, 0);
0060     const Type *t = qt2.getTypePtrOrNull();
0061     CXXRecordDecl *record = t ? t->getAsCXXRecordDecl() : nullptr;
0062     if (!record || !record->getDefinition() || typeHasClassification(qt2)) {
0063         return; // Don't crash if we only have a fwd decl
0064     }
0065 
0066     const bool isCopyable = qt2.isTriviallyCopyableType(m_astContext);
0067     const bool isTooBigForQList = isQList && checkTooBigForQList(qt2, &m_astContext);
0068 
0069     if ((isQVector || isTooBigForQList) && isCopyable) {
0070         if (sm().isInSystemHeader(record->getBeginLoc())) {
0071             return;
0072         }
0073 
0074         std::string typeName = static_cast<std::string>(clazy::name(record));
0075         if (typeName == "QPair") { // QPair doesn't use Q_DECLARE_TYPEINFO, but rather a explicit QTypeInfo.
0076             return;
0077         }
0078 
0079         emitWarning(decl, "Missing Q_DECLARE_TYPEINFO: " + typeName);
0080         emitWarning(record, "Type declared here:", false);
0081     }
0082 }
0083 
0084 void MissingTypeInfo::registerQTypeInfo(ClassTemplateSpecializationDecl *decl)
0085 {
0086     if (clazy::name(decl) == "QTypeInfo") {
0087         const std::string typeName = clazy::getTemplateArgumentTypeStr(decl, 0, lo(), /**recordOnly=*/true);
0088         if (!typeName.empty()) {
0089             m_typeInfos.insert(typeName);
0090         }
0091     }
0092 }
0093 
0094 bool MissingTypeInfo::typeHasClassification(QualType qt) const
0095 {
0096     return m_typeInfos.find(clazy::simpleTypeName(qt, lo())) != m_typeInfos.end();
0097 }