10b57cec5SDimitry Andric //===--- NamespaceEndCommentsFixer.cpp --------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This file implements NamespaceEndCommentsFixer, a TokenAnalyzer that 110b57cec5SDimitry Andric /// fixes namespace end comments. 120b57cec5SDimitry Andric /// 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "NamespaceEndCommentsFixer.h" 1681ad6265SDimitry Andric #include "clang/Basic/TokenKinds.h" 170b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 180b57cec5SDimitry Andric #include "llvm/Support/Regex.h" 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #define DEBUG_TYPE "namespace-end-comments-fixer" 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric namespace clang { 230b57cec5SDimitry Andric namespace format { 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric namespace { 2681ad6265SDimitry Andric // Iterates all tokens starting from StartTok to EndTok and apply Fn to all 2781ad6265SDimitry Andric // tokens between them including StartTok and EndTok. Returns the token after 2881ad6265SDimitry Andric // EndTok. 2981ad6265SDimitry Andric const FormatToken * 3081ad6265SDimitry Andric processTokens(const FormatToken *Tok, tok::TokenKind StartTok, 3181ad6265SDimitry Andric tok::TokenKind EndTok, 3281ad6265SDimitry Andric llvm::function_ref<void(const FormatToken *)> Fn) { 3381ad6265SDimitry Andric if (!Tok || Tok->isNot(StartTok)) 3481ad6265SDimitry Andric return Tok; 3581ad6265SDimitry Andric int NestLevel = 0; 3681ad6265SDimitry Andric do { 3781ad6265SDimitry Andric if (Tok->is(StartTok)) 3881ad6265SDimitry Andric ++NestLevel; 3981ad6265SDimitry Andric else if (Tok->is(EndTok)) 4081ad6265SDimitry Andric --NestLevel; 4181ad6265SDimitry Andric if (Fn) 4281ad6265SDimitry Andric Fn(Tok); 4381ad6265SDimitry Andric Tok = Tok->getNextNonComment(); 4481ad6265SDimitry Andric } while (Tok && NestLevel > 0); 4581ad6265SDimitry Andric return Tok; 4681ad6265SDimitry Andric } 4781ad6265SDimitry Andric 4881ad6265SDimitry Andric const FormatToken *skipAttribute(const FormatToken *Tok) { 4981ad6265SDimitry Andric if (!Tok) 5081ad6265SDimitry Andric return nullptr; 51*5f757f3fSDimitry Andric if (Tok->isAttribute()) { 5281ad6265SDimitry Andric Tok = Tok->getNextNonComment(); 5381ad6265SDimitry Andric Tok = processTokens(Tok, tok::l_paren, tok::r_paren, nullptr); 5481ad6265SDimitry Andric } else if (Tok->is(tok::l_square)) { 5581ad6265SDimitry Andric Tok = processTokens(Tok, tok::l_square, tok::r_square, nullptr); 5681ad6265SDimitry Andric } 5781ad6265SDimitry Andric return Tok; 5881ad6265SDimitry Andric } 5981ad6265SDimitry Andric 600b57cec5SDimitry Andric // Computes the name of a namespace given the namespace token. 610b57cec5SDimitry Andric // Returns "" for anonymous namespace. 620b57cec5SDimitry Andric std::string computeName(const FormatToken *NamespaceTok) { 630b57cec5SDimitry Andric assert(NamespaceTok && 640b57cec5SDimitry Andric NamespaceTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro) && 650b57cec5SDimitry Andric "expecting a namespace token"); 6604eeddc0SDimitry Andric std::string name; 670b57cec5SDimitry Andric const FormatToken *Tok = NamespaceTok->getNextNonComment(); 680b57cec5SDimitry Andric if (NamespaceTok->is(TT_NamespaceMacro)) { 690b57cec5SDimitry Andric // Collects all the non-comment tokens between opening parenthesis 70a7dea167SDimitry Andric // and closing parenthesis or comma. 710b57cec5SDimitry Andric assert(Tok && Tok->is(tok::l_paren) && "expected an opening parenthesis"); 720b57cec5SDimitry Andric Tok = Tok->getNextNonComment(); 730b57cec5SDimitry Andric while (Tok && !Tok->isOneOf(tok::r_paren, tok::comma)) { 740b57cec5SDimitry Andric name += Tok->TokenText; 750b57cec5SDimitry Andric Tok = Tok->getNextNonComment(); 760b57cec5SDimitry Andric } 7781ad6265SDimitry Andric return name; 7881ad6265SDimitry Andric } 7981ad6265SDimitry Andric Tok = skipAttribute(Tok); 8081ad6265SDimitry Andric 8181ad6265SDimitry Andric std::string FirstNSName; 82a7dea167SDimitry Andric // For `namespace [[foo]] A::B::inline C {` or 83a7dea167SDimitry Andric // `namespace MACRO1 MACRO2 A::B::inline C {`, returns "A::B::inline C". 8481ad6265SDimitry Andric // Peek for the first '::' (or '{' or '(')) and then return all tokens from 8581ad6265SDimitry Andric // one token before that up until the '{'. A '(' might be a macro with 8681ad6265SDimitry Andric // arguments. 8781ad6265SDimitry Andric const FormatToken *FirstNSTok = nullptr; 8881ad6265SDimitry Andric while (Tok && !Tok->isOneOf(tok::l_brace, tok::coloncolon, tok::l_paren)) { 8981ad6265SDimitry Andric if (FirstNSTok) 9081ad6265SDimitry Andric FirstNSName += FirstNSTok->TokenText; 91a7dea167SDimitry Andric FirstNSTok = Tok; 92a7dea167SDimitry Andric Tok = Tok->getNextNonComment(); 93a7dea167SDimitry Andric } 94a7dea167SDimitry Andric 9581ad6265SDimitry Andric if (FirstNSTok) 96a7dea167SDimitry Andric Tok = FirstNSTok; 9781ad6265SDimitry Andric Tok = skipAttribute(Tok); 9881ad6265SDimitry Andric 9981ad6265SDimitry Andric FirstNSTok = nullptr; 10081ad6265SDimitry Andric // Add everything from '(' to ')'. 10181ad6265SDimitry Andric auto AddToken = [&name](const FormatToken *Tok) { name += Tok->TokenText; }; 10281ad6265SDimitry Andric bool IsPrevColoncolon = false; 10381ad6265SDimitry Andric bool HasColoncolon = false; 10481ad6265SDimitry Andric bool IsPrevInline = false; 10581ad6265SDimitry Andric bool NameFinished = false; 10681ad6265SDimitry Andric // If we found '::' in name, then it's the name. Otherwise, we can't tell 10781ad6265SDimitry Andric // which one is name. For example, `namespace A B {`. 10881ad6265SDimitry Andric while (Tok && Tok->isNot(tok::l_brace)) { 10981ad6265SDimitry Andric if (FirstNSTok) { 11081ad6265SDimitry Andric if (!IsPrevInline && HasColoncolon && !IsPrevColoncolon) { 11181ad6265SDimitry Andric if (FirstNSTok->is(tok::l_paren)) { 11281ad6265SDimitry Andric FirstNSTok = Tok = 11381ad6265SDimitry Andric processTokens(FirstNSTok, tok::l_paren, tok::r_paren, AddToken); 11481ad6265SDimitry Andric continue; 11581ad6265SDimitry Andric } 11681ad6265SDimitry Andric if (FirstNSTok->isNot(tok::coloncolon)) { 11781ad6265SDimitry Andric NameFinished = true; 11881ad6265SDimitry Andric break; 11981ad6265SDimitry Andric } 12081ad6265SDimitry Andric } 12181ad6265SDimitry Andric name += FirstNSTok->TokenText; 12281ad6265SDimitry Andric IsPrevColoncolon = FirstNSTok->is(tok::coloncolon); 12381ad6265SDimitry Andric HasColoncolon = HasColoncolon || IsPrevColoncolon; 12481ad6265SDimitry Andric if (FirstNSTok->is(tok::kw_inline)) { 125a7dea167SDimitry Andric name += " "; 12681ad6265SDimitry Andric IsPrevInline = true; 12781ad6265SDimitry Andric } 12881ad6265SDimitry Andric } 12981ad6265SDimitry Andric FirstNSTok = Tok; 1300b57cec5SDimitry Andric Tok = Tok->getNextNonComment(); 13181ad6265SDimitry Andric const FormatToken *TokAfterAttr = skipAttribute(Tok); 13281ad6265SDimitry Andric if (TokAfterAttr != Tok) 13381ad6265SDimitry Andric FirstNSTok = Tok = TokAfterAttr; 1340b57cec5SDimitry Andric } 13581ad6265SDimitry Andric if (!NameFinished && FirstNSTok && FirstNSTok->isNot(tok::l_brace)) 13681ad6265SDimitry Andric name += FirstNSTok->TokenText; 13781ad6265SDimitry Andric if (FirstNSName.empty() || HasColoncolon) 1380b57cec5SDimitry Andric return name; 13981ad6265SDimitry Andric return name.empty() ? FirstNSName : FirstNSName + " " + name; 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric std::string computeEndCommentText(StringRef NamespaceName, bool AddNewline, 143fe6060f1SDimitry Andric const FormatToken *NamespaceTok, 144fe6060f1SDimitry Andric unsigned SpacesToAdd) { 1450b57cec5SDimitry Andric std::string text = "//"; 146fe6060f1SDimitry Andric text.append(SpacesToAdd, ' '); 1470b57cec5SDimitry Andric text += NamespaceTok->TokenText; 1480b57cec5SDimitry Andric if (NamespaceTok->is(TT_NamespaceMacro)) 1490b57cec5SDimitry Andric text += "("; 1500b57cec5SDimitry Andric else if (!NamespaceName.empty()) 1510b57cec5SDimitry Andric text += ' '; 1520b57cec5SDimitry Andric text += NamespaceName; 1530b57cec5SDimitry Andric if (NamespaceTok->is(TT_NamespaceMacro)) 1540b57cec5SDimitry Andric text += ")"; 1550b57cec5SDimitry Andric if (AddNewline) 1560b57cec5SDimitry Andric text += '\n'; 1570b57cec5SDimitry Andric return text; 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric bool hasEndComment(const FormatToken *RBraceTok) { 1610b57cec5SDimitry Andric return RBraceTok->Next && RBraceTok->Next->is(tok::comment); 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric bool validEndComment(const FormatToken *RBraceTok, StringRef NamespaceName, 1650b57cec5SDimitry Andric const FormatToken *NamespaceTok) { 1660b57cec5SDimitry Andric assert(hasEndComment(RBraceTok)); 1670b57cec5SDimitry Andric const FormatToken *Comment = RBraceTok->Next; 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric // Matches a valid namespace end comment. 1700b57cec5SDimitry Andric // Valid namespace end comments don't need to be edited. 171480093f4SDimitry Andric static const llvm::Regex NamespaceCommentPattern = 172480093f4SDimitry Andric llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" 1730b57cec5SDimitry Andric "namespace( +([a-zA-Z0-9:_ ]+))?\\.? *(\\*/)?$", 1740b57cec5SDimitry Andric llvm::Regex::IgnoreCase); 175480093f4SDimitry Andric static const llvm::Regex NamespaceMacroCommentPattern = 176480093f4SDimitry Andric llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" 177*5f757f3fSDimitry Andric "([a-zA-Z0-9_]+)\\(([a-zA-Z0-9:_]*|\".+\")\\)\\.? *(\\*/)?$", 1780b57cec5SDimitry Andric llvm::Regex::IgnoreCase); 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric SmallVector<StringRef, 8> Groups; 1810b57cec5SDimitry Andric if (NamespaceTok->is(TT_NamespaceMacro) && 182480093f4SDimitry Andric NamespaceMacroCommentPattern.match(Comment->TokenText, &Groups)) { 1830b57cec5SDimitry Andric StringRef NamespaceTokenText = Groups.size() > 4 ? Groups[4] : ""; 1840b57cec5SDimitry Andric // The name of the macro must be used. 1850b57cec5SDimitry Andric if (NamespaceTokenText != NamespaceTok->TokenText) 1860b57cec5SDimitry Andric return false; 1870b57cec5SDimitry Andric } else if (NamespaceTok->isNot(tok::kw_namespace) || 188480093f4SDimitry Andric !NamespaceCommentPattern.match(Comment->TokenText, &Groups)) { 1890b57cec5SDimitry Andric // Comment does not match regex. 1900b57cec5SDimitry Andric return false; 1910b57cec5SDimitry Andric } 192*5f757f3fSDimitry Andric StringRef NamespaceNameInComment = Groups.size() > 5 ? Groups[5].rtrim() : ""; 1930b57cec5SDimitry Andric // Anonymous namespace comments must not mention a namespace name. 1940b57cec5SDimitry Andric if (NamespaceName.empty() && !NamespaceNameInComment.empty()) 1950b57cec5SDimitry Andric return false; 1960b57cec5SDimitry Andric StringRef AnonymousInComment = Groups.size() > 3 ? Groups[3] : ""; 1970b57cec5SDimitry Andric // Named namespace comments must not mention anonymous namespace. 1980b57cec5SDimitry Andric if (!NamespaceName.empty() && !AnonymousInComment.empty()) 1990b57cec5SDimitry Andric return false; 2005ffd83dbSDimitry Andric if (NamespaceNameInComment == NamespaceName) 2015ffd83dbSDimitry Andric return true; 2025ffd83dbSDimitry Andric 2035ffd83dbSDimitry Andric // Has namespace comment flowed onto the next line. 2045ffd83dbSDimitry Andric // } // namespace 2055ffd83dbSDimitry Andric // // verylongnamespacenamethatdidnotfitonthepreviouscommentline 2065ffd83dbSDimitry Andric if (!(Comment->Next && Comment->Next->is(TT_LineComment))) 2075ffd83dbSDimitry Andric return false; 2085ffd83dbSDimitry Andric 2095ffd83dbSDimitry Andric static const llvm::Regex CommentPattern = llvm::Regex( 2105ffd83dbSDimitry Andric "^/[/*] *( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$", llvm::Regex::IgnoreCase); 2115ffd83dbSDimitry Andric 2125ffd83dbSDimitry Andric // Pull out just the comment text. 21381ad6265SDimitry Andric if (!CommentPattern.match(Comment->Next->TokenText, &Groups)) 2145ffd83dbSDimitry Andric return false; 2155ffd83dbSDimitry Andric NamespaceNameInComment = Groups.size() > 2 ? Groups[2] : ""; 2165ffd83dbSDimitry Andric 21781ad6265SDimitry Andric return NamespaceNameInComment == NamespaceName; 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric void addEndComment(const FormatToken *RBraceTok, StringRef EndCommentText, 2210b57cec5SDimitry Andric const SourceManager &SourceMgr, 2220b57cec5SDimitry Andric tooling::Replacements *Fixes) { 2230b57cec5SDimitry Andric auto EndLoc = RBraceTok->Tok.getEndLoc(); 2240b57cec5SDimitry Andric auto Range = CharSourceRange::getCharRange(EndLoc, EndLoc); 2250b57cec5SDimitry Andric auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, EndCommentText)); 2260b57cec5SDimitry Andric if (Err) { 2270b57cec5SDimitry Andric llvm::errs() << "Error while adding namespace end comment: " 2280b57cec5SDimitry Andric << llvm::toString(std::move(Err)) << "\n"; 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric void updateEndComment(const FormatToken *RBraceTok, StringRef EndCommentText, 2330b57cec5SDimitry Andric const SourceManager &SourceMgr, 2340b57cec5SDimitry Andric tooling::Replacements *Fixes) { 2350b57cec5SDimitry Andric assert(hasEndComment(RBraceTok)); 2360b57cec5SDimitry Andric const FormatToken *Comment = RBraceTok->Next; 2370b57cec5SDimitry Andric auto Range = CharSourceRange::getCharRange(Comment->getStartOfNonWhitespace(), 2380b57cec5SDimitry Andric Comment->Tok.getEndLoc()); 2390b57cec5SDimitry Andric auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, EndCommentText)); 2400b57cec5SDimitry Andric if (Err) { 2410b57cec5SDimitry Andric llvm::errs() << "Error while updating namespace end comment: " 2420b57cec5SDimitry Andric << llvm::toString(std::move(Err)) << "\n"; 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric } // namespace 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric const FormatToken * 2480b57cec5SDimitry Andric getNamespaceToken(const AnnotatedLine *Line, 2490b57cec5SDimitry Andric const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) { 2500b57cec5SDimitry Andric if (!Line->Affected || Line->InPPDirective || !Line->startsWith(tok::r_brace)) 2510b57cec5SDimitry Andric return nullptr; 2520b57cec5SDimitry Andric size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex; 2530b57cec5SDimitry Andric if (StartLineIndex == UnwrappedLine::kInvalidIndex) 2540b57cec5SDimitry Andric return nullptr; 2550b57cec5SDimitry Andric assert(StartLineIndex < AnnotatedLines.size()); 2560b57cec5SDimitry Andric const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First; 2570b57cec5SDimitry Andric if (NamespaceTok->is(tok::l_brace)) { 2580b57cec5SDimitry Andric // "namespace" keyword can be on the line preceding '{', e.g. in styles 2590b57cec5SDimitry Andric // where BraceWrapping.AfterNamespace is true. 2600eae32dcSDimitry Andric if (StartLineIndex > 0) { 2610b57cec5SDimitry Andric NamespaceTok = AnnotatedLines[StartLineIndex - 1]->First; 2620eae32dcSDimitry Andric if (AnnotatedLines[StartLineIndex - 1]->endsWith(tok::semi)) 2630eae32dcSDimitry Andric return nullptr; 2640b57cec5SDimitry Andric } 2650eae32dcSDimitry Andric } 2660eae32dcSDimitry Andric 2670b57cec5SDimitry Andric return NamespaceTok->getNamespaceToken(); 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric StringRef 2710b57cec5SDimitry Andric getNamespaceTokenText(const AnnotatedLine *Line, 2720b57cec5SDimitry Andric const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) { 2730b57cec5SDimitry Andric const FormatToken *NamespaceTok = getNamespaceToken(Line, AnnotatedLines); 2740b57cec5SDimitry Andric return NamespaceTok ? NamespaceTok->TokenText : StringRef(); 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env, 2780b57cec5SDimitry Andric const FormatStyle &Style) 2790b57cec5SDimitry Andric : TokenAnalyzer(Env, Style) {} 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::analyze( 2820b57cec5SDimitry Andric TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, 2830b57cec5SDimitry Andric FormatTokenLexer &Tokens) { 2840b57cec5SDimitry Andric const SourceManager &SourceMgr = Env.getSourceManager(); 2850b57cec5SDimitry Andric AffectedRangeMgr.computeAffectedLines(AnnotatedLines); 2860b57cec5SDimitry Andric tooling::Replacements Fixes; 2875ffd83dbSDimitry Andric 2885ffd83dbSDimitry Andric // Spin through the lines and ensure we have balanced braces. 2895ffd83dbSDimitry Andric int Braces = 0; 2901fd87a68SDimitry Andric for (AnnotatedLine *Line : AnnotatedLines) { 2911fd87a68SDimitry Andric FormatToken *Tok = Line->First; 2925ffd83dbSDimitry Andric while (Tok) { 2935ffd83dbSDimitry Andric Braces += Tok->is(tok::l_brace) ? 1 : Tok->is(tok::r_brace) ? -1 : 0; 2945ffd83dbSDimitry Andric Tok = Tok->Next; 2955ffd83dbSDimitry Andric } 2965ffd83dbSDimitry Andric } 2975ffd83dbSDimitry Andric // Don't attempt to comment unbalanced braces or this can 2985ffd83dbSDimitry Andric // lead to comments being placed on the closing brace which isn't 2995ffd83dbSDimitry Andric // the matching brace of the namespace. (occurs during incomplete editing). 30081ad6265SDimitry Andric if (Braces != 0) 3015ffd83dbSDimitry Andric return {Fixes, 0}; 3025ffd83dbSDimitry Andric 30304eeddc0SDimitry Andric std::string AllNamespaceNames; 3040b57cec5SDimitry Andric size_t StartLineIndex = SIZE_MAX; 3050b57cec5SDimitry Andric StringRef NamespaceTokenText; 3060b57cec5SDimitry Andric unsigned int CompactedNamespacesCount = 0; 3070b57cec5SDimitry Andric for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) { 3080b57cec5SDimitry Andric const AnnotatedLine *EndLine = AnnotatedLines[I]; 3090b57cec5SDimitry Andric const FormatToken *NamespaceTok = 3100b57cec5SDimitry Andric getNamespaceToken(EndLine, AnnotatedLines); 3110b57cec5SDimitry Andric if (!NamespaceTok) 3120b57cec5SDimitry Andric continue; 3130b57cec5SDimitry Andric FormatToken *RBraceTok = EndLine->First; 3140b57cec5SDimitry Andric if (RBraceTok->Finalized) 3150b57cec5SDimitry Andric continue; 3160b57cec5SDimitry Andric RBraceTok->Finalized = true; 3170b57cec5SDimitry Andric const FormatToken *EndCommentPrevTok = RBraceTok; 3180b57cec5SDimitry Andric // Namespaces often end with '};'. In that case, attach namespace end 3190b57cec5SDimitry Andric // comments to the semicolon tokens. 32081ad6265SDimitry Andric if (RBraceTok->Next && RBraceTok->Next->is(tok::semi)) 3210b57cec5SDimitry Andric EndCommentPrevTok = RBraceTok->Next; 3220b57cec5SDimitry Andric if (StartLineIndex == SIZE_MAX) 3230b57cec5SDimitry Andric StartLineIndex = EndLine->MatchingOpeningBlockLineIndex; 3240b57cec5SDimitry Andric std::string NamespaceName = computeName(NamespaceTok); 3250b57cec5SDimitry Andric if (Style.CompactNamespaces) { 3260b57cec5SDimitry Andric if (CompactedNamespacesCount == 0) 3270b57cec5SDimitry Andric NamespaceTokenText = NamespaceTok->TokenText; 3280b57cec5SDimitry Andric if ((I + 1 < E) && 3290b57cec5SDimitry Andric NamespaceTokenText == 3300b57cec5SDimitry Andric getNamespaceTokenText(AnnotatedLines[I + 1], AnnotatedLines) && 3310b57cec5SDimitry Andric StartLineIndex - CompactedNamespacesCount - 1 == 3320b57cec5SDimitry Andric AnnotatedLines[I + 1]->MatchingOpeningBlockLineIndex && 3330b57cec5SDimitry Andric !AnnotatedLines[I + 1]->First->Finalized) { 3340b57cec5SDimitry Andric if (hasEndComment(EndCommentPrevTok)) { 3350b57cec5SDimitry Andric // remove end comment, it will be merged in next one 3360b57cec5SDimitry Andric updateEndComment(EndCommentPrevTok, std::string(), SourceMgr, &Fixes); 3370b57cec5SDimitry Andric } 33804eeddc0SDimitry Andric ++CompactedNamespacesCount; 33904eeddc0SDimitry Andric if (!NamespaceName.empty()) 3400b57cec5SDimitry Andric AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames; 3410b57cec5SDimitry Andric continue; 3420b57cec5SDimitry Andric } 3430b57cec5SDimitry Andric NamespaceName += AllNamespaceNames; 3440b57cec5SDimitry Andric CompactedNamespacesCount = 0; 3450b57cec5SDimitry Andric AllNamespaceNames = std::string(); 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric // The next token in the token stream after the place where the end comment 3480b57cec5SDimitry Andric // token must be. This is either the next token on the current line or the 3490b57cec5SDimitry Andric // first token on the next line. 3500b57cec5SDimitry Andric const FormatToken *EndCommentNextTok = EndCommentPrevTok->Next; 3510b57cec5SDimitry Andric if (EndCommentNextTok && EndCommentNextTok->is(tok::comment)) 3520b57cec5SDimitry Andric EndCommentNextTok = EndCommentNextTok->Next; 3530b57cec5SDimitry Andric if (!EndCommentNextTok && I + 1 < E) 3540b57cec5SDimitry Andric EndCommentNextTok = AnnotatedLines[I + 1]->First; 3550b57cec5SDimitry Andric bool AddNewline = EndCommentNextTok && 3560b57cec5SDimitry Andric EndCommentNextTok->NewlinesBefore == 0 && 3570b57cec5SDimitry Andric EndCommentNextTok->isNot(tok::eof); 3580b57cec5SDimitry Andric const std::string EndCommentText = 359fe6060f1SDimitry Andric computeEndCommentText(NamespaceName, AddNewline, NamespaceTok, 360fe6060f1SDimitry Andric Style.SpacesInLineCommentPrefix.Minimum); 3610b57cec5SDimitry Andric if (!hasEndComment(EndCommentPrevTok)) { 362*5f757f3fSDimitry Andric unsigned LineCount = 0; 363*5f757f3fSDimitry Andric for (auto J = StartLineIndex + 1; J < I; ++J) 364*5f757f3fSDimitry Andric LineCount += AnnotatedLines[J]->size(); 365*5f757f3fSDimitry Andric if (LineCount > Style.ShortNamespaceLines) { 36606c3fb27SDimitry Andric addEndComment(EndCommentPrevTok, 36706c3fb27SDimitry Andric std::string(Style.SpacesBeforeTrailingComments, ' ') + 36806c3fb27SDimitry Andric EndCommentText, 36906c3fb27SDimitry Andric SourceMgr, &Fixes); 37006c3fb27SDimitry Andric } 3710b57cec5SDimitry Andric } else if (!validEndComment(EndCommentPrevTok, NamespaceName, 3720b57cec5SDimitry Andric NamespaceTok)) { 3730b57cec5SDimitry Andric updateEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes); 3740b57cec5SDimitry Andric } 3750b57cec5SDimitry Andric StartLineIndex = SIZE_MAX; 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric return {Fixes, 0}; 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric } // namespace format 3810b57cec5SDimitry Andric } // namespace clang 382