Index: clang-tidy/CMakeLists.txt =================================================================== --- clang-tidy/CMakeLists.txt +++ clang-tidy/CMakeLists.txt @@ -46,3 +46,4 @@ add_subdirectory(readability) add_subdirectory(tool) add_subdirectory(utils) +add_subdirectory(zircon) Index: clang-tidy/tool/CMakeLists.txt =================================================================== --- clang-tidy/tool/CMakeLists.txt +++ clang-tidy/tool/CMakeLists.txt @@ -34,6 +34,7 @@ clangTidyPerformanceModule clangTidyPortabilityModule clangTidyReadabilityModule + clangTidyZirconModule clangTooling clangToolingCore ) Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -579,6 +579,11 @@ static int LLVM_ATTRIBUTE_UNUSED HICPPModuleAnchorDestination = HICPPModuleAnchorSource; +// This anchor is used to force the linker to link the ZirconModule. +extern volatile int ZirconModuleAnchorSource; +static int LLVM_ATTRIBUTE_UNUSED ZirconModuleAnchorDestination = + ZirconModuleAnchorSource; + } // namespace tidy } // namespace clang Index: clang-tidy/zircon/CMakeLists.txt =================================================================== --- /dev/null +++ clang-tidy/zircon/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_LINK_COMPONENTS support) + +add_clang_library(clangTidyZirconModule + TemporaryObjectsCheck.cpp + ZirconTidyModule.cpp + + LINK_LIBS + clangAST + clangASTMatchers + clangBasic + clangLex + clangTidy + clangTidyUtils + ) Index: clang-tidy/zircon/TemporaryObjectsCheck.h =================================================================== --- /dev/null +++ clang-tidy/zircon/TemporaryObjectsCheck.h @@ -0,0 +1,42 @@ +//===--- TemporaryObjectsCheck.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_ZIRCON_TEMPORARYOBJECTSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_TEMPORARYOBJECTSCHECK_H + +#include "../ClangTidy.h" +#include "../utils/OptionsUtils.h" + +namespace clang { +namespace tidy { +namespace zircon { + +/// Construction of specific temporary objects in the Zircon kernel is +/// discouraged. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/zircon-temporary-objects.html +class TemporaryObjectsCheck : public ClangTidyCheck { +public: + TemporaryObjectsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + Names(utils::options::parseStringList(Options.get("Names", ""))) {} + 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 zircon +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_TEMPORARYOBJECTSCHECK_H Index: clang-tidy/zircon/TemporaryObjectsCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/zircon/TemporaryObjectsCheck.cpp @@ -0,0 +1,60 @@ +//===--- TemporaryObjectsCheck.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 "TemporaryObjectsCheck.h" +#include "../utils/OptionsUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace zircon { + +AST_MATCHER_P(CXXRecordDecl, matchesAnyName, ArrayRef, Names) { + std::string QualifiedName = Node.getQualifiedNameAsString(); + return llvm::any_of(Names, + [&](StringRef Name) { return QualifiedName == Name; }); +} + +void TemporaryObjectsCheck::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 TemporaryObjectsCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *D = Result.Nodes.getNodeAs("temps")) + diag(D->getLocation(), + "creating a temporary object of type %0 is prohibited") + << D->getConstructor()->getParent(); +} + +void TemporaryObjectsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "Names", utils::options::serializeStringList(Names)); +} + +} // namespace zircon +} // namespace tidy +} // namespace clang Index: clang-tidy/zircon/ZirconTidyModule.cpp =================================================================== --- /dev/null +++ clang-tidy/zircon/ZirconTidyModule.cpp @@ -0,0 +1,40 @@ +//===--- ZirconTidyModule.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 "../ClangTidy.h" +#include "../ClangTidyModule.h" +#include "../ClangTidyModuleRegistry.h" +#include "TemporaryObjectsCheck.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace zircon { + +/// This module is for Zircon-specific checks. +class ZirconModule : public ClangTidyModule { +public: + void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "zircon-temporary-objects"); + } +}; + +// Register the ZirconTidyModule using this statically initialized variable. +static ClangTidyModuleRegistry::Add + X("zircon-module", "Adds Zircon kernel checks."); +} // namespace zircon + +// This anchor is used to force the linker to link in the generated object file +// and thus register the ZirconModule. +volatile int ZirconModuleAnchorSource = 0; + +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -59,6 +59,8 @@ - New module ``portability``. +- New module ``zircon`` for checks related to Fuchsia's Zircon kernel. + - New `bugprone-throw-keyword-missing `_ check @@ -159,6 +161,11 @@ - The 'misc-undelegated-constructor' check was renamed to `bugprone-undelegated-constructor `_ +- New `zircon-temporary-objects + `_ check + + Warns on construction of specific temporary objects in the Zircon kernel. + Improvements to include-fixer ----------------------------- Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -225,3 +225,4 @@ readability-static-definition-in-anonymous-namespace readability-string-compare readability-uniqueptr-delete-release + zircon-temporary-objects Index: docs/clang-tidy/checks/zircon-temporary-objects.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/zircon-temporary-objects.rst @@ -0,0 +1,40 @@ +.. title:: clang-tidy - zircon-temporary-objects + +zircon-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/index.rst =================================================================== --- docs/clang-tidy/index.rst +++ docs/clang-tidy/index.rst @@ -75,6 +75,7 @@ relate to any particular coding style. ``readability-`` Checks that target readability-related issues that don't relate to any particular coding style. +``zircon-`` Checks related to Zircon kernel coding conventions. ====================== ========================================================= Clang diagnostics are treated in a similar way as check diagnostics. Clang Index: test/clang-tidy/zircon-temporary-objects.cpp =================================================================== --- /dev/null +++ test/clang-tidy/zircon-temporary-objects.cpp @@ -0,0 +1,109 @@ +// RUN: %check_clang_tidy %s zircon-temporary-objects %t -- \ +// RUN: -config="{CheckOptions: [{key: zircon-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: creating a temporary object of type 'Foo' is prohibited + Foo F3 = Foo(); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: creating a temporary object of type 'Foo' is prohibited + + Bar(); + NS::Bar(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'Bar' is prohibited + + int A = func(Foo()); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: creating a temporary object of type 'Foo' is prohibited + + Foo F4(0); + Foo *F5 = new Foo(0); + new Foo(0); + Foo(0); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'Foo' is prohibited + Foo F6 = Foo(0); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: creating a temporary object of type 'Foo' is prohibited + + Bar(0); + NS::Bar(0); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'Bar' is prohibited + + int B = func(Foo(0)); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: creating a temporary object of type 'Foo' is prohibited +} + +namespace NS { + +void f() { + Bar(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'Bar' is prohibited + Bar(0); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'Bar' is prohibited +} + +} // namespace NS + +template +Ty make_ty() { return Ty(); } +// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: creating a temporary object of type 'Bar' is prohibited +// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: creating a temporary object of type 'Foo' is prohibited + +void ty_func() { + make_ty(); + make_ty(); + make_ty(); +} + +// Inheriting the disallowed class does not trigger the check. + +class Bingo : NS::Bar {}; // Not explicitly disallowed + +void f2() { + Bingo(); +} + +template +class Quux : Ty {}; + +void f3() { + Quux(); // Diagnose + Quux(); // Fine? +}