Index: clang-tidy/fuchsia/CMakeLists.txt =================================================================== --- clang-tidy/fuchsia/CMakeLists.txt +++ clang-tidy/fuchsia/CMakeLists.txt @@ -8,6 +8,7 @@ StaticallyConstructedObjectsCheck.cpp TrailingReturnCheck.cpp VirtualInheritanceCheck.cpp + ZxTemporaryObjectsCheck.cpp LINK_LIBS clangAST Index: clang-tidy/fuchsia/FuchsiaTidyModule.cpp =================================================================== --- clang-tidy/fuchsia/FuchsiaTidyModule.cpp +++ clang-tidy/fuchsia/FuchsiaTidyModule.cpp @@ -16,6 +16,7 @@ #include "StaticallyConstructedObjectsCheck.h" #include "TrailingReturnCheck.h" #include "VirtualInheritanceCheck.h" +#include "ZxTemporaryObjectsCheck.h" using namespace clang::ast_matchers; @@ -39,6 +40,8 @@ "fuchsia-trailing-return"); CheckFactories.registerCheck( "fuchsia-virtual-inheritance"); + CheckFactories.registerCheck( + "fuchsia-zx-temporary-objects"); } }; // Register the FuchsiaTidyModule using this statically initialized variable. Index: clang-tidy/fuchsia/ZxTemporaryObjectsCheck.h =================================================================== --- /dev/null +++ clang-tidy/fuchsia/ZxTemporaryObjectsCheck.h @@ -0,0 +1,44 @@ +//===--- ZxTemporaryObjectsCheck.h - clang-tidy------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_ZXTEMPORARYOBJECTSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_ZXTEMPORARYOBJECTSCHECK_H + +#include "../ClangTidy.h" +#include "../utils/OptionsUtils.h" + +namespace clang { +namespace tidy { +namespace fuchsia { + +/// Constructing of specific temporary objects in the Zircon kernel is +/// discouraged. Takes the list of such discouraged temporary objects as a +/// parameter. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-zx-temporary-objects.html +class ZxTemporaryObjectsCheck : public ClangTidyCheck { +public: + ZxTemporaryObjectsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + Names(utils::options::parseStringList( + Options.get("Names", "::std::vector"))) {} + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + std::vector Names; +}; + +} // namespace fuchsia +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_ZXTEMPORARYOBJECTSCHECK_H Index: clang-tidy/fuchsia/ZxTemporaryObjectsCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/fuchsia/ZxTemporaryObjectsCheck.cpp @@ -0,0 +1,57 @@ +//===--- ZxTemporaryObjectsCheck.cpp - clang-tidy--------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ZxTemporaryObjectsCheck.h" +#include "../utils/OptionsUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/SmallVector.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace fuchsia { + +AST_MATCHER_P(CXXRecordDecl, matchesAnyName, ArrayRef, Names) { + std::string QualifiedName = Node.getQualifiedNameAsString(); + return llvm::any_of(Names, + [&](StringRef Name) { return QualifiedName == Name; }); +} + +void ZxTemporaryObjectsCheck::registerMatchers(MatchFinder *Finder) { + // Matcher for default constructors + Finder->addMatcher( + cxxTemporaryObjectExpr(hasDeclaration(cxxConstructorDecl(hasParent( + cxxRecordDecl(matchesAnyName(Names)))))) + .bind("temps"), + this); + + // Matcher for user-defined constructors + Finder->addMatcher( + cxxConstructExpr(allOf(hasParent(cxxFunctionalCastExpr()), + hasDeclaration(cxxConstructorDecl(hasParent( + cxxRecordDecl(matchesAnyName(Names))))))) + .bind("temps"), + this); +} + +void ZxTemporaryObjectsCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *D = Result.Nodes.getNodeAs("temps")) { + diag(D->getLocation(), "misuse of temporary object"); + } +} + +void ZxTemporaryObjectsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "Names", utils::options::serializeStringList(Names)); +} + +} // namespace fuchsia +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -72,6 +72,12 @@ with looping constructs. Every backward jump is rejected. Forward jumps are only allowed in nested loops. +- New `fuchsia-zx-temporary-objects + `_ check + + Warns on construction of specific temporary objects in the Zircon kernel. + Takes the list of such discouraged temporary objects as a parameter. + - New `fuchsia-multiple-inheritance `_ check Index: docs/clang-tidy/checks/fuchsia-zx-temporary-objects.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/fuchsia-zx-temporary-objects.rst @@ -0,0 +1,38 @@ +.. title:: clang-tidy - fuchsia-zx-temporary-objects + +fuchsia-zx-temporary-objects +============================ + +Warns on construction of specific temporary objects in the Zircon kernel. + +For example, given the list of classes "Foo" and "NS::Bar", all of the following will trigger the warning: + +.. code-block:: c++ + + Foo(); + Foo F = Foo(); + func(Foo()); + + namespace NS { + + Bar(); + + } + +With the same list, the following will not trigger the warning: + +.. code-block:: c++ + + Foo F; // Non-temporary construction okay + Foo F(param); // Non-temporary construction okay + Foo *F = new Foo(); // New construction okay + + Bar(); // Not NS::Bar, so okay + NS::Bar B; // Non-temporary construction okay + +Options +------- + +.. option:: Names + + A semi-colon-separated list of fully-qualified names of C++ classes that should not be constructed as temporaries. Default is empty. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -90,6 +90,7 @@ fuchsia-statically-constructed-objects fuchsia-trailing-return fuchsia-virtual-inheritance + fuchsia-zx-temporary-objects google-build-explicit-make-pair google-build-namespaces google-build-using-namespace Index: test/clang-tidy/fuchsia-zx-temporary-objects.cpp =================================================================== --- /dev/null +++ test/clang-tidy/fuchsia-zx-temporary-objects.cpp @@ -0,0 +1,82 @@ +// RUN: %check_clang_tidy %s fuchsia-zx-temporary-objects %t -- \ +// RUN: -config="{CheckOptions: [{key: fuchsia-zx-temporary-objects.Names, value: 'Foo;NS::Bar'}]}" \ +// RUN: -header-filter=.* \ +// RUN: -- -std=c++11 + +// Should flag instances of Foo, NS::Bar + +class Foo { +public: + Foo() = default; + Foo(int Val) : Val(Val){}; + +private: + int Val; +}; + +namespace NS { + +class Bar { +public: + Bar() = default; + Bar(int Val) : Val(Val){}; + +private: + int Val; +}; + +} // namespace NS + +class Bar { +public: + Bar() = default; + Bar(int Val) : Val(Val){}; + +private: + int Val; +}; + +int func(Foo F) { return 1; }; + +int main() { + Foo F; + Foo *F2 = new Foo(); + new Foo(); + Foo(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: misuse of temporary object + Foo F3 = Foo(); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: misuse of temporary object + + Bar(); + NS::Bar(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: misuse of temporary object + + int A = func(Foo()); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: misuse of temporary object + + Foo F4(0); + Foo *F5 = new Foo(0); + new Foo(0); + Foo(0); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: misuse of temporary object + Foo F6 = Foo(0); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: misuse of temporary object + + Bar(0); + NS::Bar(0); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: misuse of temporary object + + int B = func(Foo(0)); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: misuse of temporary object +} + +namespace NS { + +void f() { + Bar(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: misuse of temporary object + Bar(0); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: misuse of temporary object +} + +} // namespace NS