53 const LangOptions &LangOpts) {
62 Loc, Sources, LangOpts)) {
63 Loc = T->getLocation();
64 if (T->is(tok::l_brace))
67 if (T->isOneOf(tok::l_square, tok::l_paren)) {
69 }
else if (T->isOneOf(tok::r_square, tok::r_paren)) {
71 }
else if (Nesting == 0) {
72 if (T->is(tok::raw_identifier)) {
73 const StringRef ID = T->getRawIdentifier();
74 if (ID !=
"namespace")
75 Result.append(std::string(ID));
78 }
else if (T->is(tok::coloncolon)) {
89 const auto *ND = Result.Nodes.getNodeAs<NamespaceDecl>(
"namespace");
90 const SourceManager &Sources = *Result.SourceManager;
93 if (ND->getBeginLoc().isMacroID() ||
99 const unsigned StartLine = Sources.getSpellingLineNumber(ND->getBeginLoc());
100 const unsigned EndLine = Sources.getSpellingLineNumber(ND->getRBraceLoc());
101 if (EndLine - StartLine + 1 <= ShortNamespaceLines)
105 const SourceLocation AfterRBrace = Lexer::getLocForEndOfToken(
106 ND->getRBraceLoc(), 0, Sources, getLangOpts());
107 SourceLocation Loc = AfterRBrace;
108 SourceLocation LBraceLoc = ND->getBeginLoc();
113 for (
const SourceLocation &EndOfNameLocation : Ends) {
114 if (Sources.isBeforeInTranslationUnit(ND->getLocation(), EndOfNameLocation))
118 std::optional<std::string> NamespaceNameAsWritten =
120 if (!NamespaceNameAsWritten)
123 if (NamespaceNameAsWritten->empty() != ND->isAnonymousNamespace()) {
128 Ends.push_back(LBraceLoc);
132 while (Lexer::getRawToken(Loc, Tok, Sources, getLangOpts()) ||
134 Loc = Loc.getLocWithOffset(1);
140 const bool NextTokenIsOnSameLine =
141 Sources.getSpellingLineNumber(Loc) == EndLine;
144 bool NeedLineBreak = NextTokenIsOnSameLine && Tok.isNot(tok::eof);
146 SourceRange OldCommentRange(AfterRBrace, AfterRBrace);
147 std::string Message =
"%0 not terminated with a closing comment";
148 bool HasComment =
false;
151 if (Tok.is(tok::comment) && NextTokenIsOnSameLine) {
152 const StringRef Comment(Sources.getCharacterData(Loc), Tok.getLength());
153 SmallVector<StringRef, 7> Groups;
154 if (NamespaceCommentPattern.match(Comment, &Groups)) {
155 const StringRef NamespaceNameInComment =
156 Groups.size() > 5 ? Groups[5] :
"";
157 const StringRef Anonymous = Groups.size() > 3 ? Groups[3] :
"";
159 if ((ND->isAnonymousNamespace() && NamespaceNameInComment.empty()) ||
160 (*NamespaceNameAsWritten == NamespaceNameInComment &&
161 Anonymous.empty())) {
171 NeedLineBreak = Comment.starts_with(
"/*");
173 SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
176 "%0 ends with a comment that refers to a wrong namespace '") +
177 NamespaceNameInComment +
"'")
179 }
else if (Comment.starts_with(
"//")) {
182 NeedLineBreak =
false;
184 SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
185 Message =
"%0 ends with an unrecognized comment";
191 const std::string NamespaceNameForDiag =
192 ND->isAnonymousNamespace()
193 ?
"anonymous namespace"
194 : (
"namespace '" + *NamespaceNameAsWritten +
"'");
197 if (!HasComment && AllowOmittingNamespaceComments)
200 std::string
Fix(SpacesBeforeComments,
' ');
201 Fix.append(
"// namespace");
202 if (!ND->isAnonymousNamespace())
203 Fix.append(
" ").append(*NamespaceNameAsWritten);
208 const SourceLocation DiagLoc =
209 OldCommentRange.getBegin() != OldCommentRange.getEnd()
210 ? OldCommentRange.getBegin()
211 : ND->getRBraceLoc();
213 diag(DiagLoc, Message) << NamespaceNameForDiag
214 << FixItHint::CreateReplacement(
215 CharSourceRange::getCharRange(OldCommentRange),
217 diag(ND->getLocation(),
"%0 starts here", DiagnosticIDs::Note)
218 << NamespaceNameForDiag;
static cl::opt< bool > Fix("fix", desc(R"(
Apply suggested fixes. Without -fix-errors
clang-tidy will bail out if any compilation
errors were found.
)"), cl::init(false), cl::cat(ClangTidyCategory))
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.