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 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 unsigned StartLine = Sources.getSpellingLineNumber(ND->getBeginLoc());
100 unsigned EndLine = Sources.getSpellingLineNumber(ND->getRBraceLoc());
101 if (EndLine - StartLine + 1 <= ShortNamespaceLines)
105 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 bool NextTokenIsOnSameLine = 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 StringRef Comment(Sources.getCharacterData(Loc), Tok.getLength());
152 SmallVector<StringRef, 7> Groups;
153 if (NamespaceCommentPattern.match(Comment, &Groups)) {
154 StringRef NamespaceNameInComment = Groups.size() > 5 ? Groups[5] :
"";
155 StringRef Anonymous = Groups.size() > 3 ? Groups[3] :
"";
157 if ((ND->isAnonymousNamespace() && NamespaceNameInComment.empty()) ||
158 (*NamespaceNameAsWritten == NamespaceNameInComment &&
159 Anonymous.empty())) {
169 NeedLineBreak = Comment.starts_with(
"/*");
171 SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
174 "%0 ends with a comment that refers to a wrong namespace '") +
175 NamespaceNameInComment +
"'")
177 }
else if (Comment.starts_with(
"//")) {
180 NeedLineBreak =
false;
182 SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
183 Message =
"%0 ends with an unrecognized comment";
189 std::string NamespaceNameForDiag =
190 ND->isAnonymousNamespace()
191 ?
"anonymous namespace"
192 : (
"namespace '" + *NamespaceNameAsWritten +
"'");
195 if (!HasComment && AllowOmittingNamespaceComments)
198 std::string
Fix(SpacesBeforeComments,
' ');
199 Fix.append(
"// namespace");
200 if (!ND->isAnonymousNamespace())
201 Fix.append(
" ").append(*NamespaceNameAsWritten);
206 SourceLocation DiagLoc =
207 OldCommentRange.getBegin() != OldCommentRange.getEnd()
208 ? OldCommentRange.getBegin()
209 : ND->getRBraceLoc();
211 diag(DiagLoc, Message) << NamespaceNameForDiag
212 << FixItHint::CreateReplacement(
213 CharSourceRange::getCharRange(OldCommentRange),
215 diag(ND->getLocation(),
"%0 starts here", DiagnosticIDs::Note)
216 << 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.