hokein created this revision.
Herald added a subscriber: klimek.

This is first step to integrate qualified rename into clang-refactor.

Also a few changes to SymbolOccurrence:

- add more information to SymbolOccurrence
- remove the way of using SourceLocation as the array size


https://reviews.llvm.org/D39290

Files:
  include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h
  lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
  lib/Tooling/Refactoring/Rename/USRLocFinder.cpp

Index: lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
===================================================================
--- lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
+++ lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
@@ -158,27 +158,6 @@
   RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context)
       : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
 
-  // A structure records all information of a symbol reference being renamed.
-  // We try to add as few prefix qualifiers as possible.
-  struct RenameInfo {
-    // The begin location of a symbol being renamed.
-    SourceLocation Begin;
-    // The end location of a symbol being renamed.
-    SourceLocation End;
-    // The declaration of a symbol being renamed (can be nullptr).
-    const NamedDecl *FromDecl;
-    // The declaration in which the nested name is contained (can be nullptr).
-    const Decl *Context;
-    // The nested name being replaced (can be nullptr).
-    const NestedNameSpecifier *Specifier;
-    // Determine whether the prefix qualifiers of the NewName should be ignored.
-    // Normally, we set it to true for the symbol declaration and definition to
-    // avoid adding prefix qualifiers.
-    // For example, if it is true and NewName is "a::b::foo", then the symbol
-    // occurrence which the RenameInfo points to will be renamed to "foo".
-    bool IgnorePrefixQualifers;
-  };
-
   bool VisitNamedDecl(const NamedDecl *Decl) {
     // UsingDecl has been handled in other place.
     if (llvm::isa<UsingDecl>(Decl))
@@ -200,13 +179,7 @@
       auto StartLoc = Decl->getLocation();
       auto EndLoc = StartLoc;
       if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
-        RenameInfo Info = {StartLoc,
-                           EndLoc,
-                           /*FromDecl=*/nullptr,
-                           /*Context=*/nullptr,
-                           /*Specifier=*/nullptr,
-                           /*IgnorePrefixQualifers=*/true};
-        RenameInfos.push_back(Info);
+        addSymbolOccurence(StartLoc, EndLoc);
       }
     }
     return true;
@@ -217,11 +190,7 @@
     auto StartLoc = Expr->getMemberLoc();
     auto EndLoc = Expr->getMemberLoc();
     if (isInUSRSet(Decl)) {
-      RenameInfos.push_back({StartLoc, EndLoc,
-                            /*FromDecl=*/nullptr,
-                            /*Context=*/nullptr,
-                            /*Specifier=*/nullptr,
-                            /*IgnorePrefixQualifiers=*/true});
+      addSymbolOccurence(StartLoc, EndLoc);
     }
     return true;
   }
@@ -236,11 +205,7 @@
       if (const FieldDecl *FD = Initializer->getMember()) {
         if (isInUSRSet(FD)) {
           auto Loc = Initializer->getSourceLocation();
-          RenameInfos.push_back({Loc, Loc,
-                                 /*FromDecl=*/nullptr,
-                                 /*Context=*/nullptr,
-                                 /*Specifier=*/nullptr,
-                                 /*IgnorePrefixQualifiers=*/true});
+          addSymbolOccurence(Loc, Loc);
         }
       }
     }
@@ -267,11 +232,7 @@
         // Handle renaming static template class methods, we only rename the
         // name without prefix qualifiers and restrict the source range to the
         // name.
-        RenameInfos.push_back({EndLoc, EndLoc,
-                               /*FromDecl=*/nullptr,
-                               /*Context=*/nullptr,
-                               /*Specifier=*/nullptr,
-                               /*IgnorePrefixQualifiers=*/true});
+        addSymbolOccurence(EndLoc, EndLoc);
         return true;
       }
     }
@@ -309,13 +270,12 @@
     }
     if (isInUSRSet(Decl) &&
         IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
-      RenameInfo Info = {StartLoc,
+      addSymbolOccurence(StartLoc,
                          EndLoc,
                          Decl,
                          getClosestAncestorDecl(*Expr),
                          Expr->getQualifier(),
-                         /*IgnorePrefixQualifers=*/false};
-      RenameInfos.push_back(Info);
+                         /*IgnorePrefixQualifers=*/false);
     }
 
     return true;
@@ -338,13 +298,11 @@
     if (const auto *TargetDecl =
             getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
       if (isInUSRSet(TargetDecl)) {
-        RenameInfo Info = {NestedLoc.getBeginLoc(),
+        addSymbolOccurence(NestedLoc.getBeginLoc(),
                            EndLocationForType(NestedLoc.getTypeLoc()),
-                           TargetDecl,
-                           getClosestAncestorDecl(NestedLoc),
+                           TargetDecl, getClosestAncestorDecl(NestedLoc),
                            NestedLoc.getNestedNameSpecifier()->getPrefix(),
-                           /*IgnorePrefixQualifers=*/false};
-        RenameInfos.push_back(Info);
+                           /*IgnorePrefixQualifers=*/false);
       }
     }
     return true;
@@ -388,13 +346,12 @@
         auto StartLoc = StartLocationForType(Loc);
         auto EndLoc = EndLocationForType(Loc);
         if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
-          RenameInfo Info = {StartLoc,
+          addSymbolOccurence(StartLoc,
                              EndLoc,
                              TargetDecl,
                              getClosestAncestorDecl(Loc),
                              GetNestedNameForType(Loc),
-                             /*IgnorePrefixQualifers=*/false};
-          RenameInfos.push_back(Info);
+                             /*IgnorePrefixQualifers=*/false);
         }
         return true;
       }
@@ -423,23 +380,39 @@
         auto StartLoc = StartLocationForType(TargetLoc);
         auto EndLoc = EndLocationForType(TargetLoc);
         if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
-          RenameInfo Info = {
-              StartLoc,
-              EndLoc,
+          addSymbolOccurence(
+              StartLoc, EndLoc,
               TemplateSpecType->getTemplateName().getAsTemplateDecl(),
               getClosestAncestorDecl(
                   ast_type_traits::DynTypedNode::create(TargetLoc)),
               GetNestedNameForType(TargetLoc),
-              /*IgnorePrefixQualifers=*/false};
-          RenameInfos.push_back(Info);
+              /*IgnorePrefixQualifers=*/false);
         }
       }
     }
     return true;
   }
 
-  // Returns a list of RenameInfo.
-  const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; }
+  void addSymbolOccurence(SourceLocation StartLoc, SourceLocation EndLoc,
+                          const NamedDecl *FromDecl = nullptr,
+                          const Decl *DeclContext = nullptr,
+                          const NestedNameSpecifier *Specifier = nullptr,
+                          bool IgnorePrefixQualifers = true) {
+    const auto& SM = Context.getSourceManager();
+    StringRef QualifiedName = Lexer::getSourceText(
+        CharSourceRange::getTokenRange(SM.getSpellingLoc(StartLoc),
+                                       SM.getSpellingLoc(EndLoc)),
+        SM, Context.getLangOpts());
+    SymbolOccurrence::SymbolContext SC = {FromDecl, DeclContext, Specifier,
+                                          IgnorePrefixQualifers};
+    SymbolOccurrence Occurrence(SymbolName(QualifiedName),
+                                SymbolOccurrence::MatchingSymbol,
+                                SM.getSpellingLoc(StartLoc));
+    Occurrence.setSymbolContext(SC);
+    Occurences.push_back(std::move(Occurrence));
+  }
+
+  SymbolOccurrences takeOccurences() { return std::move(Occurences); }
 
   // Returns a list of using declarations which are needed to update.
   const std::vector<const UsingDecl *> &getUsingDecls() const {
@@ -493,7 +466,7 @@
 
   const std::set<std::string> USRSet;
   ASTContext &Context;
-  std::vector<RenameInfo> RenameInfos;
+  SymbolOccurrences Occurences;
   // Record all interested using declarations which contains the using-shadow
   // declarations of the symbol declarations being renamed.
   std::vector<const UsingDecl *> UsingDecls;
@@ -518,33 +491,39 @@
       TranslationUnitDecl->getASTContext().getSourceManager();
 
   std::vector<tooling::AtomicChange> AtomicChanges;
-  auto Replace = [&](SourceLocation Start, SourceLocation End,
-                     llvm::StringRef Text) {
-    tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start);
-    llvm::Error Err = ReplaceChange.replace(
-        SM, CharSourceRange::getTokenRange(Start, End), Text);
+  auto Replace = [&](CharSourceRange Range, llvm::StringRef Text) {
+    tooling::AtomicChange ReplaceChange = tooling::AtomicChange(
+        SM, Range.getBegin());
+    llvm::Error Err = ReplaceChange.replace(SM, Range, Text);
     if (Err) {
       llvm::errs() << "Faile to add replacement to AtomicChange: "
                    << llvm::toString(std::move(Err)) << "\n";
       return;
     }
     AtomicChanges.push_back(std::move(ReplaceChange));
   };
 
-  for (const auto &RenameInfo : Finder.getRenameInfos()) {
+  for (const auto &Occurrence: Finder.takeOccurences()) {
     std::string ReplacedName = NewName.str();
-    if (RenameInfo.IgnorePrefixQualifers) {
+    assert(Occurrence.getSymbolContext() &&
+           "Occurrence in qualified rename should have Context.");
+    assert(Occurrence.getSymbolName().getNamePieces().size() == 1 &&
+           "Qualified rename doesn't support symbol name composed of "
+           "multiple strings.");
+    const auto& OccurrenceContext = *Occurrence.getSymbolContext();
+    if (OccurrenceContext.IgnorePrefixQualifers) {
       // Get the name without prefix qualifiers from NewName.
       size_t LastColonPos = NewName.find_last_of(':');
       if (LastColonPos != std::string::npos)
         ReplacedName = NewName.substr(LastColonPos + 1);
     } else {
-      if (RenameInfo.FromDecl && RenameInfo.Context) {
+      if (OccurrenceContext.FromDecl && OccurrenceContext.Context) {
         if (!llvm::isa<clang::TranslationUnitDecl>(
-                RenameInfo.Context->getDeclContext())) {
+                OccurrenceContext.Context->getDeclContext())) {
           ReplacedName = tooling::replaceNestedName(
-              RenameInfo.Specifier, RenameInfo.Context->getDeclContext(),
-              RenameInfo.FromDecl,
+              OccurrenceContext.Specifier,
+              OccurrenceContext.Context->getDeclContext(),
+              OccurrenceContext.FromDecl,
               NewName.startswith("::") ? NewName.str()
                                        : ("::" + NewName).str());
         } else {
@@ -555,10 +534,8 @@
           // the translation unit and ignore the possible existence of
           // using-decls (in the global scope) that can shorten the replaced
           // name.
-          llvm::StringRef ActualName = Lexer::getSourceText(
-              CharSourceRange::getTokenRange(
-                  SourceRange(RenameInfo.Begin, RenameInfo.End)),
-              SM, TranslationUnitDecl->getASTContext().getLangOpts());
+          llvm::StringRef ActualName =
+              Occurrence.getSymbolName().getNamePieces()[0];
           // Add the leading "::" back if the name written in the code contains
           // it.
           if (ActualName.startswith("::") && !NewName.startswith("::")) {
@@ -570,13 +547,18 @@
       if (NewName.startswith("::") && NewName.substr(2) == ReplacedName)
         ReplacedName = NewName.str();
     }
-    Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
+    Replace(
+        CharSourceRange::getCharRange(Occurrence.getNameRanges()[0].getBegin(),
+                                      Occurrence.getNameRanges()[0].getEnd()),
+        ReplacedName);
   }
 
   // Hanlde using declarations explicitly as "using a::Foo" don't trigger
   // typeLoc for "a::Foo".
   for (const auto *Using : Finder.getUsingDecls())
-    Replace(Using->getLocStart(), Using->getLocEnd(), "using " + NewName.str());
+    Replace(CharSourceRange::getTokenRange(Using->getLocStart(),
+                                           Using->getLocEnd()),
+            "using " + NewName.str());
 
   return AtomicChanges;
 }
Index: lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
===================================================================
--- lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
+++ lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
@@ -16,21 +16,14 @@
 
 SymbolOccurrence::SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind,
                                    ArrayRef<SourceLocation> Locations)
-    : Kind(Kind) {
+    : Name(Name), Kind(Kind) {
   ArrayRef<std::string> NamePieces = Name.getNamePieces();
   assert(Locations.size() == NamePieces.size() &&
          "mismatching number of locations and lengths");
   assert(!Locations.empty() && "no locations");
-  if (Locations.size() == 1) {
-    RangeOrNumRanges = SourceRange(
-        Locations[0], Locations[0].getLocWithOffset(NamePieces[0].size()));
-    return;
-  }
-  MultipleRanges = llvm::make_unique<SourceRange[]>(Locations.size());
-  RangeOrNumRanges.setBegin(
-      SourceLocation::getFromRawEncoding(Locations.size()));
+  Ranges = llvm::make_unique<SourceRange[]>(Locations.size());
   for (const auto &Loc : llvm::enumerate(Locations)) {
-    MultipleRanges[Loc.index()] = SourceRange(
+    Ranges[Loc.index()] = SourceRange(
         Loc.value(),
         Loc.value().getLocWithOffset(NamePieces[Loc.index()].size()));
   }
Index: include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h
===================================================================
--- include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h
+++ include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h
@@ -12,14 +12,18 @@
 
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolName.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include <vector>
 
 namespace clang {
-namespace tooling {
 
-class SymbolName;
+class Decl;
+class NamedDecl;
+class NestedNameSpecifier;
+
+namespace tooling {
 
 /// An occurrence of a symbol in the source.
 ///
@@ -61,6 +65,23 @@
     MatchingSymbol
   };
 
+  // A context for qualified rename, it is used to calculate the fewest prefix
+  // qualifiers for the symbol occurrence.
+  struct SymbolContext {
+    // The declaration of a symbol being renamed (can be nullptr).
+    const NamedDecl *FromDecl;
+    // The declaration in which the nested name is contained (can be nullptr).
+    const Decl *Context;
+    // The nested name being replaced (can be nullptr).
+    const NestedNameSpecifier *Specifier;
+    // Determine whether the prefix qualifiers of the NewName should be ignored.
+    // Normally, we set it to true for the symbol declaration and definition to
+    // avoid adding prefix qualifiers.
+    // For example, if it is true and NewName is "a::b::foo", then the symbol
+    // occurrence which the RenameInfo points to will be renamed to "foo".
+    bool IgnorePrefixQualifers;
+  };
+
   SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind,
                    ArrayRef<SourceLocation> Locations);
 
@@ -70,17 +91,27 @@
   OccurrenceKind getKind() const { return Kind; }
 
   ArrayRef<SourceRange> getNameRanges() const {
-    if (MultipleRanges) {
-      return llvm::makeArrayRef(MultipleRanges.get(),
-                                RangeOrNumRanges.getBegin().getRawEncoding());
-    }
-    return RangeOrNumRanges;
+    return llvm::makeArrayRef(Ranges.get(), Name.getNamePieces().size());
+  }
+
+  const SymbolName& getSymbolName() const {
+    return Name;
+  }
+
+  void setSymbolContext(SymbolContext SC) {
+    Context = std::move(SC);
+  }
+
+  llvm::Optional<SymbolContext> getSymbolContext() const {
+    return Context;
   }
 
 private:
+  SymbolName Name;
   OccurrenceKind Kind;
-  std::unique_ptr<SourceRange[]> MultipleRanges;
-  SourceRange RangeOrNumRanges;
+  std::unique_ptr<SourceRange[]> Ranges;
+  // Empty if the rename operation is not qualified rename.
+  llvm::Optional<SymbolContext> Context;
 };
 
 using SymbolOccurrences = std::vector<SymbolOccurrence>;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to