[clang-rename] introduce better symbol finding

This patch introduces:

* TypeLoc visiting, which helps a lot in renaming types
* NestedNameSpecifierLoc visiting (through getting them via ASTMatcher at the moment, though, because RecursiveASTVisitor<T>::VisitNestedNameSpecifierLoc isn't implemented), which helps to treat nested names correctly
* better code formatting and refactoring
* bunch of tests

Reviewers: alexfh

Differential revision: https://reviews.llvm.org/D22465

llvm-svn: 276414
diff --git a/clang-tools-extra/clang-rename/USRFinder.cpp b/clang-tools-extra/clang-rename/USRFinder.cpp
index 7e99e70..809cfcf 100644
--- a/clang-tools-extra/clang-rename/USRFinder.cpp
+++ b/clang-tools-extra/clang-rename/USRFinder.cpp
@@ -35,18 +35,15 @@
   // \brief Finds the NamedDecl at a point in the source.
   // \param Point the location in the source to search for the NamedDecl.
   explicit NamedDeclFindingASTVisitor(const SourceManager &SourceMgr,
-                                      const SourceLocation Point)
-      : Result(nullptr), SourceMgr(SourceMgr),
-        Point(Point) {
-  }
+                                      const SourceLocation Point,
+                                      const ASTContext *Context)
+      : Result(nullptr), SourceMgr(SourceMgr), Point(Point), Context(Context) {}
 
   // \brief Finds the NamedDecl for a name in the source.
   // \param Name the fully qualified name.
   explicit NamedDeclFindingASTVisitor(const SourceManager &SourceMgr,
                                       const std::string &Name)
-      : Result(nullptr), SourceMgr(SourceMgr),
-        Name(Name) {
-  }
+      : Result(nullptr), SourceMgr(SourceMgr), Name(Name) {}
 
   // Declaration visitors:
 
@@ -62,10 +59,6 @@
   // Expression visitors:
 
   bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
-    // Check the namespace specifier first.
-    if (!checkNestedNameSpecifierLoc(Expr->getQualifierLoc()))
-      return false;
-
     const auto *Decl = Expr->getFoundDecl();
     return setResult(Decl, Expr->getLocation(),
                      Decl->getNameAsString().length());
@@ -77,26 +70,33 @@
                      Decl->getNameAsString().length());
   }
 
+  // Other visitors:
+
+  bool VisitTypeLoc(const TypeLoc Loc) {
+    const auto TypeBeginLoc = Loc.getBeginLoc();
+    const auto TypeEndLoc = Lexer::getLocForEndOfToken(
+                   TypeBeginLoc, 0, SourceMgr, Context->getLangOpts());
+    return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc,
+                     TypeEndLoc);
+  }
+
   // Other:
 
-  const NamedDecl *getNamedDecl() {
-    return Result;
+  const NamedDecl *getNamedDecl() { return Result; }
+
+  // \brief Determines if a namespace qualifier contains the point.
+  // \returns false on success and sets Result.
+  void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
+    while (NameLoc) {
+      const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
+      if (Decl) {
+        setResult(Decl, NameLoc.getLocalBeginLoc(), NameLoc.getLocalEndLoc());
+      }
+      NameLoc = NameLoc.getPrefix();
+    }
   }
 
 private:
-  // \brief Determines if a namespace qualifier contains the point.
-  // \returns false on success and sets Result.
-  bool checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
-    while (NameLoc) {
-      const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace();
-      if (Decl && !setResult(Decl, NameLoc.getLocalBeginLoc(),
-                             Decl->getNameAsString().length()))
-        return false;
-      NameLoc = NameLoc.getPrefix();
-    }
-    return true;
-  }
-
   // \brief Sets Result to Decl if the Point is within Start and End.
   // \returns false on success.
   bool setResult(const NamedDecl *Decl, SourceLocation Start,
@@ -119,8 +119,7 @@
 
   // \brief Sets Result to Decl if Point is within Loc and Loc + Offset.
   // \returns false on success.
-  bool setResult(const NamedDecl *Decl, SourceLocation Loc,
-                 unsigned Offset) {
+  bool setResult(const NamedDecl *Decl, SourceLocation Loc, unsigned Offset) {
     // FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2 etc).
     return Offset == 0 ||
            setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1));
@@ -138,6 +137,7 @@
   const SourceManager &SourceMgr;
   const SourceLocation Point; // The location to find the NamedDecl.
   const std::string Name;
+  const ASTContext *Context;
 };
 } // namespace
 
@@ -146,7 +146,7 @@
   const auto &SourceMgr = Context.getSourceManager();
   const auto SearchFile = SourceMgr.getFilename(Point);
 
-  NamedDeclFindingASTVisitor Visitor(SourceMgr, Point);
+  NamedDeclFindingASTVisitor Visitor(SourceMgr, Point, &Context);
 
   // We only want to search the decls that exist in the same file as the point.
   auto Decls = Context.getTranslationUnitDecl()->decls();
@@ -156,29 +156,24 @@
     // FIXME: Add test.
     if (FileName == SearchFile) {
       Visitor.TraverseDecl(CurrDecl);
-      if (const NamedDecl *Result = Visitor.getNamedDecl()) {
-        return Result;
-      }
     }
   }
 
-  return nullptr;
+  NestedNameSpecifierLocFinder Finder(const_cast<ASTContext &>(Context));
+  for (const auto &Location : Finder.getNestedNameSpecifierLocations()) {
+    Visitor.handleNestedNameSpecifierLoc(Location);
+  }
+
+  return Visitor.getNamedDecl();
 }
 
 const NamedDecl *getNamedDeclFor(const ASTContext &Context,
                                  const std::string &Name) {
   const auto &SourceMgr = Context.getSourceManager();
   NamedDeclFindingASTVisitor Visitor(SourceMgr, Name);
-  auto Decls = Context.getTranslationUnitDecl()->decls();
+  Visitor.TraverseDecl(Context.getTranslationUnitDecl());
 
-  for (auto &CurrDecl : Decls) {
-    Visitor.TraverseDecl(CurrDecl);
-    if (const NamedDecl *Result = Visitor.getNamedDecl()) {
-      return Result;
-    }
-  }
-
-  return nullptr;
+  return Visitor.getNamedDecl();
 }
 
 std::string getUSRForDecl(const Decl *Decl) {