UsingDeclarationsSorter.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. //===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. ///
  10. /// \file
  11. /// \brief This file implements UsingDeclarationsSorter, a TokenAnalyzer that
  12. /// sorts consecutive using declarations.
  13. ///
  14. //===----------------------------------------------------------------------===//
  15. #include "UsingDeclarationsSorter.h"
  16. #include "llvm/Support/Debug.h"
  17. #include "llvm/Support/Regex.h"
  18. #include <algorithm>
  19. #define DEBUG_TYPE "using-declarations-sorter"
  20. namespace clang {
  21. namespace format {
  22. namespace {
  23. struct UsingDeclaration {
  24. const AnnotatedLine *Line;
  25. std::string Label;
  26. UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
  27. : Line(Line), Label(Label) {}
  28. // Compares lexicographically with the exception that '_' is just before 'A'.
  29. bool operator<(const UsingDeclaration &Other) const {
  30. size_t Size = Label.size();
  31. size_t OtherSize = Other.Label.size();
  32. for (size_t I = 0, E = std::min(Size, OtherSize); I < E; ++I) {
  33. char Rank = rank(Label[I]);
  34. char OtherRank = rank(Other.Label[I]);
  35. if (Rank != OtherRank)
  36. return Rank < OtherRank;
  37. }
  38. return Size < OtherSize;
  39. }
  40. // Returns the position of c in a lexicographic ordering with the exception
  41. // that '_' is just before 'A'.
  42. static char rank(char c) {
  43. if (c == '_')
  44. return 'A';
  45. if ('A' <= c && c < '_')
  46. return c + 1;
  47. return c;
  48. }
  49. };
  50. /// Computes the label of a using declaration starting at tthe using token
  51. /// \p UsingTok.
  52. /// If \p UsingTok doesn't begin a using declaration, returns the empty string.
  53. /// Note that this detects specifically using declarations, as in:
  54. /// using A::B::C;
  55. /// and not type aliases, as in:
  56. /// using A = B::C;
  57. /// Type aliases are in general not safe to permute.
  58. std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
  59. assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token");
  60. std::string Label;
  61. const FormatToken *Tok = UsingTok->Next;
  62. if (Tok && Tok->is(tok::kw_typename)) {
  63. Label.append("typename ");
  64. Tok = Tok->Next;
  65. }
  66. if (Tok && Tok->is(tok::coloncolon)) {
  67. Label.append("::");
  68. Tok = Tok->Next;
  69. }
  70. bool HasIdentifier = false;
  71. while (Tok && Tok->is(tok::identifier)) {
  72. HasIdentifier = true;
  73. Label.append(Tok->TokenText.str());
  74. Tok = Tok->Next;
  75. if (!Tok || Tok->isNot(tok::coloncolon))
  76. break;
  77. Label.append("::");
  78. Tok = Tok->Next;
  79. }
  80. if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
  81. return Label;
  82. return "";
  83. }
  84. void endUsingDeclarationBlock(
  85. SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
  86. const SourceManager &SourceMgr, tooling::Replacements *Fixes) {
  87. bool BlockAffected = false;
  88. for (const UsingDeclaration &Declaration : *UsingDeclarations) {
  89. if (Declaration.Line->Affected) {
  90. BlockAffected = true;
  91. break;
  92. }
  93. }
  94. if (!BlockAffected) {
  95. UsingDeclarations->clear();
  96. return;
  97. }
  98. SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
  99. UsingDeclarations->begin(), UsingDeclarations->end());
  100. std::stable_sort(SortedUsingDeclarations.begin(),
  101. SortedUsingDeclarations.end());
  102. for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
  103. if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
  104. continue;
  105. auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
  106. auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
  107. auto SortedBegin =
  108. SortedUsingDeclarations[I].Line->First->Tok.getLocation();
  109. auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
  110. StringRef Text(SourceMgr.getCharacterData(SortedBegin),
  111. SourceMgr.getCharacterData(SortedEnd) -
  112. SourceMgr.getCharacterData(SortedBegin));
  113. DEBUG({
  114. StringRef OldText(SourceMgr.getCharacterData(Begin),
  115. SourceMgr.getCharacterData(End) -
  116. SourceMgr.getCharacterData(Begin));
  117. llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
  118. });
  119. auto Range = CharSourceRange::getCharRange(Begin, End);
  120. auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
  121. if (Err) {
  122. llvm::errs() << "Error while sorting using declarations: "
  123. << llvm::toString(std::move(Err)) << "\n";
  124. }
  125. }
  126. UsingDeclarations->clear();
  127. }
  128. } // namespace
  129. UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
  130. const FormatStyle &Style)
  131. : TokenAnalyzer(Env, Style) {}
  132. std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze(
  133. TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
  134. FormatTokenLexer &Tokens) {
  135. const SourceManager &SourceMgr = Env.getSourceManager();
  136. AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
  137. AnnotatedLines.end());
  138. tooling::Replacements Fixes;
  139. SmallVector<UsingDeclaration, 4> UsingDeclarations;
  140. for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
  141. if (AnnotatedLines[I]->InPPDirective ||
  142. !AnnotatedLines[I]->startsWith(tok::kw_using) ||
  143. AnnotatedLines[I]->First->Finalized) {
  144. endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
  145. continue;
  146. }
  147. if (AnnotatedLines[I]->First->NewlinesBefore > 1)
  148. endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
  149. std::string Label = computeUsingDeclarationLabel(AnnotatedLines[I]->First);
  150. if (Label.empty()) {
  151. endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
  152. continue;
  153. }
  154. UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label));
  155. }
  156. endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
  157. return {Fixes, 0};
  158. }
  159. } // namespace format
  160. } // namespace clang