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))
117 std::optional<std::string> NamespaceNameAsWritten =
119 if (!NamespaceNameAsWritten)
122 if (NamespaceNameAsWritten->empty() != ND->isAnonymousNamespace()) {
127 Ends.push_back(LBraceLoc);
131 while (Lexer::getRawToken(Loc, Tok, Sources, getLangOpts()) ||
133 Loc = Loc.getLocWithOffset(1);
139 const bool NextTokenIsOnSameLine =
140 Sources.getSpellingLineNumber(Loc) == EndLine;
143 bool NeedLineBreak = NextTokenIsOnSameLine && Tok.isNot(tok::eof);
145 SourceRange OldCommentRange(AfterRBrace, AfterRBrace);
146 std::string Message =
"%0 not terminated with a closing comment";
147 bool HasComment =
false;
150 if (Tok.is(tok::comment) && NextTokenIsOnSameLine) {
151 const StringRef Comment(Sources.getCharacterData(Loc), Tok.getLength());
152 SmallVector<StringRef, 7> Groups;
153 if (NamespaceCommentPattern.match(Comment, &Groups)) {
154 const StringRef NamespaceNameInComment =
155 Groups.size() > 5 ? Groups[5] :
"";
156 const StringRef Anonymous = Groups.size() > 3 ? Groups[3] :
"";
158 if ((ND->isAnonymousNamespace() && NamespaceNameInComment.empty()) ||
159 (*NamespaceNameAsWritten == NamespaceNameInComment &&
160 Anonymous.empty())) {
170 NeedLineBreak = Comment.starts_with(
"/*");
172 SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
175 "%0 ends with a comment that refers to a wrong namespace '") +
176 NamespaceNameInComment +
"'")
178 }
else if (Comment.starts_with(
"//")) {
181 NeedLineBreak =
false;
183 SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
184 Message =
"%0 ends with an unrecognized comment";
190 const std::string NamespaceNameForDiag =
191 ND->isAnonymousNamespace()
192 ?
"anonymous namespace"
193 : (
"namespace '" + *NamespaceNameAsWritten +
"'");
196 if (!HasComment && AllowOmittingNamespaceComments)
199 std::string
Fix(SpacesBeforeComments,
' ');
200 Fix.append(
"// namespace");
201 if (!ND->isAnonymousNamespace())
202 Fix.append(
" ").append(*NamespaceNameAsWritten);
207 const SourceLocation DiagLoc =
208 OldCommentRange.getBegin() != OldCommentRange.getEnd()
209 ? OldCommentRange.getBegin()
210 : ND->getRBraceLoc();
212 diag(DiagLoc, Message) << NamespaceNameForDiag
213 << FixItHint::CreateReplacement(
214 CharSourceRange::getCharRange(OldCommentRange),
216 diag(ND->getLocation(),
"%0 starts here", DiagnosticIDs::Note)
217 << 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.