[cfe-dev] [patch] introduce libclang API for MacroInfo
Daniel Herring
dherring at tentpost.com
Tue May 31 22:12:54 PDT 2011
The attached patch (git format, based on SVN trunk revision 131770) adds a
few functions to libclang for inspecting macros. Haven't built against
current trunk (132387) but the patch applies cleanly. It is not fully
tested, but I wanted to get it out for others to comment on, test, fix it
up for commit, etc.
notes:
- I tried to mimic the code style, but haven't really read the
standards...
- original plan was to re-lex the macro. This didn't work because the
currently exposed source locations point to the macro name, not the
#define... I couldn't see any obvious way to find it (especially with
end-of-line backslashes).
- The preprocessing record maps MacroInfo -> MacroDefinition, but not the
other way around... I hacked in something but don't know all the
implications.
- clang_getMacroTokens could use some review, in particular the missing
source location and whether previousWasAt makes sense (I don't know ObjC)
- clang_isMacroFunctionLike and clang_getMacroTokens seem to work
- clang_isMacroBuiltin isn't reporting true anywhere, even for many macros
that should be (e.g. __clang_version__)
- haven't tried to test clang_isMacroVariadic
- didn't touch the exports for Darwin since I don't have OS X handy at
home
For reference, here's a snippet from my test harness. Mostly C, but
compiled under g++...
if(kind==CXCursor_MacroDefinition)
{
if(clang_isMacroBuiltin(cursor))
printf("\t(builtin)\n");
if(clang_isMacroFunctionLike(cursor))
printf("\t(functionlike)\n");
if(clang_isMacroVariadic(cursor))
printf("\t(variadic)\n");
CXToken *args, *tokens;
unsigned numArgs, numTokens;
clang_getMacroTokens(cursor, &args, &numArgs, &tokens, &numTokens);
for(int i=0; i<numArgs; i++)
{
CXString s=clang_getTokenSpelling(tu, args[i]);
printf("%s arg: %s\n", indent, clang_getCString(s));
clang_disposeString(s);
}
for(int i=0; i<numTokens; i++)
{
CXString s=clang_getTokenSpelling(tu, tokens[i]);
printf("%s token: %s\n", indent, clang_getCString(s));
clang_disposeString(s);
}
clang_disposeTokens(tu, args, numArgs);
clang_disposeTokens(tu, tokens, numTokens);
}
Later,
Daniel
-------------- next part --------------
From 2c3857d2f939c37bd0b5790602b015d84bdc4a82 Mon Sep 17 00:00:00 2001
From: D Herring <dherring at at.tentpost.dot.com>
Date: Wed, 1 Jun 2011 00:49:40 -0400
Subject: [PATCH] introduce libclang API for MacroInfo
---
include/clang-c/Index.h | 7 ++
include/clang/Lex/PreprocessingRecord.h | 2 +
lib/Lex/PreprocessingRecord.cpp | 10 +++
tools/libclang/CIndex.cpp | 136 +++++++++++++++++++++++++++++++
tools/libclang/libclang.exports | 4 +
5 files changed, 159 insertions(+), 0 deletions(-)
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index c79475e..bea7b32 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -2452,6 +2452,13 @@ CINDEX_LINKAGE void clang_annotateTokens(CXTranslationUnit TU,
CXToken *Tokens, unsigned NumTokens,
CXCursor *Cursors);
+CINDEX_LINKAGE unsigned clang_isMacroBuiltin(CXCursor);
+CINDEX_LINKAGE unsigned clang_isMacroFunctionLike(CXCursor);
+CINDEX_LINKAGE unsigned clang_isMacroVariadic(CXCursor);
+CINDEX_LINKAGE void clang_getMacroTokens(CXCursor c,
+ CXToken **args, unsigned *numArgs,
+ CXToken **replacement, unsigned *numReplacement);
+
/**
* \brief Free the given set of tokens.
*/
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
index e498e9d..c6b3639 100644
--- a/include/clang/Lex/PreprocessingRecord.h
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -341,6 +341,8 @@ namespace clang {
/// \brief Retrieve the macro definition that corresponds to the given
/// \c MacroInfo.
MacroDefinition *findMacroDefinition(const MacroInfo *MI);
+ /// \return the macro info registered for the given definition, or 0
+ const MacroInfo *findMacroInfo(const MacroDefinition *MD);
virtual void MacroExpands(const Token &Id, const MacroInfo* MI);
virtual void MacroDefined(const Token &Id, const MacroInfo *MI);
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 0c8d948..7fcd135 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -120,6 +120,16 @@ MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
return Pos->second;
}
+const MacroInfo *PreprocessingRecord::findMacroInfo(const MacroDefinition *MD) {
+ typedef llvm::DenseMap<const MacroInfo *, MacroDefinition *>::const_iterator I;
+ I end=MacroDefinitions.end();
+ for(I iter=MacroDefinitions.begin(); iter!=end; iter++) {
+ if(iter->second==MD)
+ return iter->first;
+ }
+ return 0;
+}
+
void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) {
if (!IncludeNestedMacroInstantiations && Id.getLocation().isMacroID())
return;
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 0014118..5862ff7 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -4887,6 +4887,142 @@ void clang_annotateTokens(CXTranslationUnit TU,
} // end: extern "C"
//===----------------------------------------------------------------------===//
+// Operations for querying macros.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ const MacroInfo *getCursorMacroInfo(CXCursor C) {
+ MacroDefinition *MD=static_cast<MacroDefinition *>(C.data[0]);
+ CXTranslationUnit TU=static_cast<CXTranslationUnit>(C.data[2]);
+ ASTUnit *AU=static_cast<ASTUnit*>(TU->TUData);
+
+ PreprocessingRecord *PPRec
+ = AU->getPreprocessor().getPreprocessingRecord();
+
+ return PPRec->findMacroInfo(MD);
+ }
+}
+
+extern "C" {
+
+unsigned clang_isMacroBuiltin(CXCursor C) {
+ const MacroInfo *MI=getCursorMacroInfo(C);
+ if(!MI)
+ return false;
+ return MI->isBuiltinMacro();
+}
+
+unsigned clang_isMacroFunctionLike(CXCursor C) {
+ const MacroInfo *MI=getCursorMacroInfo(C);
+ if(!MI)
+ return false;
+ return MI->isFunctionLike();
+}
+
+unsigned clang_isMacroVariadic(CXCursor C) {
+ const MacroInfo *MI=getCursorMacroInfo(C);
+ if(!MI)
+ return false;
+ return MI->isVariadic();
+}
+
+void clang_getMacroTokens(CXCursor C,
+ CXToken **args, unsigned *numArgs,
+ CXToken **tokens, unsigned *numTokens) {
+ const MacroInfo *MI=getCursorMacroInfo(C);
+ if(!MI) {
+ *args=0;
+ *numArgs=0;
+ *tokens=0;
+ *numTokens=0;
+ return;
+ }
+
+ *numArgs=MI->getNumArgs();
+ CXToken *aout=(CXToken *)malloc(sizeof(CXToken) * *numArgs);
+ *args = aout;
+ bool previousWasAt = false;
+ for(MacroInfo::arg_iterator iter=MI->arg_begin(), end=MI->arg_end(); iter!=end; iter++, aout++) {
+ // borrow from clang_tokenize
+ IdentifierInfo *II=*iter;
+
+ // Initialize the CXToken.
+ CXToken CXTok;
+
+ // - Common fields
+ CXTok.int_data[1] = SourceLocation().getRawEncoding(); // fixme
+ CXTok.int_data[2] = II->getLength();
+ CXTok.int_data[3] = 0;
+ // - Kind-specific fields
+ if ((II->getObjCKeywordID() != tok::objc_not_keyword) && previousWasAt) {
+ CXTok.int_data[0] = CXToken_Keyword;
+ }
+ else {
+ CXTok.int_data[0] = (II->getTokenID()==tok::identifier)
+ ? CXToken_Identifier
+ : CXToken_Keyword;
+ }
+ CXTok.ptr_data = II;
+
+ //createCXString((*iter)->getName());
+ *aout=CXTok;
+
+ previousWasAt = II->getTokenID()==tok::at;
+ }
+
+ CXTranslationUnit TU=static_cast<CXTranslationUnit>(C.data[2]);
+ ASTUnit *CXXUnit=static_cast<ASTUnit*>(TU->TUData);
+
+ *numTokens=MI->getNumTokens();
+ CXToken *tout = (CXToken *)malloc(sizeof(CXToken) * *numTokens);
+ *tokens = tout;
+ previousWasAt=false;
+ for(MacroInfo::tokens_iterator iter=MI->tokens_begin(), end=MI->tokens_end(); iter!=end; iter++, tout++) {
+ // borrow from clang_tokenize
+ Token Tok=*iter;
+
+ // Initialize the CXToken.
+ CXToken CXTok;
+
+ // - Common fields
+ CXTok.int_data[1] = Tok.getLocation().getRawEncoding();
+ CXTok.int_data[2] = Tok.getLength();
+ CXTok.int_data[3] = 0;
+
+ // - Kind-specific fields
+ if (Tok.isLiteral()) {
+ CXTok.int_data[0] = CXToken_Literal;
+ CXTok.ptr_data = (void *)Tok.getLiteralData();
+ } else if (Tok.is(tok::raw_identifier)) {
+ // Lookup the identifier to determine whether we have a keyword.
+ IdentifierInfo *II
+ = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok);
+
+ if ((II->getObjCKeywordID() != tok::objc_not_keyword) && previousWasAt) {
+ CXTok.int_data[0] = CXToken_Keyword;
+ }
+ else {
+ CXTok.int_data[0] = Tok.is(tok::identifier)
+ ? CXToken_Identifier
+ : CXToken_Keyword;
+ }
+ CXTok.ptr_data = II;
+ } else if (Tok.is(tok::comment)) {
+ CXTok.int_data[0] = CXToken_Comment;
+ CXTok.ptr_data = 0;
+ } else {
+ CXTok.int_data[0] = CXToken_Punctuation;
+ CXTok.ptr_data = 0;
+ }
+ previousWasAt = Tok.is(tok::at);
+
+ *tout=CXTok;
+ }
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
// Operations for querying linkage of a cursor.
//===----------------------------------------------------------------------===//
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 403cd67..3395097 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -86,6 +86,7 @@ clang_getInclusions
clang_getInstantiationLocation
clang_getLocation
clang_getLocationForOffset
+clang_getMacroTokens
clang_getNullCursor
clang_getNullLocation
clang_getNullRange
@@ -118,6 +119,9 @@ clang_isDeclaration
clang_isExpression
clang_isFileMultipleIncludeGuarded
clang_isInvalid
+clang_isMacroBuiltin
+clang_isMacroFunctionLike
+clang_isMacroVariadic
clang_isPODType
clang_isPreprocessing
clang_isReference
--
1.7.4.4
More information about the cfe-dev
mailing list