[clang-tidy] Add Zircon module to clang-tidy

Adding a Zircon module to clang-tidy for checks specific to the Zircon
kernel, and adding a checker to fuchsia-zx (for zircon) to flag instances
where specific objects are temporarily created.

Differential Revision: https://reviews.llvm.org/D44346

llvm-svn: 327590
This commit is contained in:
Julie Hockett 2018-03-14 23:47:50 +00:00
parent 9407bb5f54
commit b6f7c934ac
12 changed files with 334 additions and 0 deletions

View File

@ -46,3 +46,4 @@ add_subdirectory(portability)
add_subdirectory(readability)
add_subdirectory(tool)
add_subdirectory(utils)
add_subdirectory(zircon)

View File

@ -34,6 +34,7 @@ target_link_libraries(clang-tidy
clangTidyPerformanceModule
clangTidyPortabilityModule
clangTidyReadabilityModule
clangTidyZirconModule
clangTooling
clangToolingCore
)

View File

@ -579,6 +579,11 @@ extern volatile int HICPPModuleAnchorSource;
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

View File

@ -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
)

View File

@ -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 <string>
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace zircon {
AST_MATCHER_P(CXXRecordDecl, matchesAnyName, ArrayRef<std::string>, 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<CXXConstructExpr>("temps"))
diag(D->getLocation(),
"creating a temporary object of type %q0 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

View File

@ -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<std::string> Names;
};
} // namespace zircon
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_TEMPORARYOBJECTSCHECK_H

View File

@ -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<TemporaryObjectsCheck>(
"zircon-temporary-objects");
}
};
// Register the ZirconTidyModule using this statically initialized variable.
static ClangTidyModuleRegistry::Add<ZirconModule>
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

View File

@ -59,6 +59,8 @@ Improvements to clang-tidy
- New module ``portability``.
- New module ``zircon`` for checks related to Fuchsia's Zircon kernel.
- New `bugprone-throw-keyword-missing
<http://clang.llvm.org/extra/clang-tidy/checks/bugprone-throw-keyword-missing.html>`_ check
@ -159,6 +161,11 @@ Improvements to clang-tidy
- The 'misc-undelegated-constructor' check was renamed to `bugprone-undelegated-constructor
<http://clang.llvm.org/extra/clang-tidy/checks/bugprone-undelegated-constructor.html>`_
- New `zircon-temporary-objects
<http://clang.llvm.org/extra/clang-tidy/checks/zircon-temporary-objects.html>`_ check
Warns on construction of specific temporary objects in the Zircon kernel.
Improvements to include-fixer
-----------------------------

View File

@ -225,3 +225,4 @@ Clang-Tidy Checks
readability-static-definition-in-anonymous-namespace
readability-string-compare
readability-uniqueptr-delete-release
zircon-temporary-objects

View File

@ -0,0 +1,53 @@
.. title:: clang-tidy - zircon-temporary-objects
zircon-temporary-objects
========================
Warns on construction of specific temporary objects in the Zircon kernel.
If the object should be flagged, If the object should be flagged, the fully
qualified type name must be explicitly passed to the check.
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
Note that objects must be explicitly specified in order to be flagged,
and so objects that inherit a specified object will not be flagged.
This check matches temporary objects without regard for inheritance and so a
prohibited base class type does not similarly prohibit derived class types.
.. code-block:: c++
class Derived : Foo {} // Derived is not explicitly disallowed
Derived(); // and so temporary construction is 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.

View File

@ -75,6 +75,7 @@ Name prefix Description
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

View File

@ -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 'NS::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 'NS::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 'NS::Bar' is prohibited
Bar(0);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'NS::Bar' is prohibited
}
} // namespace NS
template <typename Ty>
Ty make_ty() { return Ty(); }
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: creating a temporary object of type 'Foo' is prohibited
// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: creating a temporary object of type 'NS::Bar' is prohibited
void ty_func() {
make_ty<Bar>();
make_ty<NS::Bar>();
make_ty<Foo>();
}
// Inheriting the disallowed class does not trigger the check.
class Bingo : NS::Bar {}; // Not explicitly disallowed
void f2() {
Bingo();
}
template <typename Ty>
class Quux : Ty {};
void f3() {
Quux<NS::Bar>();
Quux<Bar>();
}