[libclang] When getting the cursor for an identifier inside a macro definition, check if
this was ever a macro name and return a specific CXCursor_MacroExpansion cursor in such a case,
instead of the generic CXCursor_MacroDefinition.

Checking for macro name makes sure the identifier is not part of the identifier list in a
function macro.
While, in general, resolving identifiers in macro definitions to other macros may not be completely accurate,
it greatly improves functionality such as give-me-the-definition-of-this, which was not working at all
inside macro definitions.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@171773 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 177b3a6..96c7c58 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -520,6 +520,19 @@
                                                     A->getInterfaceLoc(), TU));
   }
 
+  // If pointing inside a macro definition, check if the token is an identifier
+  // that was ever defined as a macro. In such a case, create a "pseudo" macro
+  // expansion cursor for that token.
+  SourceLocation BeginLoc = RegionOfInterest.getBegin();
+  if (Cursor.kind == CXCursor_MacroDefinition &&
+      BeginLoc == RegionOfInterest.getEnd()) {
+    SourceLocation Loc = AU->mapLocationToPreamble(BeginLoc);
+    MacroInfo *MI = getMacroInfo(cxcursor::getCursorMacroDefinition(Cursor),TU);
+    if (MacroDefinition *MacroDef =
+          checkForMacroInMacroDefinition(MI, Loc, TU))
+      return Visit(cxcursor::MakeMacroExpansionCursor(MacroDef, BeginLoc, TU));
+  }
+
   // Nothing to visit at the moment.
   return false;
 }
@@ -3185,7 +3198,7 @@
   }
   
   if (C.kind == CXCursor_MacroExpansion)
-    return createCXString(getCursorMacroExpansion(C)->getName()
+    return createCXString(getCursorMacroExpansion(C).getName()
                                                            ->getNameStart());
 
   if (C.kind == CXCursor_MacroDefinition)
@@ -3999,7 +4012,7 @@
 
   if (C.kind == CXCursor_MacroExpansion) {
     SourceLocation L
-      = cxcursor::getCursorMacroExpansion(C)->getSourceRange().getBegin();
+      = cxcursor::getCursorMacroExpansion(C).getSourceRange().getBegin();
     return cxloc::translateSourceLocation(getCursorContext(C), L);
   }
 
@@ -4125,7 +4138,7 @@
 
   if (C.kind == CXCursor_MacroExpansion) {
     ASTUnit *TU = getCursorASTUnit(C);
-    SourceRange Range = cxcursor::getCursorMacroExpansion(C)->getSourceRange();
+    SourceRange Range = cxcursor::getCursorMacroExpansion(C).getSourceRange();
     return TU->mapRangeFromPreamble(Range);
   }
 
@@ -4265,7 +4278,7 @@
   }
   
   if (C.kind == CXCursor_MacroExpansion) {
-    if (MacroDefinition *Def = getCursorMacroExpansion(C)->getDefinition())
+    if (MacroDefinition *Def = getCursorMacroExpansion(C).getDefinition())
       return MakeMacroDefinitionCursor(Def, tu);
   }
 
@@ -5265,7 +5278,7 @@
     if (cursor.kind != CXCursor_MacroExpansion)
       return CXChildVisit_Continue;
 
-    SourceRange macroRange = getCursorMacroExpansion(cursor)->getSourceRange();
+    SourceRange macroRange = getCursorMacroExpansion(cursor).getSourceRange();
     if (macroRange.getBegin() == macroRange.getEnd())
       return CXChildVisit_Continue; // it's not a function macro.
 
@@ -6169,6 +6182,100 @@
 #endif
 }
 
+MacroInfo *cxindex::getMacroInfo(const IdentifierInfo &II,
+                                 SourceLocation MacroDefLoc,
+                                 CXTranslationUnit TU){
+  if (MacroDefLoc.isInvalid() || !TU)
+    return 0;
+
+  ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+  Preprocessor &PP = Unit->getPreprocessor();
+  if (!II.hadMacroDefinition())
+    return 0;
+
+  MacroInfo *MI = PP.getMacroInfoHistory(const_cast<IdentifierInfo*>(&II));
+  while (MI) {
+    if (MacroDefLoc == MI->getDefinitionLoc())
+      return MI;
+    MI = MI->getPreviousDefinition();
+  }
+
+  return 0;
+}
+
+MacroInfo *cxindex::getMacroInfo(MacroDefinition *MacroDef,
+                                 CXTranslationUnit TU) {
+  if (!MacroDef || !TU)
+    return 0;
+  const IdentifierInfo *II = MacroDef->getName();
+  if (!II)
+    return 0;
+
+  return getMacroInfo(*II, MacroDef->getLocation(), TU);
+}
+
+MacroDefinition *cxindex::checkForMacroInMacroDefinition(const MacroInfo *MI,
+                                                         const Token &Tok,
+                                                         CXTranslationUnit TU) {
+  if (!MI || !TU)
+    return 0;
+  if (Tok.isNot(tok::raw_identifier))
+    return 0;
+
+  if (MI->getNumTokens() == 0)
+    return 0;
+  SourceRange DefRange(MI->getReplacementToken(0).getLocation(),
+                       MI->getDefinitionEndLoc());
+  ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+
+  // Check that the token is inside the definition and not its argument list.
+  SourceManager &SM = Unit->getSourceManager();
+  if (SM.isBeforeInTranslationUnit(Tok.getLocation(), DefRange.getBegin()))
+    return 0;
+  if (SM.isBeforeInTranslationUnit(DefRange.getEnd(), Tok.getLocation()))
+    return 0;
+
+  Preprocessor &PP = Unit->getPreprocessor();
+  PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
+  if (!PPRec)
+    return 0;
+
+  StringRef Name(Tok.getRawIdentifierData(), Tok.getLength());
+  IdentifierInfo &II = PP.getIdentifierTable().get(Name);
+  if (!II.hadMacroDefinition())
+    return 0;
+
+  // Check that the identifier is not one of the macro arguments.
+  if (std::find(MI->arg_begin(), MI->arg_end(), &II) != MI->arg_end())
+    return 0;
+
+  MacroInfo *InnerMI = PP.getMacroInfoHistory(&II);
+  if (!InnerMI)
+    return 0;
+
+  return PPRec->findMacroDefinition(InnerMI);
+}
+
+MacroDefinition *cxindex::checkForMacroInMacroDefinition(const MacroInfo *MI,
+                                                         SourceLocation Loc,
+                                                         CXTranslationUnit TU) {
+  if (Loc.isInvalid() || !MI || !TU)
+    return 0;
+
+  if (MI->getNumTokens() == 0)
+    return 0;
+  ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+  Preprocessor &PP = Unit->getPreprocessor();
+  if (!PP.getPreprocessingRecord())
+    return 0;
+  Loc = Unit->getSourceManager().getSpellingLoc(Loc);
+  Token Tok;
+  if (PP.getRawToken(Loc, Tok))
+    return 0;
+
+  return checkForMacroInMacroDefinition(MI, Tok, TU);
+}
+
 extern "C" {
 
 CXString clang_getClangVersion() {