diff --git a/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.h b/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.h --- a/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.h +++ b/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.h @@ -26,6 +26,10 @@ NamespaceCommentCheck(StringRef Name, ClangTidyContext *Context); void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + + void addMacro(const std::string &Name, const std::string &Value) noexcept; private: void storeOptions(ClangTidyOptions::OptionMap &Options) override; @@ -34,6 +38,10 @@ const unsigned ShortNamespaceLines; const unsigned SpacesBeforeComments; llvm::SmallVector Ends; + + // Store macros to verify that warning is not thrown when namespace name is a + // preprocessed define + std::vector> Macros; }; } // namespace readability diff --git a/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.cpp b/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.cpp --- a/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.cpp @@ -19,6 +19,44 @@ namespace tidy { namespace readability { +namespace { +class NamespaceCommentPPCallbacks : public PPCallbacks { +public: + NamespaceCommentPPCallbacks(Preprocessor *PP, NamespaceCommentCheck *Check) + : PP(PP), Check(Check) {} + + void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) { + // Record all defined macros. We store the whole token to compare names + // later + + const MacroInfo *const MI = MD->getMacroInfo(); + + if (MI->isFunctionLike()) + return; + + std::string ValueBuffer; + llvm::raw_string_ostream Value(ValueBuffer); + + SmallString<128> SpellingBuffer; + bool First = true; + for (const auto &T : MI->tokens()) { + if (!First && T.hasLeadingSpace()) + Value << ' '; + + Value << PP->getSpelling(T, SpellingBuffer); + First = false; + } + + Check->addMacro(MacroNameTok.getIdentifierInfo()->getName().str(), + Value.str()); + } + +private: + Preprocessor *PP; + NamespaceCommentCheck *Check; +}; +} // namespace + NamespaceCommentCheck::NamespaceCommentCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), @@ -40,6 +78,11 @@ Finder->addMatcher(namespaceDecl().bind("namespace"), this); } +void NamespaceCommentCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + PP->addPPCallbacks(std::make_unique(PP, this)); +} + static bool locationsInSameFile(const SourceManager &Sources, SourceLocation Loc1, SourceLocation Loc2) { return Loc1.isFileID() && Loc2.isFileID() && @@ -65,6 +108,11 @@ return Fix; } +void NamespaceCommentCheck::addMacro(const std::string &Name, + const std::string &Value) noexcept { + Macros.emplace_back(Name, Value); +} + void NamespaceCommentCheck::check(const MatchFinder::MatchResult &Result) { const auto *ND = Result.Nodes.getNodeAs("namespace"); const SourceManager &Sources = *Result.SourceManager; @@ -156,6 +204,16 @@ return; } + const auto &MacroIt = + std::find_if(std::begin(Macros), std::end(Macros), + [&NamespaceNameInComment](const auto &Macro) { + return NamespaceNameInComment == Macro.first; + }); + + if (MacroIt != Macros.end()) { + return; + } + // Otherwise we need to fix the comment. NeedLineBreak = Comment.startswith("/*"); OldCommentRange = @@ -165,6 +223,7 @@ "%0 ends with a comment that refers to a wrong namespace '") + NamespaceNameInComment + "'") .str(); + } else if (Comment.startswith("//")) { // Assume that this is an unrecognized form of a namespace closing line // comment. Replace it. diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm-namespace-comment.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm-namespace-comment.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm-namespace-comment.cpp @@ -0,0 +1,27 @@ +// RUN: %check_clang_tidy %s llvm-namespace-comment %t + +namespace n1 { +namespace n2 { + void f(); + + + // CHECK-MESSAGES: :[[@LINE+2]]:1: warning: namespace 'n2' not terminated with a closing comment [llvm-namespace-comment] + // CHECK-MESSAGES: :[[@LINE+1]]:2: warning: namespace 'n1' not terminated with a closing comment [llvm-namespace-comment] +}} +// CHECK-FIXES: } // namespace n2 +// CHECK-FIXES: } // namespace n1 + +#define MACRO macro_expansion +namespace MACRO { + void f(); + // CHECK-MESSAGES: :[[@LINE+1]]:1: warning: namespace 'macro_expansion' not terminated with a closing comment [llvm-namespace-comment] +} +// CHECK-FIXES: } // namespace macro_expansion + +namespace MACRO { + void g(); +} // namespace MACRO + +namespace MACRO { + void h(); +} // namespace macro_expansion