Added clang_getCursorReferenceNameRange to libclang to to retrieve parts of
a cursor reference, from Erik Verbruggen!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135920 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 63031ce..6d7bf5b 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -158,6 +158,21 @@
 /* Pretty-printing.                                                           */
 /******************************************************************************/
 
+static void PrintRange(CXSourceRange R, const char *str) {
+  CXFile begin_file, end_file;
+  unsigned begin_line, begin_column, end_line, end_column;
+
+  clang_getSpellingLocation(clang_getRangeStart(R),
+                            &begin_file, &begin_line, &begin_column, 0);
+  clang_getSpellingLocation(clang_getRangeEnd(R),
+                            &end_file, &end_line, &end_column, 0);
+  if (!begin_file || !end_file)
+    return;
+
+  printf(" %s=", str);
+  PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
+}
+
 int want_display_name = 0;
 
 static void PrintCursor(CXTranslationUnit TU, CXCursor Cursor) {
@@ -173,6 +188,9 @@
     CXCursor SpecializationOf;
     CXCursor *overridden;
     unsigned num_overridden;
+    unsigned RefNameRangeNr;
+    CXSourceRange CursorExtent;
+    CXSourceRange RefNameRange;
 
     ks = clang_getCursorKindSpelling(Cursor.kind);
     string = want_display_name? clang_getCursorDisplayName(Cursor) 
@@ -288,6 +306,26 @@
       if (clang_isFileMultipleIncludeGuarded(TU, File))
         printf("  [multi-include guarded]");
     }
+    
+    CursorExtent = clang_getCursorExtent(Cursor);
+    RefNameRange = clang_getCursorReferenceNameRange(Cursor, 
+                                                   CXNameRange_WantQualifier
+                                                 | CXNameRange_WantSinglePiece
+                                                 | CXNameRange_WantTemplateArgs,
+                                                     0);
+    if (!clang_equalRanges(CursorExtent, RefNameRange))
+      PrintRange(RefNameRange, "SingleRefName");
+    
+    for (RefNameRangeNr = 0; 1; RefNameRangeNr++) {
+      RefNameRange = clang_getCursorReferenceNameRange(Cursor, 
+                                                   CXNameRange_WantQualifier
+                                                 | CXNameRange_WantTemplateArgs,
+                                                       RefNameRangeNr);
+      if (clang_equalRanges(clang_getNullRange(), RefNameRange))
+        break;
+      if (!clang_equalRanges(CursorExtent, RefNameRange))
+        PrintRange(RefNameRange, "RefName");
+    }
   }
 }
 
@@ -405,18 +443,7 @@
 
 static void PrintCursorExtent(CXCursor C) {
   CXSourceRange extent = clang_getCursorExtent(C);
-  CXFile begin_file, end_file;
-  unsigned begin_line, begin_column, end_line, end_column;
-
-  clang_getSpellingLocation(clang_getRangeStart(extent),
-                            &begin_file, &begin_line, &begin_column, 0);
-  clang_getSpellingLocation(clang_getRangeEnd(extent),
-                            &end_file, &end_line, &end_column, 0);
-  if (!begin_file || !end_file)
-    return;
-
-  printf(" Extent=");
-  PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
+  PrintRange(extent, "Extent");
 }
 
 /* Data used by all of the visitors. */
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index df93049..7f8f759 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -4253,6 +4253,94 @@
   *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc());
 }
 
+namespace {
+typedef llvm::SmallVector<SourceRange, 4> RefNamePieces;
+RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr, 
+                          const DeclarationNameInfo &NI, 
+                          const SourceRange &QLoc, 
+                          const ExplicitTemplateArgumentList *TemplateArgs = 0){
+  const bool WantQualifier = NameFlags & CXNameRange_WantQualifier;
+  const bool WantTemplateArgs = NameFlags & CXNameRange_WantTemplateArgs;
+  const bool WantSinglePiece = NameFlags & CXNameRange_WantSinglePiece;
+  
+  const DeclarationName::NameKind Kind = NI.getName().getNameKind();
+  
+  RefNamePieces Pieces;
+
+  if (WantQualifier && QLoc.isValid())
+    Pieces.push_back(QLoc);
+  
+  if (Kind != DeclarationName::CXXOperatorName || IsMemberRefExpr)
+    Pieces.push_back(NI.getLoc());
+  
+  if (WantTemplateArgs && TemplateArgs)
+    Pieces.push_back(SourceRange(TemplateArgs->LAngleLoc,
+                                 TemplateArgs->RAngleLoc));
+  
+  if (Kind == DeclarationName::CXXOperatorName) {
+    Pieces.push_back(SourceLocation::getFromRawEncoding(
+                       NI.getInfo().CXXOperatorName.BeginOpNameLoc));
+    Pieces.push_back(SourceLocation::getFromRawEncoding(
+                       NI.getInfo().CXXOperatorName.EndOpNameLoc));
+  }
+  
+  if (WantSinglePiece) {
+    SourceRange R(Pieces.front().getBegin(), Pieces.back().getEnd());
+    Pieces.clear();
+    Pieces.push_back(R);
+  }  
+
+  return Pieces;  
+}
+}
+
+CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, unsigned NameFlags,
+                                                unsigned PieceIndex) {
+  RefNamePieces Pieces;
+  
+  switch (C.kind) {
+  case CXCursor_MemberRefExpr:
+    if (MemberExpr *E = dyn_cast<MemberExpr>(getCursorExpr(C)))
+      Pieces = buildPieces(NameFlags, true, E->getMemberNameInfo(),
+                           E->getQualifierLoc().getSourceRange());
+    break;
+  
+  case CXCursor_DeclRefExpr:
+    if (DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C)))
+      Pieces = buildPieces(NameFlags, false, E->getNameInfo(), 
+                           E->getQualifierLoc().getSourceRange(),
+                           E->getExplicitTemplateArgsOpt());
+    break;
+    
+  case CXCursor_CallExpr:
+    if (CXXOperatorCallExpr *OCE = 
+        dyn_cast<CXXOperatorCallExpr>(getCursorExpr(C))) {
+      Expr *Callee = OCE->getCallee();
+      if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Callee))
+        Callee = ICE->getSubExpr();
+
+      if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee))
+        Pieces = buildPieces(NameFlags, false, DRE->getNameInfo(),
+                             DRE->getQualifierLoc().getSourceRange());
+    }
+    break;
+    
+  default:
+    break;
+  }
+
+  if (Pieces.empty()) {
+    if (PieceIndex == 0)
+      return clang_getCursorExtent(C);
+  } else if (PieceIndex < Pieces.size()) {
+      SourceRange R = Pieces[PieceIndex];
+      if (R.isValid())
+        return cxloc::translateSourceRange(getCursorContext(C), R);
+  }
+  
+  return clang_getNullRange();
+}
+
 void clang_enableStackTraces(void) {
   llvm::sys::PrintStackTraceOnErrorSignal();
 }
diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports
index f174989..9610864 100644
--- a/tools/libclang/libclang.darwin.exports
+++ b/tools/libclang/libclang.darwin.exports
@@ -2,6 +2,7 @@
 _clang_CXCursorSet_insert
 _clang_CXXMethod_isStatic
 _clang_CXXMethod_isVirtual
+_clang_getCursorReferenceNameRange
 _clang_annotateTokens
 _clang_codeCompleteAt
 _clang_codeCompleteGetDiagnostic
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 789a94b..329ae5a 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -2,6 +2,7 @@
 clang_CXCursorSet_insert
 clang_CXXMethod_isStatic
 clang_CXXMethod_isVirtual
+clang_getCursorReferenceNameRange
 clang_annotateTokens
 clang_codeCompleteAt
 clang_codeCompleteGetDiagnostic