UsingDeclarationsSorter.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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 Label < Other.Label;
  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. SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
  70. UsingDeclarations->begin(), UsingDeclarations->end());
  71. std::sort(SortedUsingDeclarations.begin(), SortedUsingDeclarations.end());
  72. for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
  73. if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
  74. continue;
  75. auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
  76. auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
  77. auto SortedBegin =
  78. SortedUsingDeclarations[I].Line->First->Tok.getLocation();
  79. auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
  80. StringRef Text(SourceMgr.getCharacterData(SortedBegin),
  81. SourceMgr.getCharacterData(SortedEnd) -
  82. SourceMgr.getCharacterData(SortedBegin));
  83. DEBUG({
  84. StringRef OldText(SourceMgr.getCharacterData(Begin),
  85. SourceMgr.getCharacterData(End) -
  86. SourceMgr.getCharacterData(Begin));
  87. llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
  88. });
  89. auto Range = CharSourceRange::getCharRange(Begin, End);
  90. auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
  91. if (Err) {
  92. llvm::errs() << "Error while sorting using declarations: "
  93. << llvm::toString(std::move(Err)) << "\n";
  94. }
  95. }
  96. UsingDeclarations->clear();
  97. }
  98. } // namespace
  99. UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
  100. const FormatStyle &Style)
  101. : TokenAnalyzer(Env, Style) {}
  102. tooling::Replacements UsingDeclarationsSorter::analyze(
  103. TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
  104. FormatTokenLexer &Tokens) {
  105. const SourceManager &SourceMgr = Env.getSourceManager();
  106. AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
  107. AnnotatedLines.end());
  108. tooling::Replacements Fixes;
  109. SmallVector<UsingDeclaration, 4> UsingDeclarations;
  110. for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
  111. if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective ||
  112. !AnnotatedLines[I]->startsWith(tok::kw_using) ||
  113. AnnotatedLines[I]->First->Finalized) {
  114. endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
  115. continue;
  116. }
  117. if (AnnotatedLines[I]->First->NewlinesBefore > 1)
  118. endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
  119. std::string Label = computeUsingDeclarationLabel(AnnotatedLines[I]->First);
  120. if (Label.empty()) {
  121. endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
  122. continue;
  123. }
  124. UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label));
  125. }
  126. endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
  127. return Fixes;
  128. }
  129. } // namespace format
  130. } // namespace clang