[clang-tidy] Adding Fuchsia checker for statically constructed objects

Adds a check to the Fuchsia module to warn if statically-stored objects
are created, unless constructed with `constexpr`.

See https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md for
reference.

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

llvm-svn: 322310
This commit is contained in:
Julie Hockett 2018-01-11 21:17:43 +00:00
parent d423f0d290
commit 1ee1f49393
8 changed files with 240 additions and 1 deletions

View File

@ -4,6 +4,7 @@ add_clang_library(clangTidyFuchsiaModule
DefaultArgumentsCheck.cpp
FuchsiaTidyModule.cpp
OverloadedOperatorCheck.cpp
StaticallyConstructedObjectsCheck.cpp
VirtualInheritanceCheck.cpp
LINK_LIBS

View File

@ -12,6 +12,7 @@
#include "../ClangTidyModuleRegistry.h"
#include "DefaultArgumentsCheck.h"
#include "OverloadedOperatorCheck.h"
#include "StaticallyConstructedObjectsCheck.h"
#include "VirtualInheritanceCheck.h"
using namespace clang::ast_matchers;
@ -28,6 +29,8 @@ public:
"fuchsia-default-arguments");
CheckFactories.registerCheck<OverloadedOperatorCheck>(
"fuchsia-overloaded-operator");
CheckFactories.registerCheck<StaticallyConstructedObjectsCheck>(
"fuchsia-statically-constructed-objects");
CheckFactories.registerCheck<VirtualInheritanceCheck>(
"fuchsia-virtual-inheritance");
}

View File

@ -0,0 +1,58 @@
//===--- StaticallyConstructedObjectsCheck.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 "StaticallyConstructedObjectsCheck.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace fuchsia {
AST_MATCHER(Expr, isConstantInitializer) {
return Node.isConstantInitializer(Finder->getASTContext(), false);
}
AST_MATCHER(VarDecl, isGlobalStatic) {
return Node.getStorageDuration() == SD_Static && !Node.isLocalVarDecl();
}
void StaticallyConstructedObjectsCheck::registerMatchers(MatchFinder *Finder) {
// Constructing global, non-trivial objects with static storage is
// disallowed, unless the object is statically initialized with a constexpr
// constructor or has no explicit constructor.
// Constexpr requires C++11 or later.
if (!getLangOpts().CPlusPlus11)
return;
Finder->addMatcher(
varDecl(allOf(
// Match global, statically stored objects...
isGlobalStatic(),
// ... that have C++ constructors...
hasDescendant(cxxConstructExpr(unless(allOf(
// ... unless it is constexpr ...
hasDeclaration(cxxConstructorDecl(isConstexpr())),
// ... and is statically initialized.
isConstantInitializer()))))))
.bind("decl"),
this);
}
void StaticallyConstructedObjectsCheck::check(
const MatchFinder::MatchResult &Result) {
if (const auto *D = Result.Nodes.getNodeAs<VarDecl>("decl"))
diag(D->getLocStart(), "static objects are disallowed; if possible, use a "
"constexpr constructor instead");
}
} // namespace fuchsia
} // namespace tidy
} // namespace clang

View File

@ -0,0 +1,37 @@
//===--- StaticallyConstructedObjectsCheck.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_STATICALLY_CONSTRUCTED_OBJECTS_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_STATICALLY_CONSTRUCTED_OBJECTS_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace fuchsia {
/// Constructing global, non-trivial objects with static storage is
/// disallowed, unless the object is statically initialized with a constexpr
/// constructor or has no explicit constructor.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-statically-constructed-objects.html
class StaticallyConstructedObjectsCheck : public ClangTidyCheck {
public:
StaticallyConstructedObjectsCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace fuchsia
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_STATICALLY_CONSTRUCTED_OBJECTS_H

View File

@ -57,7 +57,12 @@ The improvements are...
Improvements to clang-tidy
--------------------------
- ...
- New `fuchsia-statically-constructed-objects
<http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-statically-constructed-objects.html>`_ check
Warns if global, non-trivial objects with static storage are constructed, unless the
object is statically initialized with a ``constexpr`` constructor or has no
explicit constructor.
Improvements to include-fixer
-----------------------------

View File

@ -0,0 +1,43 @@
.. title:: clang-tidy - fuchsia-statically-constructed-objects
fuchsia-statically-constructed-objects
======================================
Warns if global, non-trivial objects with static storage are constructed, unless
the object is statically initialized with a ``constexpr`` constructor or has no
explicit constructor.
For example:
.. code-block:: c++
class A {};
class B {
public:
B(int Val) : Val(Val) {}
private:
int Val;
};
class C {
public:
C(int Val) : Val(Val) {}
constexpr C() : Val(0) {}
private:
int Val;
};
static A a; // No warning, as there is no explicit constructor
static C c(0); // No warning, as constructor is constexpr
static B b(0); // Warning, as constructor is not constexpr
static C c2(0, 1); // Warning, as constructor is not constexpr
static int i; // No warning, as it is trivial
extern int get_i();
static C(get_i()) // Warning, as the constructor is dynamically initialized
See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md

View File

@ -70,6 +70,7 @@ Clang-Tidy Checks
cppcoreguidelines-special-member-functions
fuchsia-default-arguments
fuchsia-overloaded-operator
fuchsia-statically-constructed-objects
fuchsia-virtual-inheritance
google-build-explicit-make-pair
google-build-namespaces

View File

@ -0,0 +1,91 @@
// RUN: %check_clang_tidy %s fuchsia-statically-constructed-objects %t
// Trivial static is fine
static int i;
class ClassWithNoCtor {};
class ClassWithCtor {
public:
ClassWithCtor(int Val) : Val(Val) {}
private:
int Val;
};
class ClassWithConstexpr {
public:
ClassWithConstexpr(int Val1, int Val2) : Val(Val1) {}
constexpr ClassWithConstexpr(int Val) : Val(Val) {}
private:
int Val;
};
ClassWithNoCtor A;
ClassWithConstexpr C(0);
ClassWithConstexpr E(0, 1);
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
// CHECK-MESSAGES-NEXT: ClassWithConstexpr E(0, 1);
ClassWithCtor G(0);
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
// CHECK-MESSAGES-NEXT: ClassWithCtor G(0);
static ClassWithNoCtor A2;
static ClassWithConstexpr C2(0);
static ClassWithConstexpr E2(0, 1);
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
// CHECK-MESSAGES-NEXT: static ClassWithConstexpr E2(0, 1);
static ClassWithCtor G2(0);
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
// CHECK-MESSAGES-NEXT: static ClassWithCtor G2(0);
struct StructWithConstexpr { constexpr StructWithConstexpr(int Val) {} };
struct StructWithNoCtor {};
struct StructWithCtor { StructWithCtor(); };
StructWithNoCtor SNoCtor;
StructWithConstexpr SConstexpr(0);
StructWithCtor SCtor;
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
// CHECK-MESSAGES-NEXT: StructWithCtor SCtor;
static StructWithConstexpr SConstexpr2(0);
static StructWithNoCtor SNoCtor2;
static StructWithCtor SCtor2;
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
// CHECK-MESSAGES-NEXT: static StructWithCtor SCtor2;
extern StructWithCtor SCtor3;
class ClassWithStaticMember {
private:
static StructWithNoCtor S;
};
ClassWithStaticMember Z();
class S {
int Val;
public:
constexpr S(int i) : Val(100 / i) {}
int getVal() const { return Val; }
};
static S s1(1);
static S s2(0);
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
// CHECK-MESSAGES-NEXT: static S s2(0);
extern int get_i();
static S s3(get_i());
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
// CHECK-MESSAGES-NEXT: static S s3(get_i());
void f() {
// Locally static is fine
static int i;
static ClassWithNoCtor A2;
static ClassWithConstexpr C2(0);
static ClassWithConstexpr E2(0, 1);
static ClassWithCtor G2(0);
}