Add clang-tidy check google-global-names-in-headers.

Summary:
google-global-names-in-headers flags global namespace pollution in header files.
Right now it only triggers on using declarations and directives.

Reviewers: alexfh

Subscribers: curdeius

Differential Revision: http://reviews.llvm.org/D7563

llvm-svn: 228875
This commit is contained in:
Samuel Benzaquen 2015-02-11 21:21:05 +00:00
parent 3e76643a95
commit 59c8aa92b8
5 changed files with 137 additions and 0 deletions

View File

@ -4,6 +4,7 @@ add_clang_library(clangTidyGoogleModule
AvoidCStyleCastsCheck.cpp
ExplicitConstructorCheck.cpp
ExplicitMakePairCheck.cpp
GlobalNamesInHeadersCheck.cpp
GoogleTidyModule.cpp
IntegerTypesCheck.cpp
MemsetZeroLengthCheck.cpp

View File

@ -0,0 +1,53 @@
//===--- GlobalNamesInHeadersCheck.cpp - clang-tidy -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "GlobalNamesInHeadersCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Lex/Lexer.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace readability {
void
GlobalNamesInHeadersCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
Finder->addMatcher(
decl(anyOf(usingDecl(), usingDirectiveDecl()),
hasDeclContext(translationUnitDecl())).bind("using_decl"),
this);
}
void GlobalNamesInHeadersCheck::check(const MatchFinder::MatchResult &Result) {
const auto *D = Result.Nodes.getNodeAs<Decl>("using_decl");
// If it comes from a macro, we'll assume it is fine.
if (D->getLocStart().isMacroID())
return;
// Ignore if it comes from the "main" file ...
if (Result.SourceManager->isInMainFile(
Result.SourceManager->getExpansionLoc(D->getLocStart()))) {
// unless that file is a header.
StringRef Filename = Result.SourceManager->getFilename(
Result.SourceManager->getSpellingLoc(D->getLocStart()));
if (!Filename.endswith(".h"))
return;
}
diag(D->getLocStart(),
"using declarations in the global namespace in headers are prohibited");
}
} // namespace readability
} // namespace tidy
} // namespace clang

View File

@ -0,0 +1,34 @@
//===--- GlobalNamesInHeadersCheck.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_GOOGLE_GLOBAL_NAMES_IN_HEADERS_CHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GLOBAL_NAMES_IN_HEADERS_CHECK_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
namespace readability {
// Flag global namespace pollution in header files.
// Right now it only triggers on using declarations and directives.
class GlobalNamesInHeadersCheck : public ClangTidyCheck {
public:
GlobalNamesInHeadersCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace readability
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GLOBAL_NAMES_IN_HEADERS_CHECK_H

View File

@ -17,6 +17,7 @@
#include "AvoidCStyleCastsCheck.h"
#include "ExplicitConstructorCheck.h"
#include "ExplicitMakePairCheck.h"
#include "GlobalNamesInHeadersCheck.h"
#include "IntegerTypesCheck.h"
#include "MemsetZeroLengthCheck.h"
#include "NamedParameterCheck.h"
@ -58,6 +59,8 @@ public:
"google-readability-todo");
CheckFactories.registerCheck<readability::BracesAroundStatementsCheck>(
"google-readability-braces-around-statements");
CheckFactories.registerCheck<readability::GlobalNamesInHeadersCheck>(
"google-global-names-in-headers");
CheckFactories.registerCheck<readability::FunctionSizeCheck>(
"google-readability-function-size");
CheckFactories.registerCheck<readability::NamespaceCommentCheck>(

View File

@ -1,5 +1,6 @@
#include "ClangTidyTest.h"
#include "google/ExplicitConstructorCheck.h"
#include "google/GlobalNamesInHeadersCheck.h"
#include "gtest/gtest.h"
namespace clang {
@ -56,6 +57,51 @@ TEST(ExplicitConstructorCheckTest, RemoveExplicitWithMacros) {
"A(Foo);"));
}
class GlobalNamesInHeadersCheckTest : public ::testing::Test {
protected:
bool runCheckOnCode(const std::string &Code, const std::string &Filename) {
static const char *const Header = "namespace std {\n"
"class string {};\n"
"} // namespace std\n"
"\n"
"#define SOME_MACRO(x) using x\n";
std::vector<ClangTidyError> Errors;
std::vector<std::string> Args;
if (!StringRef(Filename).endswith(".cpp")) {
Args.emplace_back("-xc++-header");
}
test::runCheckOnCode<readability::GlobalNamesInHeadersCheck>(
Header + Code, &Errors, Filename, Args);
if (Errors.empty())
return false;
assert(Errors.size() == 1);
assert(
Errors[0].Message.Message ==
"using declarations in the global namespace in headers are prohibited");
return true;
}
};
TEST_F(GlobalNamesInHeadersCheckTest, UsingDeclarations) {
EXPECT_TRUE(runCheckOnCode("using std::string;", "foo.h"));
EXPECT_FALSE(runCheckOnCode("using std::string;", "foo.cpp"));
EXPECT_FALSE(runCheckOnCode("namespace my_namespace {\n"
"using std::string;\n"
"} // my_namespace\n",
"foo.h"));
EXPECT_FALSE(runCheckOnCode("SOME_MACRO(std::string);", "foo.h"));
}
TEST_F(GlobalNamesInHeadersCheckTest, UsingDirectives) {
EXPECT_TRUE(runCheckOnCode("using namespace std;", "foo.h"));
EXPECT_FALSE(runCheckOnCode("using namespace std;", "foo.cpp"));
EXPECT_FALSE(runCheckOnCode("namespace my_namespace {\n"
"using namespace std;\n"
"} // my_namespace\n",
"foo.h"));
EXPECT_FALSE(runCheckOnCode("SOME_MACRO(namespace std);", "foo.h"));
}
} // namespace test
} // namespace tidy
} // namespace clang