diff options
author | Sergio Martins <smartins@kde.org> | 2017-02-05 18:31:18 +0000 |
---|---|---|
committer | Sergio Martins <smartins@kde.org> | 2017-02-05 18:34:37 +0000 |
commit | 2ccdae6537eb9aade05aad0538baa1f5f64c8f7b (patch) | |
tree | cffb63fa6c58593fa4c2c78effad0f0464e11725 /src/QtUtils.cpp | |
parent | 3781c06d5e04bb5ab32b80d341e19120088cbb43 (diff) |
Move all source files into a src/ folder
Top-level folder was starting to get messy
Diffstat (limited to 'src/QtUtils.cpp')
-rw-r--r-- | src/QtUtils.cpp | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/src/QtUtils.cpp b/src/QtUtils.cpp new file mode 100644 index 00000000..cdaa047a --- /dev/null +++ b/src/QtUtils.cpp @@ -0,0 +1,323 @@ +/* + This file is part of the clazy static checker. + + Copyright (C) 2015-2016 Sergio Martins <smartins@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "clazy_stl.h" +#include "QtUtils.h" +#include "Utils.h" +#include "TypeUtils.h" +#include "StmtBodyRange.h" +#include "MacroUtils.h" +#include "HierarchyUtils.h" +#include "StringUtils.h" +#include "ContextUtils.h" + +#include <clang/AST/AST.h> + +using namespace std; +using namespace clang; + +bool QtUtils::isQtIterableClass(clang::CXXRecordDecl *record) +{ + if (!record) + return false; + + return isQtIterableClass(record->getQualifiedNameAsString()); +} + +const vector<string> & QtUtils::qtContainers() +{ + static const vector<string> classes = { "QListSpecialMethods", "QList", "QVector", "QVarLengthArray", "QMap", + "QHash", "QMultiMap", "QMultiHash", "QSet", "QStack", "QQueue", "QString", "QStringRef", + "QByteArray", "QSequentialIterable", "QAssociativeIterable", "QJsonArray", "QLinkedList" }; + return classes; +} + +const vector<string> & QtUtils::qtCOWContainers() +{ + static const vector<string> classes = { "QListSpecialMethods", "QList", "QVector", "QVarLengthArray", "QMap", + "QHash", "QMultiMap", "QMultiHash", "QSet", "QStack", "QQueue", "QString", "QStringRef", + "QByteArray", "QJsonArray", "QLinkedList" }; + return classes; +} + +bool QtUtils::isQtCOWIterableClass(clang::CXXRecordDecl *record) +{ + if (!record) + return false; + + return isQtCOWIterableClass(record->getQualifiedNameAsString()); +} + +bool QtUtils::isQtCOWIterableClass(const string &className) +{ + const auto &classes = qtCOWContainers(); + return clazy_std::contains(classes, className); +} + +bool QtUtils::isQtIterableClass(const string &className) +{ + const auto &classes = qtContainers(); + return clazy_std::contains(classes, className); +} + +bool QtUtils::isQtAssociativeContainer(clang::CXXRecordDecl *record) +{ + if (!record) + return false; + + return isQtAssociativeContainer(record->getNameAsString()); +} + +bool QtUtils::isQtAssociativeContainer(const string &className) +{ + static const vector<string> classes = { "QSet", "QMap", "QHash" }; + return clazy_std::contains(classes, className); +} + +bool QtUtils::isBootstrapping(const clang::CompilerInstance &ci) +{ + return MacroUtils::isPredefined(ci, "QT_BOOTSTRAPPED"); +} + +bool QtUtils::isQObject(CXXRecordDecl *decl) +{ + return TypeUtils::derivesFrom(decl, "QObject"); +} + +bool QtUtils::isQObject(clang::QualType qt) +{ + qt = TypeUtils::pointeeQualType(qt); + const auto t = qt.getTypePtrOrNull(); + return t ? isQObject(t->getAsCXXRecordDecl()) : false; +} + +bool QtUtils::isConvertibleTo(const Type *source, const Type *target) +{ + if (!source || !target) + return false; + + if (source->isPointerType() ^ target->isPointerType()) + return false; + + if (source == target) + return true; + + if (source->getPointeeCXXRecordDecl() && source->getPointeeCXXRecordDecl() == target->getPointeeCXXRecordDecl()) + return true; + + if (source->isIntegerType() && target->isIntegerType()) + return true; + + if (source->isFloatingType() && target->isFloatingType()) + return true; + + return false; +} + +bool QtUtils::isInForeach(const clang::CompilerInstance &ci, clang::SourceLocation loc) +{ + return MacroUtils::isInAnyMacro(ci, loc, { "Q_FOREACH", "foreach" }); +} + +bool QtUtils::isJavaIterator(CXXRecordDecl *record) +{ + if (!record) + return false; + + static const vector<string> names = { "QHashIterator", "QMapIterator", "QSetIterator", "QListIterator", + "QVectorIterator", "QLinkedListIterator", "QStringListIterator" }; + + return clazy_std::contains(names, record->getNameAsString()); +} + +bool QtUtils::isJavaIterator(CXXMemberCallExpr *call) +{ + if (!call) + return false; + + return isJavaIterator(call->getRecordDecl()); +} + +clang::ValueDecl *QtUtils::signalSenderForConnect(clang::CallExpr *call) +{ + if (!call || call->getNumArgs() < 1) + return nullptr; + + Expr *firstArg = call->getArg(0); + auto declRef = isa<DeclRefExpr>(firstArg) ? cast<DeclRefExpr>(firstArg) : HierarchyUtils::getFirstChildOfType2<DeclRefExpr>(firstArg); + if (!declRef) + return nullptr; + + return declRef->getDecl(); +} + +bool QtUtils::isTooBigForQList(clang::QualType qt, const clang::CompilerInstance &ci) +{ + return (int)ci.getASTContext().getTypeSize(qt) <= TypeUtils::sizeOfPointer(ci, qt); +} + +bool QtUtils::isQtContainer(QualType t, const LangOptions &lo) +{ + const string typeName = StringUtils::simpleTypeName(t, lo); + return clazy_std::any_of(QtUtils::qtContainers(), [typeName] (const string &container) { + return container == typeName; + }); +} + +bool QtUtils::containerNeverDetaches(const clang::VarDecl *valDecl, StmtBodyRange bodyRange) // clazy:exclude=function-args-by-value +{ + if (!valDecl) + return false; + + const FunctionDecl *context = dyn_cast<FunctionDecl>(valDecl->getDeclContext()); + if (!context) + return false; + + bodyRange.body = context->getBody(); + if (!bodyRange.body) + return false; + + // TODO1: Being passed to a function as const should be OK + if (Utils::isPassedToFunction(bodyRange, valDecl, false)) + return false; + + return true; +} + +bool QtUtils::isAReserveClass(CXXRecordDecl *recordDecl) +{ + if (!recordDecl) + return false; + + static const std::vector<std::string> classes = {"QVector", "vector", "QList", "QSet"}; + + return clazy_std::any_of(classes, [recordDecl](const string &className) { + return TypeUtils::derivesFrom(recordDecl, className); + }); +} + +clang::CXXRecordDecl *QtUtils::getQObjectBaseClass(clang::CXXRecordDecl *recordDecl) +{ + if (!recordDecl) + return nullptr; + + for (auto baseClass : recordDecl->bases()) { + CXXRecordDecl *record = TypeUtils::recordFromBaseSpecifier(baseClass); + if (isQObject(record)) + return record; + } + + return nullptr; +} + + +bool QtUtils::isConnect(FunctionDecl *func) +{ + return func && func->getQualifiedNameAsString() == "QObject::connect"; +} + +bool QtUtils::connectHasPMFStyle(FunctionDecl *func) +{ + // Look for char* arguments + for (auto parm : Utils::functionParameters(func)) { + QualType qt = parm->getType(); + const Type *t = qt.getTypePtrOrNull(); + if (!t || !t->isPointerType()) + continue; + + const Type *ptt = t->getPointeeType().getTypePtrOrNull(); + if (ptt && ptt->isCharType()) + return false; + } + + return true; +} + +CXXMethodDecl *QtUtils::pmfFromConnect(CallExpr *funcCall, int argIndex) +{ + if (!funcCall) + return nullptr; + + const int numArgs = funcCall->getNumArgs(); + if (numArgs < 3) { + llvm::errs() << "error, connect call has less than 3 arguments\n"; + return nullptr; + } + + if (argIndex >= numArgs) { + llvm::errs() << "error, invalid argIndex " << argIndex << " " << numArgs; + return nullptr; + } + + Expr *expr = funcCall->getArg(argIndex); + return pmfFromUnary(expr); +} + + +CXXMethodDecl *QtUtils::pmfFromUnary(Expr *expr) +{ + if (auto uo = dyn_cast<UnaryOperator>(expr)) { + return pmfFromUnary(uo); + } else if (auto call = dyn_cast<CXXOperatorCallExpr>(expr)) { + + if (call->getNumArgs() <= 1) + return nullptr; + + FunctionDecl *func = call->getDirectCallee(); + if (!func) + return nullptr; + + auto context = func->getParent(); + if (!context) + return nullptr; + + CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(context); + if (!record) + return nullptr; + + const std::string className = record->getQualifiedNameAsString(); + if (className != "QNonConstOverload" && className != "QConstOverload") + return nullptr; + + return pmfFromUnary(dyn_cast<UnaryOperator>(call->getArg(1))); + } + + return nullptr; +} + +CXXMethodDecl *QtUtils::pmfFromUnary(UnaryOperator *uo) +{ + if (!uo) + return nullptr; + + Expr *subExpr = uo->getSubExpr(); + if (!subExpr) + return nullptr; + + auto declref = dyn_cast<DeclRefExpr>(subExpr); + + if (declref) + return dyn_cast<CXXMethodDecl>(declref->getDecl()); + + return nullptr; +} + + |