Index: clang-tidy/google/GlobalNamesInHeadersCheck.cpp =================================================================== --- clang-tidy/google/GlobalNamesInHeadersCheck.cpp +++ clang-tidy/google/GlobalNamesInHeadersCheck.cpp @@ -46,6 +46,24 @@ this); } +namespace { +std::string getIncludeFromMessage(SourceLocation DeclLoc, + const SourceManager &SM) { + FileID FID = SM.getFileID(DeclLoc); + bool Invalid; + const auto &Entry = SM.getSLocEntry(FID, &Invalid); + if (Invalid) + return ""; + SourceLocation IncludeLoc = Entry.getFile().getIncludeLoc(); + if (!IncludeLoc.isValid()) + return ""; + StringRef Filename = SM.getFilename(IncludeLoc); + if (Filename.empty()) + return ""; + return (Twine("; in file included from '") + Filename + "'").str(); +} +} // namespace + void GlobalNamesInHeadersCheck::check(const MatchFinder::MatchResult &Result) { const auto *D = Result.Nodes.getNodeAs("using_decl"); // If it comes from a macro, we'll assume it is fine. @@ -71,8 +89,12 @@ } } + std::string IncludeMessage = + getIncludeFromMessage(D->getLocStart(), *Result.SourceManager); + diag(D->getLocStart(), - "using declarations in the global namespace in headers are prohibited"); + "using declarations in the global namespace in headers are prohibited%0") + << IncludeMessage; } } // namespace readability Index: unittests/clang-tidy/GoogleModuleTest.cpp =================================================================== --- unittests/clang-tidy/GoogleModuleTest.cpp +++ unittests/clang-tidy/GoogleModuleTest.cpp @@ -58,10 +58,12 @@ class GlobalNamesInHeadersCheckTest : public ::testing::Test { protected: - bool runCheckOnCode(const std::string &Code, const std::string &Filename) { + bool runCheckOnCode(const std::string &Code, const std::string &Filename, + bool IsIncluded = false) { static const char *const Header = "namespace std {\n" "class string {};\n" "} // namespace std\n" + "#include \"header.h\"\n" "\n" "#define SOME_MACRO(x) using x\n"; std::vector Errors; @@ -69,14 +71,21 @@ if (!StringRef(Filename).endswith(".cpp")) { Args.emplace_back("-xc++-header"); } + std::map Paths; + Paths["header.h"] = IsIncluded ? StringRef(Code) : StringRef("\n"); + ClangTidyOptions Options; + Options.HeaderFilterRegex = ".*"; test::runCheckOnCode( - Header + Code, &Errors, Filename, Args); + Header + (IsIncluded ? "" : Code), &Errors, + IsIncluded ? "main.cpp" : Filename, Args, Options, Paths); if (Errors.empty()) return false; assert(Errors.size() == 1); - assert( - Errors[0].Message.Message == - "using declarations in the global namespace in headers are prohibited"); + std::string Expected = + "using declarations in the global namespace in headers are prohibited"; + if (IsIncluded) + Expected += "; in file included from 'main.cpp'"; + assert(Errors[0].Message.Message == Expected); return true; } }; @@ -89,6 +98,7 @@ "} // my_namespace\n", "foo.h")); EXPECT_FALSE(runCheckOnCode("SOME_MACRO(std::string);", "foo.h")); + EXPECT_TRUE(runCheckOnCode("using std::string;", "foo.h", true)); } TEST_F(GlobalNamesInHeadersCheckTest, UsingDirectives) { @@ -99,6 +109,7 @@ "} // my_namespace\n", "foo.h")); EXPECT_FALSE(runCheckOnCode("SOME_MACRO(namespace std);", "foo.h")); + EXPECT_TRUE(runCheckOnCode("using namespace std;", "foo.h", true)); } TEST_F(GlobalNamesInHeadersCheckTest, RegressionAnonymousNamespace) {