[cfe-commits] r171773 - in /cfe/trunk: test/Index/c-index-getCursor-pp.c tools/libclang/CIndex.cpp tools/libclang/CIndexHigh.cpp tools/libclang/CIndexer.h tools/libclang/CXCursor.cpp tools/libclang/CXCursor.h
Argyrios Kyrtzidis
akyrtzi at gmail.com
Mon Jan 7 11:16:26 PST 2013
Author: akirtzidis
Date: Mon Jan 7 13:16:25 2013
New Revision: 171773
URL: http://llvm.org/viewvc/llvm-project?rev=171773&view=rev
Log:
[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.
Modified:
cfe/trunk/test/Index/c-index-getCursor-pp.c
cfe/trunk/tools/libclang/CIndex.cpp
cfe/trunk/tools/libclang/CIndexHigh.cpp
cfe/trunk/tools/libclang/CIndexer.h
cfe/trunk/tools/libclang/CXCursor.cpp
cfe/trunk/tools/libclang/CXCursor.h
Modified: cfe/trunk/test/Index/c-index-getCursor-pp.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/c-index-getCursor-pp.c?rev=171773&r1=171772&r2=171773&view=diff
==============================================================================
--- cfe/trunk/test/Index/c-index-getCursor-pp.c (original)
+++ cfe/trunk/test/Index/c-index-getCursor-pp.c Mon Jan 7 13:16:25 2013
@@ -1,6 +1,6 @@
#define OBSCURE(X) X
#define DECORATION
-
+#define FNM(X) OBSCURE(X)
typedef int T;
void OBSCURE(func)(int x) {
OBSCURE(T) DECORATION value;
@@ -23,6 +23,8 @@
#if defined(OBSCURE)
#endif
+#define C(A) A
+
// RUN: c-index-test -cursor-at=%s:1:11 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-1 %s
// CHECK-1: macro definition=OBSCURE
// RUN: c-index-test -cursor-at=%s:2:14 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-2 %s
@@ -45,8 +47,17 @@
// CHECK-10: 20:8 macro expansion=OBSCURE
// CHECK-10: 23:13 macro expansion=OBSCURE
+// RUN: c-index-test -cursor-at=%s:3:20 -cursor-at=%s:12:14 \
+// RUN: -cursor-at=%s:26:11 -cursor-at=%s:26:14 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-IN-MACRODEF %s
+// CHECK-IN-MACRODEF: 3:16 macro expansion=OBSCURE
+// CHECK-IN-MACRODEF: 12:14 macro expansion=A
+// CHECK-IN-MACRODEF: 26:9 macro definition=C
+// CHECK-IN-MACRODEF: 26:9 macro definition=C
+
// Same tests, but with "editing" optimizations
// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:1:11 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-1 %s
// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:2:14 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-2 %s
// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:5:7 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-3 %s
// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:9:10 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-6 %s
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:3:20 -cursor-at=%s:12:14 \
+// RUN: -cursor-at=%s:26:11 -cursor-at=%s:26:14 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-IN-MACRODEF %s
Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=171773&r1=171772&r2=171773&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Mon Jan 7 13:16:25 2013
@@ -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() {
Modified: cfe/trunk/tools/libclang/CIndexHigh.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndexHigh.cpp?rev=171773&r1=171772&r2=171773&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndexHigh.cpp (original)
+++ cfe/trunk/tools/libclang/CIndexHigh.cpp Mon Jan 7 13:16:25 2013
@@ -266,7 +266,7 @@
if (cursor.kind == CXCursor_MacroDefinition)
Macro = getCursorMacroDefinition(cursor)->getName();
else if (cursor.kind == CXCursor_MacroExpansion)
- Macro = getCursorMacroExpansion(cursor)->getName();
+ Macro = getCursorMacroExpansion(cursor).getName();
if (!Macro)
return CXChildVisit_Continue;
@@ -317,7 +317,7 @@
if (Cursor.kind == CXCursor_MacroDefinition)
Macro = getCursorMacroDefinition(Cursor)->getName();
else
- Macro = getCursorMacroExpansion(Cursor)->getName();
+ Macro = getCursorMacroExpansion(Cursor).getName();
if (!Macro)
return;
Modified: cfe/trunk/tools/libclang/CIndexer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndexer.h?rev=171773&r1=171772&r2=171773&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndexer.h (original)
+++ cfe/trunk/tools/libclang/CIndexer.h Mon Jan 7 13:16:25 2013
@@ -26,6 +26,11 @@
namespace clang {
class ASTUnit;
+ class MacroInfo;
+ class MacroDefinition;
+ class SourceLocation;
+ class Token;
+ class IdentifierInfo;
class CIndexer {
bool OnlyLocalDecls;
@@ -94,6 +99,29 @@
namespace cxindex {
void printDiagsToStderr(ASTUnit *Unit);
+
+ /// \brief If \c MacroDefLoc points at a macro definition with \c II as
+ /// its name, this retrieves its MacroInfo.
+ MacroInfo *getMacroInfo(const IdentifierInfo &II,
+ SourceLocation MacroDefLoc,
+ CXTranslationUnit TU);
+
+ /// \brief Retrieves the corresponding MacroInfo of a MacroDefinition.
+ MacroInfo *getMacroInfo(MacroDefinition *MacroDef, CXTranslationUnit TU);
+
+ /// \brief If \c Loc resides inside the definition of \c MI and it points at
+ /// an identifier that has ever been a macro name, this returns the latest
+ /// MacroDefinition for that name, otherwise it returns NULL.
+ MacroDefinition *checkForMacroInMacroDefinition(const MacroInfo *MI,
+ SourceLocation Loc,
+ CXTranslationUnit TU);
+
+ /// \brief If \c Tok resides inside the definition of \c MI and it points at
+ /// an identifier that has ever been a macro name, this returns the latest
+ /// MacroDefinition for that name, otherwise it returns NULL.
+ MacroDefinition *checkForMacroInMacroDefinition(const MacroInfo *MI,
+ const Token &Tok,
+ CXTranslationUnit TU);
}
}
Modified: cfe/trunk/tools/libclang/CXCursor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=171773&r1=171772&r2=171773&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXCursor.cpp (original)
+++ cfe/trunk/tools/libclang/CXCursor.cpp Mon Jan 7 13:16:25 2013
@@ -677,9 +677,28 @@
return C;
}
-MacroExpansion *cxcursor::getCursorMacroExpansion(CXCursor C) {
- assert(C.kind == CXCursor_MacroExpansion);
- return static_cast<MacroExpansion *>(C.data[0]);
+CXCursor cxcursor::MakeMacroExpansionCursor(MacroDefinition *MI,
+ SourceLocation Loc,
+ CXTranslationUnit TU) {
+ assert(Loc.isValid());
+ CXCursor C = { CXCursor_MacroExpansion, 0, { MI, Loc.getPtrEncoding(), TU } };
+ return C;
+}
+
+const IdentifierInfo *cxcursor::MacroExpansionCursor::getName() const {
+ if (isPseudo())
+ return getAsMacroDefinition()->getName();
+ return getAsMacroExpansion()->getName();
+}
+MacroDefinition *cxcursor::MacroExpansionCursor::getDefinition() const {
+ if (isPseudo())
+ return getAsMacroDefinition();
+ return getAsMacroExpansion()->getDefinition();
+}
+SourceRange cxcursor::MacroExpansionCursor::getSourceRange() const {
+ if (isPseudo())
+ return getPseudoLoc();
+ return getAsMacroExpansion()->getSourceRange();
}
CXCursor cxcursor::MakeInclusionDirectiveCursor(InclusionDirective *ID,
Modified: cfe/trunk/tools/libclang/CXCursor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.h?rev=171773&r1=171772&r2=171773&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXCursor.h (original)
+++ cfe/trunk/tools/libclang/CXCursor.h Mon Jan 7 13:16:25 2013
@@ -42,6 +42,7 @@
class TemplateName;
class TypeDecl;
class VarDecl;
+class IdentifierInfo;
namespace cxcursor {
@@ -153,9 +154,51 @@
CXCursor MakeMacroExpansionCursor(MacroExpansion *,
CXTranslationUnit TU);
-/// \brief Unpack a given macro expansion cursor to retrieve its
-/// source range.
-MacroExpansion *getCursorMacroExpansion(CXCursor C);
+/// \brief Create a "pseudo" macro expansion cursor, using a macro definition
+/// and a source location.
+CXCursor MakeMacroExpansionCursor(MacroDefinition *, SourceLocation Loc,
+ CXTranslationUnit TU);
+
+/// \brief Wraps a macro expansion cursor and provides a common interface
+/// for a normal macro expansion cursor or a "pseudo" one.
+///
+/// "Pseudo" macro expansion cursors (essentially a macro definition along with
+/// a source location) are created in special cases, for example they can be
+/// created for identifiers inside macro definitions, if these identifiers are
+/// macro names.
+class MacroExpansionCursor {
+ CXCursor C;
+
+ bool isPseudo() const {
+ return C.data[1] != 0;
+ }
+ MacroDefinition *getAsMacroDefinition() const {
+ assert(isPseudo());
+ return static_cast<MacroDefinition *>(C.data[0]);
+ }
+ MacroExpansion *getAsMacroExpansion() const {
+ assert(!isPseudo());
+ return static_cast<MacroExpansion *>(C.data[0]);
+ }
+ SourceLocation getPseudoLoc() const {
+ assert(isPseudo());
+ return SourceLocation::getFromPtrEncoding(C.data[1]);
+ }
+
+public:
+ MacroExpansionCursor(CXCursor C) : C(C) {
+ assert(C.kind == CXCursor_MacroExpansion);
+ }
+
+ const IdentifierInfo *getName() const;
+ MacroDefinition *getDefinition() const;
+ SourceRange getSourceRange() const;
+};
+
+/// \brief Unpack a given macro expansion cursor to retrieve its info.
+static inline MacroExpansionCursor getCursorMacroExpansion(CXCursor C) {
+ return C;
+}
/// \brief Create an inclusion directive cursor.
CXCursor MakeInclusionDirectiveCursor(InclusionDirective *,
More information about the cfe-commits
mailing list