diff --git a/Changelog b/Changelog index 34ec9af..68f6d15 100644 --- a/Changelog +++ b/Changelog @@ -1,60 +1,61 @@ * v0.0.1 (June 10th, 2015) - (...) * v1.0 (September 12th, 2016) - (...) * v1.1 (February 20th, 2017) - macOS and Windows support - New checks: child-event-qobject-cast ctor-missing-parent-argument returning-data-from-temporary qt-macros base-class-event connect-non-signal incorrect-emit tr-non-literal - Fixes against clang 4.0 - Fixes against Qt 5.9 - 60% performance improvement - Fixed many false positives * v1.2 (July 8th, 2017) - clazy-standalone executable. Allows to run clazy against a JSON compilation database instead of as a plugin. clang-tidy doesn't support loading external modules (https://bugs.llvm.org/show_bug.cgi?id=32739) so this is a good workaround. - qt-compat mode. Allows to disable Qt5 specific checks by passing -Xclang -plugin-arg-clang-lazy -Xclang qt4-compat - New checks: install-event-filter qcolor-from-literal strict-iterators connect-not-normalized - returning-data-from-temporary now checks for temporary QByteArrays casting to char* when returned - returning-data-from-temporary now checks for assignment too, not only return statements - unused-non-trivial-variable now warns for unused QList, QVector and many more types - ASTMatchers based checks are now supported - clang 3.7 was dropped due to ASTMatchers source incompatibilities. Use clazy v1.1 for clang >= 3.6 support - clazylib.so no longer gets built by default, only the plugin (ClangLazy.so) gets built. Pass -DCLAZY_BUILD_UTILS_LIB=ON to enable the utils library if you're developing tools using clazy's convenience functions, which you're probably not. - CLAZY_INSTALL_NO_HEADERS option was removed. Either install the utils library and headers or nothing at all. By default nothing is installed, except the plugin and man pages. * v1.3 () - New checks: connect-3arg-lambda qproperty-without-notify virtual-signal overridden-signal + qhash-namespace - missing-qobject-macro is now a level2 check, instead of level1. Because, people can omit Q_OBJECT intentionally. - Added -only-qt option, which will make clazy bailout early on non-Qt files. For this purpose, the definition of a Qt file is whenever -DQT_CORE_LIB is passed, which is usually the case in most build systems. diff --git a/ClazySources.cmake b/ClazySources.cmake index e6222cf..b888bec 100644 --- a/ClazySources.cmake +++ b/ClazySources.cmake @@ -1,113 +1,114 @@ set(CLAZY_LIB_SRC ${CMAKE_CURRENT_LIST_DIR}/src/AccessSpecifierManager.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checkbase.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checkmanager.cpp ${CMAKE_CURRENT_LIST_DIR}/src/SuppressionManager.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ContextUtils.cpp ${CMAKE_CURRENT_LIST_DIR}/src/FixItUtils.cpp ${CMAKE_CURRENT_LIST_DIR}/src/LoopUtils.cpp ${CMAKE_CURRENT_LIST_DIR}/src/PreProcessorVisitor.cpp ${CMAKE_CURRENT_LIST_DIR}/src/QtUtils.cpp ${CMAKE_CURRENT_LIST_DIR}/src/StringUtils.cpp ${CMAKE_CURRENT_LIST_DIR}/src/TemplateUtils.cpp ${CMAKE_CURRENT_LIST_DIR}/src/TypeUtils.cpp ${CMAKE_CURRENT_LIST_DIR}/src/Utils.cpp ) set(CLAZY_CHECKS_SRCS ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/qcolor-from-literal.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/connect-non-signal.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/connect-not-normalized.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/container-anti-pattern.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/lambda-in-connect.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/qdatetimeutc.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/qenums.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/qfileinfo-exists.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/qgetenv.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/qmap-with-pointer-key.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/qstringarg.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/qstring-insensitive-allocation.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/qstringref.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/qt-macros.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/qvariant-template-instantiation.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/mutable-container-key.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/strict-iterators.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/temporaryiterator.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/unused-non-trivial-variable.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/writingtotemporary.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level0/wrong-qglobalstatic.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/autounexpectedqstringbuilder.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/child-event-qobject-cast.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/connect-3arg-lambda.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/detachingtemporary.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/foreach.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/inefficient-qlist-soft.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/install-event-filter.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/ctor-missing-parent-argument.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/nonpodstatic.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/qdeleteall.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/qproperty-without-notify.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/qstring-left.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/qlatin1string-non-ascii.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/range-loop.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/returning-data-from-temporary.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/ruleoftwosoft.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/post-event.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/incorrect-emit.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/overridden-signal.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/qhash-namespace.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level1/virtual-signal.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/base-class-event.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/container-inside-loop.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/function-args-by-ref.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/function-args-by-value.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/globalconstcharpointer.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/implicitcasts.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/missing-qobject-macro.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/missing-type-info.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/qstring-allocations.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/reservecandidates.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/ruleofthree.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/virtualcallsfromctor.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/returning-void-expression.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/copyable-polymorphic.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level3/assertwithsideeffects.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level3/detachingmember.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/level3/dynamic_cast.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/hiddenlevel/inefficientqlist.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/hiddenlevel/isempty-vs-count.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/hiddenlevel/tr-non-literal.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/hiddenlevel/qt4-qstring-from-array.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/detachingbase.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/inefficientqlistbase.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/requiredresults.cpp ${CMAKE_CURRENT_LIST_DIR}/src/checks/ruleofbase.cpp ) if(HAS_STD_REGEX) set(CLAZY_CHECKS_SRCS ${CLAZY_CHECKS_SRCS} ${CMAKE_CURRENT_LIST_DIR}/src/checks/level2/oldstyleconnect.cpp) endif() set(CLAZY_SHARED_SRCS # sources shared between clazy-standalone and clazy plugin ${CLAZY_CHECKS_SRCS} ${CMAKE_CURRENT_LIST_DIR}/src/ClazyContext.cpp ${CMAKE_CURRENT_LIST_DIR}/src/Clazy.cpp ) if (NOT CLAZY_BUILD_UTILS_LIB) set(CLAZY_SHARED_SRCS ${CLAZY_SHARED_SRCS} ${CLAZY_LIB_SRC}) endif() set(CLAZY_PLUGIN_SRCS # Sources for the plugin ${CLAZY_SHARED_SRCS} ) if (MSVC) set(CLAZY_STANDALONE_SRCS ${CLAZY_SHARED_SRCS} ${CMAKE_CURRENT_LIST_DIR}/src/ClazyStandaloneMain.cpp ) else() set(CLAZY_STANDALONE_SRCS ${CMAKE_CURRENT_LIST_DIR}/src/ClazyStandaloneMain.cpp ) endif() diff --git a/checks.json b/checks.json index beee0b8..5525027 100644 --- a/checks.json +++ b/checks.json @@ -1,379 +1,384 @@ { "available_categories" : ["readability", "qt4", "containers", "qstring", "cpp", "bug", "performance"], "checks" : [ { "name" : "inefficient-qlist", "level" : -1, "categories" : ["containers", "performance"] }, { "name" : "isempty-vs-count", "level" : -1, "categories" : ["readability"] }, { "name" : "qt4-qstring-from-array", "level" : -1, "categories" : ["qt4", "qstring"], "fixits" : [ { "name" : "qt4-qstring-from-array" } ] }, { "name" : "connect-non-signal", "level" : 0, "categories" : ["bug"] }, { "name" : "lambda-in-connect", "level" : 0, "categories" : ["bug"] }, { "name" : "qdatetime-utc", "level" : 0, "categories" : ["performance"], "fixits" : [ { "name" : "qdatetime-utc" } ] }, { "name" : "qgetenv", "level" : 0, "categories" : ["performance"], "fixits" : [ { "name" : "qgetenv" } ] }, { "name" : "qstring-insensitive-allocation", "level" : 0, "categories" : ["performance", "qstring"] }, { "name" : "qvariant-template-instantiation", "level" : 0 }, { "name" : "unused-non-trivial-variable", "level" : 0, "categories" : ["readability"] }, { "name" : "connect-not-normalized", "level" : 0, "categories" : ["performance"] }, { "name" : "mutable-container-key", "level" : 0, "categories" : ["containers", "bug"] }, { "name" : "qenums", "level" : 0, "categories" : ["deprecation"] }, { "name" : "qmap-with-pointer-key", "level" : 0, "categories" : ["containers", "performance"] }, { "name" : "qstring-ref", "level" : 0, "categories" : ["performance", "qstring"], "fixits" : [ { "name" : "missing-qstringref" } ] }, { "name" : "strict-iterators", "level" : 0, "categories" : ["containers", "performance", "bug"] }, { "name" : "writing-to-temporary", "level" : 0, "categories" : ["bug"], "options" : [ { "name" : "widen-criteria" } ] }, { "name" : "container-anti-pattern", "level" : 0, "categories" : ["containers", "performance"] }, { "name" : "qcolor-from-literal", "level" : 0, "categories" : ["performance"] }, { "name" : "qfileinfo-exists", "level" : 0, "categories" : ["performance"] }, { "name" : "qstring-arg", "level" : 0, "categories" : ["performance", "qstring"], "options" : [ { "name" : "fillChar-overloads" } ] }, { "name" : "qt-macros", "level" : 0, "categories" : ["bug"] }, { "name" : "temporary-iterator", "level" : 0, "categories" : ["containers", "bug"] }, { "name" : "wrong-qglobalstatic", "level" : 0, "categories" : ["performance"] }, { "name" : "auto-unexpected-qstringbuilder", "level" : 1, "categories" : ["bug", "qstring"], "fixits" : [ { "name" : "auto-unexpected-qstringbuilder" } ] }, { "name" : "connect-3arg-lambda", "level" : 1, "categories" : ["bug"] }, { "name" : "ctor-missing-parent-argument", "level" : 1 }, { "name" : "detaching-temporary", "level" : 1, "categories" : ["containers", "performance"] }, { "name" : "foreach", "level" : 1, "categories" : ["containers", "performance"] }, { "name" : "incorrect-emit", "level" : 1, "categories" : ["readability"] }, { "name" : "inefficient-qlist-soft", "level" : 1, "categories" : ["containers", "performance"] }, { "name" : "install-event-filter", "level" : 1, "categories" : ["bug"] }, { "name" : "non-pod-global-static", "level" : 1, "categories" : ["performance"] }, { "name" : "post-event", "level" : 1, "categories" : ["bug"] }, { "name" : "qdeleteall", "level" : 1, "categories" : ["containers", "performance"] }, { "name" : "qlatin1string-non-ascii", "level" : 1, "categories" : ["bug", "qstring"] }, { "name" : "qproperty-without-notify", "level" : 1, "categories" : ["bug"] }, { "name" : "qstring-left", "level" : 1, "categories" : ["bug", "performance", "qstring"] }, { "name" : "range-loop", "level" : 1, "categories" : ["containers", "performance"] }, { "name" : "returning-data-from-temporary", "level" : 1, "categories" : ["bug"] }, { "name" : "rule-of-two-soft", "level" : 1, "categories" : ["cpp", "bug"] }, { "name" : "child-event-qobject-cast", "level" : 1, "categories" : ["bug"] }, { "name" : "virtual-signal", "level" : 1, "categories" : ["bug", "readability"] }, { "name" : "overridden-signal", "level" : 1, "categories" : ["bug", "readability"] }, + { + "name" : "qhash-namespace", + "level" : 1, + "categories" : ["bug"] + }, { "name" : "base-class-event", "level" : 2, "categories" : ["bug"] }, { "name" : "container-inside-loop", "level" : 2, "categories" : ["containers", "performance"] }, { "name" : "copyable-polymorphic", "level" : 2, "categories" : ["cpp", "bug"] }, { "name" : "function-args-by-ref", "level" : 2, "categories" : ["cpp", "performance"] }, { "name" : "function-args-by-value", "level" : 2, "categories" : ["cpp", "performance"] }, { "name" : "global-const-char-pointer", "level" : 2, "categories" : ["cpp", "performance"] }, { "name" : "implicit-casts", "level" : 2, "categories" : ["cpp", "bug"], "options" : [ { "name" : "bool-to-int" } ] }, { "name" : "missing-qobject-macro", "level" : 2 }, { "name" : "missing-typeinfo", "level" : 2, "categories" : ["containers", "performance"] }, { "name" : "old-style-connect", "level" : 2, "categories" : ["performance"], "fixits" : [ { "name" : "old-style-connect" } ] }, { "name" : "qstring-allocations", "level" : 2, "categories" : ["performance", "qstring"], "fixits" : [ { "name" : "qlatin1string-allocations" }, { "name" : "fromLatin1_fromUtf8-allocations" }, { "name" : "fromCharPtrAllocations" } ], "options" : [ { "name" : "no-msvc-compat" } ] }, { "name" : "reserve-candidates", "level" : 2, "categories" : ["containers"] }, { "name" : "returning-void-expression", "level" : 2, "categories" : ["readability", "cpp"] }, { "name" : "rule-of-three", "level" : 2, "categories" : ["cpp", "bug"] }, { "name" : "virtual-call-ctor", "level" : 2, "categories" : ["cpp", "bug"] }, { "name" : "assert-with-side-effects", "level" : 3, "categories" : ["bug"] }, { "name" : "detaching-member", "level" : 3, "categories" : ["containers", "performance"] }, { "name" : "bogus-dynamic-cast", "level" : 3, "categories" : ["performance"], "options" : [ { "name" : "qobject" } ] } ] } diff --git a/src/ContextUtils.h b/src/ContextUtils.h index f195c6d..ed00e25 100644 --- a/src/ContextUtils.h +++ b/src/ContextUtils.h @@ -1,125 +1,171 @@ /* This file is part of the clazy static checker. Copyright (C) 2016 Sergio Martins 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. */ #ifndef CLAZY_CONTEXT_UTILS_H #define CLAZY_CONTEXT_UTILS_H #include "clazy_export.h" +#include "TypeUtils.h" #include #include #include #include #include #include namespace clang { class ValueDecl; class DeclContext; class SourceManager; class SourceLocation; class CXXMethodDecl; class ParentMap; } namespace ContextUtils { /** * Returns true if a decl is inside a function, instead of say a class field. * This returns true if "QList l;" is a local variable, instead of being a class field such * as struct Foo { QList l; } */ inline bool isValueDeclInFunctionContext(const clang::ValueDecl *valueDecl) { auto context = valueDecl ? valueDecl->getDeclContext() : nullptr; return context && llvm::isa(context) && !llvm::isa(valueDecl); } /** * Returns the list of scopes for a decl context (namespaces, classes, inner classes, etc) * The inner ones are at the beginning of the list */ CLAZYLIB_EXPORT std::vector contextsForDecl(clang::DeclContext *); /** * Returns the first context for a decl. */ inline clang::DeclContext * contextForDecl(clang::Decl *decl) { if (!decl) return nullptr; if (auto context = llvm::dyn_cast(decl)) return context; return decl->getDeclContext(); } +inline clang::NamespaceDecl *namespaceForDecl(clang::Decl *decl) +{ + if (!decl) + return nullptr; + + clang::DeclContext *declContext = decl->getDeclContext(); + while (declContext) { + if (auto ns = llvm::dyn_cast(declContext)) + return ns; + + declContext = declContext->getParent(); + } + + return nullptr; +} + +inline clang::NamespaceDecl *namespaceForType(clang::QualType q) +{ + if (q.isNull()) + return nullptr; + + q = TypeUtils::pointeeQualType(q); + // Check if it's a class, struct or union + clang::CXXRecordDecl *rec = q->getAsCXXRecordDecl(); + if (rec) + return namespaceForDecl(rec); + + // Or maybe it's a typedef to a builtin type: + auto typeDefType = q->getAs(); + if (typeDefType) { + clang::TypedefNameDecl* typedeff = typeDefType->getDecl(); + return namespaceForDecl(typedeff); + } + + return nullptr; +} + +inline clang::NamespaceDecl *namespaceForFunction(clang::FunctionDecl *func) +{ + if (auto ns = llvm::dyn_cast(func->getDeclContext())) + return ns; + + return namespaceForDecl(func); +} + /** * Returns the first context of type T in which the specified context is in. * Contexts are namespaces, classes, inner classes, functions, etc. */ template T* firstContextOfType(clang::DeclContext *context) { if (!context) return nullptr; if (llvm::isa(context)) return llvm::cast(context); return ContextUtils::firstContextOfType(context->getParent()); } /** * Returns fully/semi-fully qualified name for a method, but doesn't over-qualify with namespaces * which we're already in. * * if currentScope == nullptr will return a fully qualified name */ CLAZYLIB_EXPORT std::string getMostNeededQualifiedName(const clang::SourceManager &sourceManager, clang::CXXMethodDecl *method, clang::DeclContext *currentScope, clang::SourceLocation usageLoc, bool honourUsingDirectives); /** * Returns true, if in a specific context, we can take the address of a method * for example doing &ClassName::SomePrivateMember might not be possible if the member is private * but might be possible if we're in a context which is friend of ClassName * Or it might be protected but context is a derived class * * When inside a derived class scope it's possible to take the address of a protected base method * but only if you qualify it with the derived class name, so &Derived::baseMethod, instead of &Base::baseMethod * If this was the case then isSpecialProtectedCase will be true */ CLAZYLIB_EXPORT bool canTakeAddressOf(clang::CXXMethodDecl *method, clang::DeclContext *context, bool &isSpecialProtectedCase); } #endif diff --git a/src/checks/level1/README-qhash-namespace.md b/src/checks/level1/README-qhash-namespace.md new file mode 100644 index 0000000..ca4b646 --- /dev/null +++ b/src/checks/level1/README-qhash-namespace.md @@ -0,0 +1,4 @@ +# qhash-namespace + +Warns when a `qHash()` function is not declared inside the namespace of it's argument. +`qHash()` needs to be inside the namespace for ADL lookup to happen. diff --git a/src/checks/level1/qhash-namespace.cpp b/src/checks/level1/qhash-namespace.cpp new file mode 100644 index 0000000..ad8562c --- /dev/null +++ b/src/checks/level1/qhash-namespace.cpp @@ -0,0 +1,68 @@ +/* + This file is part of the clazy static checker. + + Copyright (C) 2017 Sergio Martins + + 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 "qhash-namespace.h" +#include "Utils.h" +#include "HierarchyUtils.h" +#include "QtUtils.h" +#include "TypeUtils.h" +#include "ContextUtils.h" +#include "StringUtils.h" +#include "checkmanager.h" + +#include + +using namespace clang; +using namespace std; + + +qhash_namespace::qhash_namespace(const std::string &name, ClazyContext *context) + : CheckBase(name, context) +{ +} + +void qhash_namespace::VisitDecl(clang::Decl *decl) +{ + auto func = dyn_cast(decl); + if (!func || isa(func) || func->getNumParams() == 0 || func->getNameAsString() != "qHash") + return; + + ParmVarDecl *firstArg = func->getParamDecl(0); + NamespaceDecl *argumentNS = ContextUtils::namespaceForType(firstArg->getType()); + NamespaceDecl *qHashNS = ContextUtils::namespaceForFunction(func); + + std::string msg; + if (qHashNS && argumentNS) { + const string argumentNSstr = argumentNS->getQualifiedNameAsString(); + const string qhashNSstr = qHashNS->getQualifiedNameAsString(); + if (argumentNSstr != qhashNSstr) + msg = "Move qHash(" + StringUtils::simpleTypeName(firstArg->getType(), lo()) + ") to " + argumentNSstr + " namespace for ADL lookup"; + } else if (qHashNS && !argumentNS) { + msg = "Move qHash(" + StringUtils::simpleTypeName(firstArg->getType(), lo()) + ") out of namespace " + qHashNS->getQualifiedNameAsString(); + } else if (!qHashNS && argumentNS) { + msg = "Move qHash(" + StringUtils::simpleTypeName(firstArg->getType(), lo()) + ") into " + argumentNS->getQualifiedNameAsString() + " namespace for ADL lookup"; + } + + if (!msg.empty()) + emitWarning(decl, msg); +} + +REGISTER_CHECK("qhash-namespace", qhash_namespace, CheckLevel1) diff --git a/src/checks/level1/qhash-namespace.h b/src/checks/level1/qhash-namespace.h new file mode 100644 index 0000000..820ca54 --- /dev/null +++ b/src/checks/level1/qhash-namespace.h @@ -0,0 +1,39 @@ +/* + This file is part of the clazy static checker. + + Copyright (C) 2017 Sergio Martins + + 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. +*/ + +#ifndef CLAZY_QHASH_NAMESPACE_H +#define CLAZY_QHASH_NAMESPACE_H + +#include "checkbase.h" + + +/** + * See README-qhash-namespace.md for more info. + */ +class qhash_namespace : public CheckBase +{ +public: + explicit qhash_namespace(const std::string &name, ClazyContext *context); + void VisitDecl(clang::Decl *decl) override; +private: +}; + +#endif diff --git a/tests/clazy/test_requested_checks.sh.expected b/tests/clazy/test_requested_checks.sh.expected index e6e8e6f..7c18018 100644 --- a/tests/clazy/test_requested_checks.sh.expected +++ b/tests/clazy/test_requested_checks.sh.expected @@ -1,118 +1,119 @@ -Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic +Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qhash-namespace, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic Invalid check: foo -Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic +Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qhash-namespace, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic Requested checks: foreach Requested checks: foreach, writing-to-temporary Invalid check: foo Requested checks: foreach, writing-to-temporary Requested checks: old-style-connect Requested checks: old-style-connect Requested checks: foreach, old-style-connect -Requested checks: auto-unexpected-qstringbuilder, base-class-event, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, container-inside-loop, copyable-polymorphic, ctor-missing-parent-argument, detaching-temporary, foreach, function-args-by-ref, function-args-by-value, global-const-char-pointer, implicit-casts, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, missing-qobject-macro, missing-typeinfo, mutable-container-key, non-pod-global-static, old-style-connect, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-allocations, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, reserve-candidates, returning-data-from-temporary, returning-void-expression, rule-of-three, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-call-ctor, virtual-signal, writing-to-temporary, wrong-qglobalstatic +Requested checks: auto-unexpected-qstringbuilder, base-class-event, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, container-inside-loop, copyable-polymorphic, ctor-missing-parent-argument, detaching-temporary, foreach, function-args-by-ref, function-args-by-value, global-const-char-pointer, implicit-casts, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, missing-qobject-macro, missing-typeinfo, mutable-container-key, non-pod-global-static, old-style-connect, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qhash-namespace, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-allocations, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, reserve-candidates, returning-data-from-temporary, returning-void-expression, rule-of-three, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-call-ctor, virtual-signal, writing-to-temporary, wrong-qglobalstatic Requested checks: implicit-casts Requested checks: foreach, implicit-casts Requested checks: old-style-connect Requested checks: connect-non-signal, connect-not-normalized, container-anti-pattern, lambda-in-connect, mutable-container-key, qcolor-from-literal, qdatetime-utc, qenums, qfileinfo-exists, qgetenv, qmap-with-pointer-key, qstring-arg, qstring-insensitive-allocation, qstring-ref, qt-macros, qvariant-template-instantiation, strict-iterators, temporary-iterator, unused-non-trivial-variable, writing-to-temporary, wrong-qglobalstatic -Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic +Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qhash-namespace, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic Requested checks: connect-non-signal, connect-not-normalized, container-anti-pattern, lambda-in-connect, mutable-container-key, qcolor-from-literal, qdatetime-utc, qenums, qfileinfo-exists, qgetenv, qmap-with-pointer-key, qstring-arg, qstring-insensitive-allocation, qstring-ref, qt-macros, qvariant-template-instantiation, reserve-candidates, strict-iterators, temporary-iterator, unused-non-trivial-variable, writing-to-temporary, wrong-qglobalstatic Requested checks: connect-non-signal, connect-not-normalized, container-anti-pattern, lambda-in-connect, mutable-container-key, qcolor-from-literal, qdatetime-utc, qenums, qfileinfo-exists, qgetenv, qmap-with-pointer-key, qstring-arg, qstring-insensitive-allocation, qstring-ref, qt-macros, qvariant-template-instantiation, strict-iterators, temporary-iterator, unused-non-trivial-variable, writing-to-temporary, wrong-qglobalstatic Requested checks: connect-non-signal, connect-not-normalized, container-anti-pattern, foreach, implicit-casts, lambda-in-connect, mutable-container-key, qcolor-from-literal, qdatetime-utc, qenums, qfileinfo-exists, qgetenv, qmap-with-pointer-key, qstring-arg, qstring-insensitive-allocation, qstring-ref, qt-macros, qvariant-template-instantiation, strict-iterators, temporary-iterator, unused-non-trivial-variable, writing-to-temporary, wrong-qglobalstatic -Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic +Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qhash-namespace, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic Test9 -Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic +Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qhash-namespace, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic Requested checks: connect-non-signal, connect-not-normalized, container-anti-pattern, lambda-in-connect, mutable-container-key, qcolor-from-literal, qdatetime-utc, qenums, qfileinfo-exists, qgetenv, qmap-with-pointer-key, qstring-arg, qstring-insensitive-allocation, qstring-ref, qt-macros, qvariant-template-instantiation, reserve-candidates, strict-iterators, temporary-iterator, unused-non-trivial-variable, writing-to-temporary, wrong-qglobalstatic Requested checks: connect-non-signal, connect-not-normalized, container-anti-pattern, implicit-casts, lambda-in-connect, mutable-container-key, qcolor-from-literal, qdatetime-utc, qenums, qfileinfo-exists, qgetenv, qmap-with-pointer-key, qstring-arg, qstring-insensitive-allocation, qstring-ref, qt-macros, qvariant-template-instantiation, reserve-candidates, strict-iterators, temporary-iterator, unused-non-trivial-variable, writing-to-temporary, wrong-qglobalstatic Requested checks: implicit-casts Requested checks: implicit-casts Could not find checks in comma separated string implicit-casts,no-implicit-casts Available checks and FixIts: - Checks from level0: - connect-non-signal - connect-not-normalized - container-anti-pattern - lambda-in-connect - mutable-container-key - qcolor-from-literal - qdatetime-utc (fix-qdatetime-utc) - qenums - qfileinfo-exists - qgetenv (fix-qgetenv) - qmap-with-pointer-key - qstring-arg - qstring-insensitive-allocation - qstring-ref (fix-missing-qstringref) - qt-macros - qvariant-template-instantiation - strict-iterators - temporary-iterator - unused-non-trivial-variable - writing-to-temporary - wrong-qglobalstatic - Checks from level1: - auto-unexpected-qstringbuilder (fix-auto-unexpected-qstringbuilder) - child-event-qobject-cast - connect-3arg-lambda - detaching-temporary - foreach - incorrect-emit - inefficient-qlist-soft - install-event-filter - non-pod-global-static - overridden-signal - post-event - qdeleteall + - qhash-namespace - qlatin1string-non-ascii - qproperty-without-notify - qstring-left - range-loop - returning-data-from-temporary - rule-of-two-soft - virtual-signal - Checks from level2: - base-class-event - container-inside-loop - copyable-polymorphic - ctor-missing-parent-argument - function-args-by-ref - function-args-by-value - global-const-char-pointer - implicit-casts - missing-qobject-macro - missing-typeinfo - old-style-connect (fix-old-style-connect) - qstring-allocations (fix-qlatin1string-allocations,fix-fromLatin1_fromUtf8-allocations,fix-fromCharPtrAllocations) - reserve-candidates - returning-void-expression - rule-of-three - virtual-call-ctor - Checks from level3: - assert-with-side-effects - bogus-dynamic-cast - detaching-member If nothing is specified, all checks from level0 and level1 will be run. To specify which checks to enable set the CLAZY_CHECKS env variable, for example: export CLAZY_CHECKS="level0" export CLAZY_CHECKS="level0,reserve-candidates,qstring-allocations" export CLAZY_CHECKS="reserve-candidates" or pass as compiler arguments, for example: -Xclang -plugin-arg-clang-lazy -Xclang reserve-candidates,qstring-allocations To enable FixIts for a check, also set the env variable CLAZY_FIXIT, for example: export CLAZY_FIXIT="fix-qlatin1string-allocations" FixIts are experimental and rewrite your code therefore only one FixIt is allowed per build. Specifying a list of different FixIts is not supported. Backup your code before running them. Requested checks: connect-non-signal, connect-not-normalized, container-anti-pattern, lambda-in-connect, mutable-container-key, qcolor-from-literal, qdatetime-utc, qfileinfo-exists, qmap-with-pointer-key, qstring-arg, qstring-insensitive-allocation, qstring-ref, qt-macros, qvariant-template-instantiation, strict-iterators, temporary-iterator, unused-non-trivial-variable, writing-to-temporary, wrong-qglobalstatic Requested checks: implicit-casts Requested checks: implicit-casts -Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic +Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qenums, qfileinfo-exists, qgetenv, qhash-namespace, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic Requested checks: connect-non-signal, connect-not-normalized, container-anti-pattern, lambda-in-connect, mutable-container-key, qcolor-from-literal, qdatetime-utc, qfileinfo-exists, qmap-with-pointer-key, qstring-arg, qstring-insensitive-allocation, qstring-ref, qt-macros, qvariant-template-instantiation, strict-iterators, temporary-iterator, unused-non-trivial-variable, writing-to-temporary, wrong-qglobalstatic -Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qfileinfo-exists, qgetenv, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic +Requested checks: auto-unexpected-qstringbuilder, child-event-qobject-cast, connect-3arg-lambda, connect-non-signal, connect-not-normalized, container-anti-pattern, detaching-temporary, foreach, incorrect-emit, inefficient-qlist-soft, install-event-filter, lambda-in-connect, mutable-container-key, non-pod-global-static, overridden-signal, post-event, qcolor-from-literal, qdatetime-utc, qdeleteall, qfileinfo-exists, qgetenv, qhash-namespace, qlatin1string-non-ascii, qmap-with-pointer-key, qproperty-without-notify, qstring-arg, qstring-insensitive-allocation, qstring-left, qstring-ref, qt-macros, qvariant-template-instantiation, range-loop, returning-data-from-temporary, rule-of-two-soft, strict-iterators, temporary-iterator, unused-non-trivial-variable, virtual-signal, writing-to-temporary, wrong-qglobalstatic diff --git a/tests/qhash-namespace/config.json b/tests/qhash-namespace/config.json new file mode 100644 index 0000000..e7e6e0c --- /dev/null +++ b/tests/qhash-namespace/config.json @@ -0,0 +1,7 @@ +{ + "tests" : [ + { + "filename" : "main.cpp" + } + ] +} diff --git a/tests/qhash-namespace/main.cpp b/tests/qhash-namespace/main.cpp new file mode 100644 index 0000000..7c7e329 --- /dev/null +++ b/tests/qhash-namespace/main.cpp @@ -0,0 +1,22 @@ +#include + +struct A { }; +uint qHash(A) { return 0; }; // OK + +namespace NS { + typedef int IntFoo; + struct B { struct B2 {}; struct B3 {}; }; + uint qHash(B) { return 0; }; // OK + uint qHash(B::B2) { return 0; }; // OK + namespace NS2 { + struct C {}; + uint qHash(C) { return 0; }; // OK + } + uint qHash(NS2::C) { return 0; }; // Warn + uint qHash(::A) { return 0; } // Warn + uint qHash(B::B3) { return 0; }; // OK +} +uint qHash(NS::B) { return 0; } // Warn +uint qHash(NS::B *) { return 0; } // Warn +uint qHash(NS::B::B3) { return 0; }; // Warn +uint qHash(NS::IntFoo) { return 0; } diff --git a/tests/qhash-namespace/main.cpp.expected b/tests/qhash-namespace/main.cpp.expected new file mode 100644 index 0000000..2265803 --- /dev/null +++ b/tests/qhash-namespace/main.cpp.expected @@ -0,0 +1,6 @@ +qhash-namespace/main.cpp:15:5: warning: Move qHash(NS::NS2::C) to NS::NS2 namespace for ADL lookup [-Wclazy-qhash-namespace] +qhash-namespace/main.cpp:16:5: warning: Move qHash(A) out of namespace NS [-Wclazy-qhash-namespace] +qhash-namespace/main.cpp:19:1: warning: Move qHash(NS::B) into NS namespace for ADL lookup [-Wclazy-qhash-namespace] +qhash-namespace/main.cpp:20:1: warning: Move qHash(NS::B *) into NS namespace for ADL lookup [-Wclazy-qhash-namespace] +qhash-namespace/main.cpp:21:1: warning: Move qHash(NS::B::B3) into NS namespace for ADL lookup [-Wclazy-qhash-namespace] +qhash-namespace/main.cpp:22:1: warning: Move qHash(NS::IntFoo) into NS namespace for ADL lookup [-Wclazy-qhash-namespace]