1e5dd7070Spatrick //===--- NamespaceEndCommentsFixer.cpp --------------------------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick ///
9e5dd7070Spatrick /// \file
10e5dd7070Spatrick /// This file implements NamespaceEndCommentsFixer, a TokenAnalyzer that
11e5dd7070Spatrick /// fixes namespace end comments.
12e5dd7070Spatrick ///
13e5dd7070Spatrick //===----------------------------------------------------------------------===//
14e5dd7070Spatrick
15e5dd7070Spatrick #include "NamespaceEndCommentsFixer.h"
16*12c85518Srobert #include "clang/Basic/TokenKinds.h"
17e5dd7070Spatrick #include "llvm/Support/Debug.h"
18e5dd7070Spatrick #include "llvm/Support/Regex.h"
19e5dd7070Spatrick
20e5dd7070Spatrick #define DEBUG_TYPE "namespace-end-comments-fixer"
21e5dd7070Spatrick
22e5dd7070Spatrick namespace clang {
23e5dd7070Spatrick namespace format {
24e5dd7070Spatrick
25e5dd7070Spatrick namespace {
26*12c85518Srobert // Iterates all tokens starting from StartTok to EndTok and apply Fn to all
27*12c85518Srobert // tokens between them including StartTok and EndTok. Returns the token after
28*12c85518Srobert // EndTok.
29*12c85518Srobert const FormatToken *
processTokens(const FormatToken * Tok,tok::TokenKind StartTok,tok::TokenKind EndTok,llvm::function_ref<void (const FormatToken *)> Fn)30*12c85518Srobert processTokens(const FormatToken *Tok, tok::TokenKind StartTok,
31*12c85518Srobert tok::TokenKind EndTok,
32*12c85518Srobert llvm::function_ref<void(const FormatToken *)> Fn) {
33*12c85518Srobert if (!Tok || Tok->isNot(StartTok))
34*12c85518Srobert return Tok;
35*12c85518Srobert int NestLevel = 0;
36*12c85518Srobert do {
37*12c85518Srobert if (Tok->is(StartTok))
38*12c85518Srobert ++NestLevel;
39*12c85518Srobert else if (Tok->is(EndTok))
40*12c85518Srobert --NestLevel;
41*12c85518Srobert if (Fn)
42*12c85518Srobert Fn(Tok);
43*12c85518Srobert Tok = Tok->getNextNonComment();
44*12c85518Srobert } while (Tok && NestLevel > 0);
45*12c85518Srobert return Tok;
46*12c85518Srobert }
47*12c85518Srobert
skipAttribute(const FormatToken * Tok)48*12c85518Srobert const FormatToken *skipAttribute(const FormatToken *Tok) {
49*12c85518Srobert if (!Tok)
50*12c85518Srobert return nullptr;
51*12c85518Srobert if (Tok->is(tok::kw___attribute)) {
52*12c85518Srobert Tok = Tok->getNextNonComment();
53*12c85518Srobert Tok = processTokens(Tok, tok::l_paren, tok::r_paren, nullptr);
54*12c85518Srobert } else if (Tok->is(tok::l_square)) {
55*12c85518Srobert Tok = processTokens(Tok, tok::l_square, tok::r_square, nullptr);
56*12c85518Srobert }
57*12c85518Srobert return Tok;
58*12c85518Srobert }
59*12c85518Srobert
60e5dd7070Spatrick // Computes the name of a namespace given the namespace token.
61e5dd7070Spatrick // Returns "" for anonymous namespace.
computeName(const FormatToken * NamespaceTok)62e5dd7070Spatrick std::string computeName(const FormatToken *NamespaceTok) {
63e5dd7070Spatrick assert(NamespaceTok &&
64e5dd7070Spatrick NamespaceTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro) &&
65e5dd7070Spatrick "expecting a namespace token");
66*12c85518Srobert std::string name;
67e5dd7070Spatrick const FormatToken *Tok = NamespaceTok->getNextNonComment();
68e5dd7070Spatrick if (NamespaceTok->is(TT_NamespaceMacro)) {
69e5dd7070Spatrick // Collects all the non-comment tokens between opening parenthesis
70e5dd7070Spatrick // and closing parenthesis or comma.
71e5dd7070Spatrick assert(Tok && Tok->is(tok::l_paren) && "expected an opening parenthesis");
72e5dd7070Spatrick Tok = Tok->getNextNonComment();
73e5dd7070Spatrick while (Tok && !Tok->isOneOf(tok::r_paren, tok::comma)) {
74e5dd7070Spatrick name += Tok->TokenText;
75e5dd7070Spatrick Tok = Tok->getNextNonComment();
76e5dd7070Spatrick }
77*12c85518Srobert return name;
78*12c85518Srobert }
79*12c85518Srobert Tok = skipAttribute(Tok);
80*12c85518Srobert
81*12c85518Srobert std::string FirstNSName;
82e5dd7070Spatrick // For `namespace [[foo]] A::B::inline C {` or
83e5dd7070Spatrick // `namespace MACRO1 MACRO2 A::B::inline C {`, returns "A::B::inline C".
84*12c85518Srobert // Peek for the first '::' (or '{' or '(')) and then return all tokens from
85*12c85518Srobert // one token before that up until the '{'. A '(' might be a macro with
86*12c85518Srobert // arguments.
87*12c85518Srobert const FormatToken *FirstNSTok = nullptr;
88*12c85518Srobert while (Tok && !Tok->isOneOf(tok::l_brace, tok::coloncolon, tok::l_paren)) {
89*12c85518Srobert if (FirstNSTok)
90*12c85518Srobert FirstNSName += FirstNSTok->TokenText;
91e5dd7070Spatrick FirstNSTok = Tok;
92e5dd7070Spatrick Tok = Tok->getNextNonComment();
93e5dd7070Spatrick }
94e5dd7070Spatrick
95*12c85518Srobert if (FirstNSTok)
96e5dd7070Spatrick Tok = FirstNSTok;
97*12c85518Srobert Tok = skipAttribute(Tok);
98*12c85518Srobert
99*12c85518Srobert FirstNSTok = nullptr;
100*12c85518Srobert // Add everything from '(' to ')'.
101*12c85518Srobert auto AddToken = [&name](const FormatToken *Tok) { name += Tok->TokenText; };
102*12c85518Srobert bool IsPrevColoncolon = false;
103*12c85518Srobert bool HasColoncolon = false;
104*12c85518Srobert bool IsPrevInline = false;
105*12c85518Srobert bool NameFinished = false;
106*12c85518Srobert // If we found '::' in name, then it's the name. Otherwise, we can't tell
107*12c85518Srobert // which one is name. For example, `namespace A B {`.
108*12c85518Srobert while (Tok && Tok->isNot(tok::l_brace)) {
109*12c85518Srobert if (FirstNSTok) {
110*12c85518Srobert if (!IsPrevInline && HasColoncolon && !IsPrevColoncolon) {
111*12c85518Srobert if (FirstNSTok->is(tok::l_paren)) {
112*12c85518Srobert FirstNSTok = Tok =
113*12c85518Srobert processTokens(FirstNSTok, tok::l_paren, tok::r_paren, AddToken);
114*12c85518Srobert continue;
115*12c85518Srobert }
116*12c85518Srobert if (FirstNSTok->isNot(tok::coloncolon)) {
117*12c85518Srobert NameFinished = true;
118*12c85518Srobert break;
119*12c85518Srobert }
120*12c85518Srobert }
121*12c85518Srobert name += FirstNSTok->TokenText;
122*12c85518Srobert IsPrevColoncolon = FirstNSTok->is(tok::coloncolon);
123*12c85518Srobert HasColoncolon = HasColoncolon || IsPrevColoncolon;
124*12c85518Srobert if (FirstNSTok->is(tok::kw_inline)) {
125e5dd7070Spatrick name += " ";
126*12c85518Srobert IsPrevInline = true;
127*12c85518Srobert }
128*12c85518Srobert }
129*12c85518Srobert FirstNSTok = Tok;
130e5dd7070Spatrick Tok = Tok->getNextNonComment();
131*12c85518Srobert const FormatToken *TokAfterAttr = skipAttribute(Tok);
132*12c85518Srobert if (TokAfterAttr != Tok)
133*12c85518Srobert FirstNSTok = Tok = TokAfterAttr;
134e5dd7070Spatrick }
135*12c85518Srobert if (!NameFinished && FirstNSTok && FirstNSTok->isNot(tok::l_brace))
136*12c85518Srobert name += FirstNSTok->TokenText;
137*12c85518Srobert if (FirstNSName.empty() || HasColoncolon)
138e5dd7070Spatrick return name;
139*12c85518Srobert return name.empty() ? FirstNSName : FirstNSName + " " + name;
140e5dd7070Spatrick }
141e5dd7070Spatrick
computeEndCommentText(StringRef NamespaceName,bool AddNewline,const FormatToken * NamespaceTok,unsigned SpacesToAdd)142e5dd7070Spatrick std::string computeEndCommentText(StringRef NamespaceName, bool AddNewline,
143a9ac8606Spatrick const FormatToken *NamespaceTok,
144a9ac8606Spatrick unsigned SpacesToAdd) {
145e5dd7070Spatrick std::string text = "//";
146a9ac8606Spatrick text.append(SpacesToAdd, ' ');
147e5dd7070Spatrick text += NamespaceTok->TokenText;
148e5dd7070Spatrick if (NamespaceTok->is(TT_NamespaceMacro))
149e5dd7070Spatrick text += "(";
150e5dd7070Spatrick else if (!NamespaceName.empty())
151e5dd7070Spatrick text += ' ';
152e5dd7070Spatrick text += NamespaceName;
153e5dd7070Spatrick if (NamespaceTok->is(TT_NamespaceMacro))
154e5dd7070Spatrick text += ")";
155e5dd7070Spatrick if (AddNewline)
156e5dd7070Spatrick text += '\n';
157e5dd7070Spatrick return text;
158e5dd7070Spatrick }
159e5dd7070Spatrick
hasEndComment(const FormatToken * RBraceTok)160e5dd7070Spatrick bool hasEndComment(const FormatToken *RBraceTok) {
161e5dd7070Spatrick return RBraceTok->Next && RBraceTok->Next->is(tok::comment);
162e5dd7070Spatrick }
163e5dd7070Spatrick
validEndComment(const FormatToken * RBraceTok,StringRef NamespaceName,const FormatToken * NamespaceTok)164e5dd7070Spatrick bool validEndComment(const FormatToken *RBraceTok, StringRef NamespaceName,
165e5dd7070Spatrick const FormatToken *NamespaceTok) {
166e5dd7070Spatrick assert(hasEndComment(RBraceTok));
167e5dd7070Spatrick const FormatToken *Comment = RBraceTok->Next;
168e5dd7070Spatrick
169e5dd7070Spatrick // Matches a valid namespace end comment.
170e5dd7070Spatrick // Valid namespace end comments don't need to be edited.
171e5dd7070Spatrick static const llvm::Regex NamespaceCommentPattern =
172e5dd7070Spatrick llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *"
173e5dd7070Spatrick "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$",
174e5dd7070Spatrick llvm::Regex::IgnoreCase);
175e5dd7070Spatrick static const llvm::Regex NamespaceMacroCommentPattern =
176e5dd7070Spatrick llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *"
177e5dd7070Spatrick "([a-zA-Z0-9_]+)\\(([a-zA-Z0-9:_]*)\\)\\.? *(\\*/)?$",
178e5dd7070Spatrick llvm::Regex::IgnoreCase);
179e5dd7070Spatrick
180e5dd7070Spatrick SmallVector<StringRef, 8> Groups;
181e5dd7070Spatrick if (NamespaceTok->is(TT_NamespaceMacro) &&
182e5dd7070Spatrick NamespaceMacroCommentPattern.match(Comment->TokenText, &Groups)) {
183e5dd7070Spatrick StringRef NamespaceTokenText = Groups.size() > 4 ? Groups[4] : "";
184e5dd7070Spatrick // The name of the macro must be used.
185e5dd7070Spatrick if (NamespaceTokenText != NamespaceTok->TokenText)
186e5dd7070Spatrick return false;
187e5dd7070Spatrick } else if (NamespaceTok->isNot(tok::kw_namespace) ||
188e5dd7070Spatrick !NamespaceCommentPattern.match(Comment->TokenText, &Groups)) {
189e5dd7070Spatrick // Comment does not match regex.
190e5dd7070Spatrick return false;
191e5dd7070Spatrick }
192e5dd7070Spatrick StringRef NamespaceNameInComment = Groups.size() > 5 ? Groups[5] : "";
193e5dd7070Spatrick // Anonymous namespace comments must not mention a namespace name.
194e5dd7070Spatrick if (NamespaceName.empty() && !NamespaceNameInComment.empty())
195e5dd7070Spatrick return false;
196e5dd7070Spatrick StringRef AnonymousInComment = Groups.size() > 3 ? Groups[3] : "";
197e5dd7070Spatrick // Named namespace comments must not mention anonymous namespace.
198e5dd7070Spatrick if (!NamespaceName.empty() && !AnonymousInComment.empty())
199e5dd7070Spatrick return false;
200ec727ea7Spatrick if (NamespaceNameInComment == NamespaceName)
201ec727ea7Spatrick return true;
202ec727ea7Spatrick
203ec727ea7Spatrick // Has namespace comment flowed onto the next line.
204ec727ea7Spatrick // } // namespace
205ec727ea7Spatrick // // verylongnamespacenamethatdidnotfitonthepreviouscommentline
206ec727ea7Spatrick if (!(Comment->Next && Comment->Next->is(TT_LineComment)))
207ec727ea7Spatrick return false;
208ec727ea7Spatrick
209ec727ea7Spatrick static const llvm::Regex CommentPattern = llvm::Regex(
210ec727ea7Spatrick "^/[/*] *( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$", llvm::Regex::IgnoreCase);
211ec727ea7Spatrick
212ec727ea7Spatrick // Pull out just the comment text.
213*12c85518Srobert if (!CommentPattern.match(Comment->Next->TokenText, &Groups))
214ec727ea7Spatrick return false;
215ec727ea7Spatrick NamespaceNameInComment = Groups.size() > 2 ? Groups[2] : "";
216ec727ea7Spatrick
217*12c85518Srobert return NamespaceNameInComment == NamespaceName;
218e5dd7070Spatrick }
219e5dd7070Spatrick
addEndComment(const FormatToken * RBraceTok,StringRef EndCommentText,const SourceManager & SourceMgr,tooling::Replacements * Fixes)220e5dd7070Spatrick void addEndComment(const FormatToken *RBraceTok, StringRef EndCommentText,
221e5dd7070Spatrick const SourceManager &SourceMgr,
222e5dd7070Spatrick tooling::Replacements *Fixes) {
223e5dd7070Spatrick auto EndLoc = RBraceTok->Tok.getEndLoc();
224e5dd7070Spatrick auto Range = CharSourceRange::getCharRange(EndLoc, EndLoc);
225e5dd7070Spatrick auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, EndCommentText));
226e5dd7070Spatrick if (Err) {
227e5dd7070Spatrick llvm::errs() << "Error while adding namespace end comment: "
228e5dd7070Spatrick << llvm::toString(std::move(Err)) << "\n";
229e5dd7070Spatrick }
230e5dd7070Spatrick }
231e5dd7070Spatrick
updateEndComment(const FormatToken * RBraceTok,StringRef EndCommentText,const SourceManager & SourceMgr,tooling::Replacements * Fixes)232e5dd7070Spatrick void updateEndComment(const FormatToken *RBraceTok, StringRef EndCommentText,
233e5dd7070Spatrick const SourceManager &SourceMgr,
234e5dd7070Spatrick tooling::Replacements *Fixes) {
235e5dd7070Spatrick assert(hasEndComment(RBraceTok));
236e5dd7070Spatrick const FormatToken *Comment = RBraceTok->Next;
237e5dd7070Spatrick auto Range = CharSourceRange::getCharRange(Comment->getStartOfNonWhitespace(),
238e5dd7070Spatrick Comment->Tok.getEndLoc());
239e5dd7070Spatrick auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, EndCommentText));
240e5dd7070Spatrick if (Err) {
241e5dd7070Spatrick llvm::errs() << "Error while updating namespace end comment: "
242e5dd7070Spatrick << llvm::toString(std::move(Err)) << "\n";
243e5dd7070Spatrick }
244e5dd7070Spatrick }
245e5dd7070Spatrick } // namespace
246e5dd7070Spatrick
247e5dd7070Spatrick const FormatToken *
getNamespaceToken(const AnnotatedLine * Line,const SmallVectorImpl<AnnotatedLine * > & AnnotatedLines)248e5dd7070Spatrick getNamespaceToken(const AnnotatedLine *Line,
249e5dd7070Spatrick const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
250e5dd7070Spatrick if (!Line->Affected || Line->InPPDirective || !Line->startsWith(tok::r_brace))
251e5dd7070Spatrick return nullptr;
252e5dd7070Spatrick size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex;
253e5dd7070Spatrick if (StartLineIndex == UnwrappedLine::kInvalidIndex)
254e5dd7070Spatrick return nullptr;
255e5dd7070Spatrick assert(StartLineIndex < AnnotatedLines.size());
256e5dd7070Spatrick const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First;
257e5dd7070Spatrick if (NamespaceTok->is(tok::l_brace)) {
258e5dd7070Spatrick // "namespace" keyword can be on the line preceding '{', e.g. in styles
259e5dd7070Spatrick // where BraceWrapping.AfterNamespace is true.
260*12c85518Srobert if (StartLineIndex > 0) {
261e5dd7070Spatrick NamespaceTok = AnnotatedLines[StartLineIndex - 1]->First;
262*12c85518Srobert if (AnnotatedLines[StartLineIndex - 1]->endsWith(tok::semi))
263*12c85518Srobert return nullptr;
264e5dd7070Spatrick }
265*12c85518Srobert }
266*12c85518Srobert
267e5dd7070Spatrick return NamespaceTok->getNamespaceToken();
268e5dd7070Spatrick }
269e5dd7070Spatrick
270e5dd7070Spatrick StringRef
getNamespaceTokenText(const AnnotatedLine * Line,const SmallVectorImpl<AnnotatedLine * > & AnnotatedLines)271e5dd7070Spatrick getNamespaceTokenText(const AnnotatedLine *Line,
272e5dd7070Spatrick const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
273e5dd7070Spatrick const FormatToken *NamespaceTok = getNamespaceToken(Line, AnnotatedLines);
274e5dd7070Spatrick return NamespaceTok ? NamespaceTok->TokenText : StringRef();
275e5dd7070Spatrick }
276e5dd7070Spatrick
NamespaceEndCommentsFixer(const Environment & Env,const FormatStyle & Style)277e5dd7070Spatrick NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env,
278e5dd7070Spatrick const FormatStyle &Style)
279e5dd7070Spatrick : TokenAnalyzer(Env, Style) {}
280e5dd7070Spatrick
analyze(TokenAnnotator & Annotator,SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,FormatTokenLexer & Tokens)281e5dd7070Spatrick std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::analyze(
282e5dd7070Spatrick TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
283e5dd7070Spatrick FormatTokenLexer &Tokens) {
284e5dd7070Spatrick const SourceManager &SourceMgr = Env.getSourceManager();
285e5dd7070Spatrick AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
286e5dd7070Spatrick tooling::Replacements Fixes;
287ec727ea7Spatrick
288ec727ea7Spatrick // Spin through the lines and ensure we have balanced braces.
289ec727ea7Spatrick int Braces = 0;
290*12c85518Srobert for (AnnotatedLine *Line : AnnotatedLines) {
291*12c85518Srobert FormatToken *Tok = Line->First;
292ec727ea7Spatrick while (Tok) {
293ec727ea7Spatrick Braces += Tok->is(tok::l_brace) ? 1 : Tok->is(tok::r_brace) ? -1 : 0;
294ec727ea7Spatrick Tok = Tok->Next;
295ec727ea7Spatrick }
296ec727ea7Spatrick }
297ec727ea7Spatrick // Don't attempt to comment unbalanced braces or this can
298ec727ea7Spatrick // lead to comments being placed on the closing brace which isn't
299ec727ea7Spatrick // the matching brace of the namespace. (occurs during incomplete editing).
300*12c85518Srobert if (Braces != 0)
301ec727ea7Spatrick return {Fixes, 0};
302ec727ea7Spatrick
303*12c85518Srobert std::string AllNamespaceNames;
304e5dd7070Spatrick size_t StartLineIndex = SIZE_MAX;
305e5dd7070Spatrick StringRef NamespaceTokenText;
306e5dd7070Spatrick unsigned int CompactedNamespacesCount = 0;
307e5dd7070Spatrick for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
308e5dd7070Spatrick const AnnotatedLine *EndLine = AnnotatedLines[I];
309e5dd7070Spatrick const FormatToken *NamespaceTok =
310e5dd7070Spatrick getNamespaceToken(EndLine, AnnotatedLines);
311e5dd7070Spatrick if (!NamespaceTok)
312e5dd7070Spatrick continue;
313e5dd7070Spatrick FormatToken *RBraceTok = EndLine->First;
314e5dd7070Spatrick if (RBraceTok->Finalized)
315e5dd7070Spatrick continue;
316e5dd7070Spatrick RBraceTok->Finalized = true;
317e5dd7070Spatrick const FormatToken *EndCommentPrevTok = RBraceTok;
318e5dd7070Spatrick // Namespaces often end with '};'. In that case, attach namespace end
319e5dd7070Spatrick // comments to the semicolon tokens.
320*12c85518Srobert if (RBraceTok->Next && RBraceTok->Next->is(tok::semi))
321e5dd7070Spatrick EndCommentPrevTok = RBraceTok->Next;
322e5dd7070Spatrick if (StartLineIndex == SIZE_MAX)
323e5dd7070Spatrick StartLineIndex = EndLine->MatchingOpeningBlockLineIndex;
324e5dd7070Spatrick std::string NamespaceName = computeName(NamespaceTok);
325e5dd7070Spatrick if (Style.CompactNamespaces) {
326e5dd7070Spatrick if (CompactedNamespacesCount == 0)
327e5dd7070Spatrick NamespaceTokenText = NamespaceTok->TokenText;
328e5dd7070Spatrick if ((I + 1 < E) &&
329e5dd7070Spatrick NamespaceTokenText ==
330e5dd7070Spatrick getNamespaceTokenText(AnnotatedLines[I + 1], AnnotatedLines) &&
331e5dd7070Spatrick StartLineIndex - CompactedNamespacesCount - 1 ==
332e5dd7070Spatrick AnnotatedLines[I + 1]->MatchingOpeningBlockLineIndex &&
333e5dd7070Spatrick !AnnotatedLines[I + 1]->First->Finalized) {
334e5dd7070Spatrick if (hasEndComment(EndCommentPrevTok)) {
335e5dd7070Spatrick // remove end comment, it will be merged in next one
336e5dd7070Spatrick updateEndComment(EndCommentPrevTok, std::string(), SourceMgr, &Fixes);
337e5dd7070Spatrick }
338*12c85518Srobert ++CompactedNamespacesCount;
339*12c85518Srobert if (!NamespaceName.empty())
340e5dd7070Spatrick AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames;
341e5dd7070Spatrick continue;
342e5dd7070Spatrick }
343e5dd7070Spatrick NamespaceName += AllNamespaceNames;
344e5dd7070Spatrick CompactedNamespacesCount = 0;
345e5dd7070Spatrick AllNamespaceNames = std::string();
346e5dd7070Spatrick }
347e5dd7070Spatrick // The next token in the token stream after the place where the end comment
348e5dd7070Spatrick // token must be. This is either the next token on the current line or the
349e5dd7070Spatrick // first token on the next line.
350e5dd7070Spatrick const FormatToken *EndCommentNextTok = EndCommentPrevTok->Next;
351e5dd7070Spatrick if (EndCommentNextTok && EndCommentNextTok->is(tok::comment))
352e5dd7070Spatrick EndCommentNextTok = EndCommentNextTok->Next;
353e5dd7070Spatrick if (!EndCommentNextTok && I + 1 < E)
354e5dd7070Spatrick EndCommentNextTok = AnnotatedLines[I + 1]->First;
355e5dd7070Spatrick bool AddNewline = EndCommentNextTok &&
356e5dd7070Spatrick EndCommentNextTok->NewlinesBefore == 0 &&
357e5dd7070Spatrick EndCommentNextTok->isNot(tok::eof);
358e5dd7070Spatrick const std::string EndCommentText =
359a9ac8606Spatrick computeEndCommentText(NamespaceName, AddNewline, NamespaceTok,
360a9ac8606Spatrick Style.SpacesInLineCommentPrefix.Minimum);
361e5dd7070Spatrick if (!hasEndComment(EndCommentPrevTok)) {
362a9ac8606Spatrick bool isShort = I - StartLineIndex <= Style.ShortNamespaceLines + 1;
363e5dd7070Spatrick if (!isShort)
364e5dd7070Spatrick addEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
365e5dd7070Spatrick } else if (!validEndComment(EndCommentPrevTok, NamespaceName,
366e5dd7070Spatrick NamespaceTok)) {
367e5dd7070Spatrick updateEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
368e5dd7070Spatrick }
369e5dd7070Spatrick StartLineIndex = SIZE_MAX;
370e5dd7070Spatrick }
371e5dd7070Spatrick return {Fixes, 0};
372e5dd7070Spatrick }
373e5dd7070Spatrick
374e5dd7070Spatrick } // namespace format
375e5dd7070Spatrick } // namespace clang
376