1b03877abSKrasimir Georgiev //===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===// 2b03877abSKrasimir Georgiev // 3b03877abSKrasimir Georgiev // The LLVM Compiler Infrastructure 4b03877abSKrasimir Georgiev // 5b03877abSKrasimir Georgiev // This file is distributed under the University of Illinois Open Source 6b03877abSKrasimir Georgiev // License. See LICENSE.TXT for details. 7b03877abSKrasimir Georgiev // 8b03877abSKrasimir Georgiev //===----------------------------------------------------------------------===// 9b03877abSKrasimir Georgiev /// 10b03877abSKrasimir Georgiev /// \file 11b03877abSKrasimir Georgiev /// \brief This file implements UsingDeclarationsSorter, a TokenAnalyzer that 12b03877abSKrasimir Georgiev /// sorts consecutive using declarations. 13b03877abSKrasimir Georgiev /// 14b03877abSKrasimir Georgiev //===----------------------------------------------------------------------===// 15b03877abSKrasimir Georgiev 16b03877abSKrasimir Georgiev #include "UsingDeclarationsSorter.h" 17b03877abSKrasimir Georgiev #include "llvm/Support/Debug.h" 18b03877abSKrasimir Georgiev #include "llvm/Support/Regex.h" 19b03877abSKrasimir Georgiev 20b03877abSKrasimir Georgiev #include <algorithm> 21b03877abSKrasimir Georgiev 22b03877abSKrasimir Georgiev #define DEBUG_TYPE "using-declarations-sorter" 23b03877abSKrasimir Georgiev 24b03877abSKrasimir Georgiev namespace clang { 25b03877abSKrasimir Georgiev namespace format { 26b03877abSKrasimir Georgiev 27b03877abSKrasimir Georgiev namespace { 28b03877abSKrasimir Georgiev 29818da9bbSKrasimir Georgiev // The order of using declaration is defined as follows: 30818da9bbSKrasimir Georgiev // Split the strings by "::" and discard any initial empty strings. The last 31818da9bbSKrasimir Georgiev // element of each list is a non-namespace name; all others are namespace 32818da9bbSKrasimir Georgiev // names. Sort the lists of names lexicographically, where the sort order of 33818da9bbSKrasimir Georgiev // individual names is that all non-namespace names come before all namespace 34818da9bbSKrasimir Georgiev // names, and within those groups, names are in case-insensitive lexicographic 35818da9bbSKrasimir Georgiev // order. 36818da9bbSKrasimir Georgiev int compareLabels(StringRef A, StringRef B) { 37818da9bbSKrasimir Georgiev SmallVector<StringRef, 2> NamesA; 38818da9bbSKrasimir Georgiev A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false); 39818da9bbSKrasimir Georgiev SmallVector<StringRef, 2> NamesB; 40818da9bbSKrasimir Georgiev B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false); 41818da9bbSKrasimir Georgiev size_t SizeA = NamesA.size(); 42818da9bbSKrasimir Georgiev size_t SizeB = NamesB.size(); 43818da9bbSKrasimir Georgiev for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) { 44818da9bbSKrasimir Georgiev if (I + 1 == SizeA) { 45818da9bbSKrasimir Georgiev // I is the last index of NamesA and NamesA[I] is a non-namespace name. 46818da9bbSKrasimir Georgiev 47818da9bbSKrasimir Georgiev // Non-namespace names come before all namespace names. 48818da9bbSKrasimir Georgiev if (SizeB > SizeA) 49818da9bbSKrasimir Georgiev return -1; 50818da9bbSKrasimir Georgiev 51818da9bbSKrasimir Georgiev // Two names within a group compare case-insensitively. 52818da9bbSKrasimir Georgiev return NamesA[I].compare_lower(NamesB[I]); 53818da9bbSKrasimir Georgiev } 54818da9bbSKrasimir Georgiev 55818da9bbSKrasimir Georgiev // I is the last index of NamesB and NamesB[I] is a non-namespace name. 56818da9bbSKrasimir Georgiev // Non-namespace names come before all namespace names. 57818da9bbSKrasimir Georgiev if (I + 1 == SizeB) 58818da9bbSKrasimir Georgiev return 1; 59818da9bbSKrasimir Georgiev 60818da9bbSKrasimir Georgiev // Two namespaces names within a group compare case-insensitively. 61818da9bbSKrasimir Georgiev int C = NamesA[I].compare_lower(NamesB[I]); 62818da9bbSKrasimir Georgiev if (C != 0) 63818da9bbSKrasimir Georgiev return C; 64818da9bbSKrasimir Georgiev } 65818da9bbSKrasimir Georgiev return 0; 66818da9bbSKrasimir Georgiev } 67818da9bbSKrasimir Georgiev 68b03877abSKrasimir Georgiev struct UsingDeclaration { 69b03877abSKrasimir Georgiev const AnnotatedLine *Line; 70b03877abSKrasimir Georgiev std::string Label; 71b03877abSKrasimir Georgiev 72b03877abSKrasimir Georgiev UsingDeclaration(const AnnotatedLine *Line, const std::string &Label) 73b03877abSKrasimir Georgiev : Line(Line), Label(Label) {} 74b03877abSKrasimir Georgiev 75b03877abSKrasimir Georgiev bool operator<(const UsingDeclaration &Other) const { 76818da9bbSKrasimir Georgiev return compareLabels(Label, Other.Label) < 0; 77b03877abSKrasimir Georgiev } 78b03877abSKrasimir Georgiev }; 79b03877abSKrasimir Georgiev 80b03877abSKrasimir Georgiev /// Computes the label of a using declaration starting at tthe using token 81b03877abSKrasimir Georgiev /// \p UsingTok. 82b03877abSKrasimir Georgiev /// If \p UsingTok doesn't begin a using declaration, returns the empty string. 83b03877abSKrasimir Georgiev /// Note that this detects specifically using declarations, as in: 84b03877abSKrasimir Georgiev /// using A::B::C; 85b03877abSKrasimir Georgiev /// and not type aliases, as in: 86b03877abSKrasimir Georgiev /// using A = B::C; 87b03877abSKrasimir Georgiev /// Type aliases are in general not safe to permute. 88b03877abSKrasimir Georgiev std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) { 89b03877abSKrasimir Georgiev assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token"); 90b03877abSKrasimir Georgiev std::string Label; 91b03877abSKrasimir Georgiev const FormatToken *Tok = UsingTok->Next; 92b03877abSKrasimir Georgiev if (Tok && Tok->is(tok::kw_typename)) { 93b03877abSKrasimir Georgiev Label.append("typename "); 94b03877abSKrasimir Georgiev Tok = Tok->Next; 95b03877abSKrasimir Georgiev } 96b03877abSKrasimir Georgiev if (Tok && Tok->is(tok::coloncolon)) { 97b03877abSKrasimir Georgiev Label.append("::"); 98b03877abSKrasimir Georgiev Tok = Tok->Next; 99b03877abSKrasimir Georgiev } 100b03877abSKrasimir Georgiev bool HasIdentifier = false; 101b03877abSKrasimir Georgiev while (Tok && Tok->is(tok::identifier)) { 102b03877abSKrasimir Georgiev HasIdentifier = true; 103b03877abSKrasimir Georgiev Label.append(Tok->TokenText.str()); 104b03877abSKrasimir Georgiev Tok = Tok->Next; 105b03877abSKrasimir Georgiev if (!Tok || Tok->isNot(tok::coloncolon)) 106b03877abSKrasimir Georgiev break; 107b03877abSKrasimir Georgiev Label.append("::"); 108b03877abSKrasimir Georgiev Tok = Tok->Next; 109b03877abSKrasimir Georgiev } 110b03877abSKrasimir Georgiev if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma)) 111b03877abSKrasimir Georgiev return Label; 112b03877abSKrasimir Georgiev return ""; 113b03877abSKrasimir Georgiev } 114b03877abSKrasimir Georgiev 115b03877abSKrasimir Georgiev void endUsingDeclarationBlock( 116b03877abSKrasimir Georgiev SmallVectorImpl<UsingDeclaration> *UsingDeclarations, 117b03877abSKrasimir Georgiev const SourceManager &SourceMgr, tooling::Replacements *Fixes) { 1189da65aa8SKrasimir Georgiev bool BlockAffected = false; 1199da65aa8SKrasimir Georgiev for (const UsingDeclaration &Declaration : *UsingDeclarations) { 1209da65aa8SKrasimir Georgiev if (Declaration.Line->Affected) { 1219da65aa8SKrasimir Georgiev BlockAffected = true; 1229da65aa8SKrasimir Georgiev break; 1239da65aa8SKrasimir Georgiev } 1249da65aa8SKrasimir Georgiev } 1259da65aa8SKrasimir Georgiev if (!BlockAffected) { 1269da65aa8SKrasimir Georgiev UsingDeclarations->clear(); 1279da65aa8SKrasimir Georgiev return; 1289da65aa8SKrasimir Georgiev } 129b03877abSKrasimir Georgiev SmallVector<UsingDeclaration, 4> SortedUsingDeclarations( 130b03877abSKrasimir Georgiev UsingDeclarations->begin(), UsingDeclarations->end()); 1317fc53367SKrasimir Georgiev std::stable_sort(SortedUsingDeclarations.begin(), 1327fc53367SKrasimir Georgiev SortedUsingDeclarations.end()); 133f09c4285SKrasimir Georgiev SortedUsingDeclarations.erase( 134f09c4285SKrasimir Georgiev std::unique(SortedUsingDeclarations.begin(), 135f09c4285SKrasimir Georgiev SortedUsingDeclarations.end(), 136f09c4285SKrasimir Georgiev [](const UsingDeclaration &a, const UsingDeclaration &b) { 137f09c4285SKrasimir Georgiev return a.Label == b.Label; 138f09c4285SKrasimir Georgiev }), 139f09c4285SKrasimir Georgiev SortedUsingDeclarations.end()); 140b03877abSKrasimir Georgiev for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) { 141f09c4285SKrasimir Georgiev if (I >= SortedUsingDeclarations.size()) { 142f09c4285SKrasimir Georgiev // This using declaration has been deduplicated, delete it. 143f09c4285SKrasimir Georgiev auto Begin = 144f09c4285SKrasimir Georgiev (*UsingDeclarations)[I].Line->First->WhitespaceRange.getBegin(); 145f09c4285SKrasimir Georgiev auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc(); 146f09c4285SKrasimir Georgiev auto Range = CharSourceRange::getCharRange(Begin, End); 147f09c4285SKrasimir Georgiev auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, "")); 148f09c4285SKrasimir Georgiev if (Err) { 149f09c4285SKrasimir Georgiev llvm::errs() << "Error while sorting using declarations: " 150f09c4285SKrasimir Georgiev << llvm::toString(std::move(Err)) << "\n"; 151f09c4285SKrasimir Georgiev } 152f09c4285SKrasimir Georgiev continue; 153f09c4285SKrasimir Georgiev } 154b03877abSKrasimir Georgiev if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line) 155b03877abSKrasimir Georgiev continue; 156b03877abSKrasimir Georgiev auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation(); 157b03877abSKrasimir Georgiev auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc(); 158b03877abSKrasimir Georgiev auto SortedBegin = 159b03877abSKrasimir Georgiev SortedUsingDeclarations[I].Line->First->Tok.getLocation(); 160b03877abSKrasimir Georgiev auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc(); 161b03877abSKrasimir Georgiev StringRef Text(SourceMgr.getCharacterData(SortedBegin), 162b03877abSKrasimir Georgiev SourceMgr.getCharacterData(SortedEnd) - 163b03877abSKrasimir Georgiev SourceMgr.getCharacterData(SortedBegin)); 164b03877abSKrasimir Georgiev DEBUG({ 165b03877abSKrasimir Georgiev StringRef OldText(SourceMgr.getCharacterData(Begin), 166b03877abSKrasimir Georgiev SourceMgr.getCharacterData(End) - 167b03877abSKrasimir Georgiev SourceMgr.getCharacterData(Begin)); 168b03877abSKrasimir Georgiev llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n"; 169b03877abSKrasimir Georgiev }); 170b03877abSKrasimir Georgiev auto Range = CharSourceRange::getCharRange(Begin, End); 171b03877abSKrasimir Georgiev auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text)); 172b03877abSKrasimir Georgiev if (Err) { 173b03877abSKrasimir Georgiev llvm::errs() << "Error while sorting using declarations: " 174b03877abSKrasimir Georgiev << llvm::toString(std::move(Err)) << "\n"; 175b03877abSKrasimir Georgiev } 176b03877abSKrasimir Georgiev } 177b03877abSKrasimir Georgiev UsingDeclarations->clear(); 178b03877abSKrasimir Georgiev } 179b03877abSKrasimir Georgiev 180b03877abSKrasimir Georgiev } // namespace 181b03877abSKrasimir Georgiev 182b03877abSKrasimir Georgiev UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env, 183b03877abSKrasimir Georgiev const FormatStyle &Style) 184b03877abSKrasimir Georgiev : TokenAnalyzer(Env, Style) {} 185b03877abSKrasimir Georgiev 1869ad83fe7SKrasimir Georgiev std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze( 187b03877abSKrasimir Georgiev TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, 188b03877abSKrasimir Georgiev FormatTokenLexer &Tokens) { 189b03877abSKrasimir Georgiev const SourceManager &SourceMgr = Env.getSourceManager(); 190*0dddcf78SManuel Klimek AffectedRangeMgr.computeAffectedLines(AnnotatedLines); 191b03877abSKrasimir Georgiev tooling::Replacements Fixes; 192b03877abSKrasimir Georgiev SmallVector<UsingDeclaration, 4> UsingDeclarations; 193b03877abSKrasimir Georgiev for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) { 194028d815eSDaniel Jasper const auto *FirstTok = AnnotatedLines[I]->First; 1959da65aa8SKrasimir Georgiev if (AnnotatedLines[I]->InPPDirective || 196028d815eSDaniel Jasper !AnnotatedLines[I]->startsWith(tok::kw_using) || FirstTok->Finalized) { 197b03877abSKrasimir Georgiev endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); 198b03877abSKrasimir Georgiev continue; 199b03877abSKrasimir Georgiev } 200028d815eSDaniel Jasper if (FirstTok->NewlinesBefore > 1) 201b03877abSKrasimir Georgiev endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); 202028d815eSDaniel Jasper const auto *UsingTok = 203028d815eSDaniel Jasper FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok; 204028d815eSDaniel Jasper std::string Label = computeUsingDeclarationLabel(UsingTok); 205b03877abSKrasimir Georgiev if (Label.empty()) { 206b03877abSKrasimir Georgiev endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); 207b03877abSKrasimir Georgiev continue; 208b03877abSKrasimir Georgiev } 209b03877abSKrasimir Georgiev UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label)); 210b03877abSKrasimir Georgiev } 211b03877abSKrasimir Georgiev endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); 2129ad83fe7SKrasimir Georgiev return {Fixes, 0}; 213b03877abSKrasimir Georgiev } 214b03877abSKrasimir Georgiev 215b03877abSKrasimir Georgiev } // namespace format 216b03877abSKrasimir Georgiev } // namespace clang 217