[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