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 29b03877abSKrasimir Georgiev struct UsingDeclaration { 30b03877abSKrasimir Georgiev const AnnotatedLine *Line; 31b03877abSKrasimir Georgiev std::string Label; 32b03877abSKrasimir Georgiev 33b03877abSKrasimir Georgiev UsingDeclaration(const AnnotatedLine *Line, const std::string &Label) 34b03877abSKrasimir Georgiev : Line(Line), Label(Label) {} 35b03877abSKrasimir Georgiev 36b03877abSKrasimir Georgiev bool operator<(const UsingDeclaration &Other) const { 37*7fc53367SKrasimir Georgiev return StringRef(Label).compare_lower(Other.Label) < 0; 38b03877abSKrasimir Georgiev } 39b03877abSKrasimir Georgiev }; 40b03877abSKrasimir Georgiev 41b03877abSKrasimir Georgiev /// Computes the label of a using declaration starting at tthe using token 42b03877abSKrasimir Georgiev /// \p UsingTok. 43b03877abSKrasimir Georgiev /// If \p UsingTok doesn't begin a using declaration, returns the empty string. 44b03877abSKrasimir Georgiev /// Note that this detects specifically using declarations, as in: 45b03877abSKrasimir Georgiev /// using A::B::C; 46b03877abSKrasimir Georgiev /// and not type aliases, as in: 47b03877abSKrasimir Georgiev /// using A = B::C; 48b03877abSKrasimir Georgiev /// Type aliases are in general not safe to permute. 49b03877abSKrasimir Georgiev std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) { 50b03877abSKrasimir Georgiev assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token"); 51b03877abSKrasimir Georgiev std::string Label; 52b03877abSKrasimir Georgiev const FormatToken *Tok = UsingTok->Next; 53b03877abSKrasimir Georgiev if (Tok && Tok->is(tok::kw_typename)) { 54b03877abSKrasimir Georgiev Label.append("typename "); 55b03877abSKrasimir Georgiev Tok = Tok->Next; 56b03877abSKrasimir Georgiev } 57b03877abSKrasimir Georgiev if (Tok && Tok->is(tok::coloncolon)) { 58b03877abSKrasimir Georgiev Label.append("::"); 59b03877abSKrasimir Georgiev Tok = Tok->Next; 60b03877abSKrasimir Georgiev } 61b03877abSKrasimir Georgiev bool HasIdentifier = false; 62b03877abSKrasimir Georgiev while (Tok && Tok->is(tok::identifier)) { 63b03877abSKrasimir Georgiev HasIdentifier = true; 64b03877abSKrasimir Georgiev Label.append(Tok->TokenText.str()); 65b03877abSKrasimir Georgiev Tok = Tok->Next; 66b03877abSKrasimir Georgiev if (!Tok || Tok->isNot(tok::coloncolon)) 67b03877abSKrasimir Georgiev break; 68b03877abSKrasimir Georgiev Label.append("::"); 69b03877abSKrasimir Georgiev Tok = Tok->Next; 70b03877abSKrasimir Georgiev } 71b03877abSKrasimir Georgiev if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma)) 72b03877abSKrasimir Georgiev return Label; 73b03877abSKrasimir Georgiev return ""; 74b03877abSKrasimir Georgiev } 75b03877abSKrasimir Georgiev 76b03877abSKrasimir Georgiev void endUsingDeclarationBlock( 77b03877abSKrasimir Georgiev SmallVectorImpl<UsingDeclaration> *UsingDeclarations, 78b03877abSKrasimir Georgiev const SourceManager &SourceMgr, tooling::Replacements *Fixes) { 79b03877abSKrasimir Georgiev SmallVector<UsingDeclaration, 4> SortedUsingDeclarations( 80b03877abSKrasimir Georgiev UsingDeclarations->begin(), UsingDeclarations->end()); 81*7fc53367SKrasimir Georgiev std::stable_sort(SortedUsingDeclarations.begin(), 82*7fc53367SKrasimir Georgiev SortedUsingDeclarations.end()); 83b03877abSKrasimir Georgiev for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) { 84b03877abSKrasimir Georgiev if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line) 85b03877abSKrasimir Georgiev continue; 86b03877abSKrasimir Georgiev auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation(); 87b03877abSKrasimir Georgiev auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc(); 88b03877abSKrasimir Georgiev auto SortedBegin = 89b03877abSKrasimir Georgiev SortedUsingDeclarations[I].Line->First->Tok.getLocation(); 90b03877abSKrasimir Georgiev auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc(); 91b03877abSKrasimir Georgiev StringRef Text(SourceMgr.getCharacterData(SortedBegin), 92b03877abSKrasimir Georgiev SourceMgr.getCharacterData(SortedEnd) - 93b03877abSKrasimir Georgiev SourceMgr.getCharacterData(SortedBegin)); 94b03877abSKrasimir Georgiev DEBUG({ 95b03877abSKrasimir Georgiev StringRef OldText(SourceMgr.getCharacterData(Begin), 96b03877abSKrasimir Georgiev SourceMgr.getCharacterData(End) - 97b03877abSKrasimir Georgiev SourceMgr.getCharacterData(Begin)); 98b03877abSKrasimir Georgiev llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n"; 99b03877abSKrasimir Georgiev }); 100b03877abSKrasimir Georgiev auto Range = CharSourceRange::getCharRange(Begin, End); 101b03877abSKrasimir Georgiev auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text)); 102b03877abSKrasimir Georgiev if (Err) { 103b03877abSKrasimir Georgiev llvm::errs() << "Error while sorting using declarations: " 104b03877abSKrasimir Georgiev << llvm::toString(std::move(Err)) << "\n"; 105b03877abSKrasimir Georgiev } 106b03877abSKrasimir Georgiev } 107b03877abSKrasimir Georgiev UsingDeclarations->clear(); 108b03877abSKrasimir Georgiev } 109b03877abSKrasimir Georgiev 110b03877abSKrasimir Georgiev } // namespace 111b03877abSKrasimir Georgiev 112b03877abSKrasimir Georgiev UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env, 113b03877abSKrasimir Georgiev const FormatStyle &Style) 114b03877abSKrasimir Georgiev : TokenAnalyzer(Env, Style) {} 115b03877abSKrasimir Georgiev 116b03877abSKrasimir Georgiev tooling::Replacements UsingDeclarationsSorter::analyze( 117b03877abSKrasimir Georgiev TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, 118b03877abSKrasimir Georgiev FormatTokenLexer &Tokens) { 119b03877abSKrasimir Georgiev const SourceManager &SourceMgr = Env.getSourceManager(); 120b03877abSKrasimir Georgiev AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(), 121b03877abSKrasimir Georgiev AnnotatedLines.end()); 122b03877abSKrasimir Georgiev tooling::Replacements Fixes; 123b03877abSKrasimir Georgiev SmallVector<UsingDeclaration, 4> UsingDeclarations; 124b03877abSKrasimir Georgiev for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) { 125b03877abSKrasimir Georgiev if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective || 126b03877abSKrasimir Georgiev !AnnotatedLines[I]->startsWith(tok::kw_using) || 127b03877abSKrasimir Georgiev AnnotatedLines[I]->First->Finalized) { 128b03877abSKrasimir Georgiev endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); 129b03877abSKrasimir Georgiev continue; 130b03877abSKrasimir Georgiev } 131b03877abSKrasimir Georgiev if (AnnotatedLines[I]->First->NewlinesBefore > 1) 132b03877abSKrasimir Georgiev endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); 133b03877abSKrasimir Georgiev std::string Label = computeUsingDeclarationLabel(AnnotatedLines[I]->First); 134b03877abSKrasimir Georgiev if (Label.empty()) { 135b03877abSKrasimir Georgiev endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); 136b03877abSKrasimir Georgiev continue; 137b03877abSKrasimir Georgiev } 138b03877abSKrasimir Georgiev UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label)); 139b03877abSKrasimir Georgiev } 140b03877abSKrasimir Georgiev endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); 141b03877abSKrasimir Georgiev return Fixes; 142b03877abSKrasimir Georgiev } 143b03877abSKrasimir Georgiev 144b03877abSKrasimir Georgiev } // namespace format 145b03877abSKrasimir Georgiev } // namespace clang 146