UsingDeclarationsSorter.cpp 5.5 KB

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