r257968 - [libclang] Introduce APIs for evaluating a cursor and checking if a macro is builtin/function.

Argyrios Kyrtzidis via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 15 16:20:03 PST 2016


Author: akirtzidis
Date: Fri Jan 15 18:20:02 2016
New Revision: 257968

URL: http://llvm.org/viewvc/llvm-project?rev=257968&view=rev
Log:
[libclang] Introduce APIs for evaluating a cursor and checking if a macro is builtin/function.

rdar://24091595

Added:
    cfe/trunk/test/Index/evaluate-cursor.cpp
Modified:
    cfe/trunk/include/clang-c/Index.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/tools/c-index-test/c-index-test.c
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/libclang.exports

Modified: cfe/trunk/include/clang-c/Index.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=257968&r1=257967&r2=257968&view=diff
==============================================================================
--- cfe/trunk/include/clang-c/Index.h (original)
+++ cfe/trunk/include/clang-c/Index.h Fri Jan 15 18:20:02 2016
@@ -32,7 +32,7 @@
  * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
  */
 #define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 32
+#define CINDEX_VERSION_MINOR 33
 
 #define CINDEX_VERSION_ENCODE(major, minor) ( \
       ((major) * 10000)                       \
@@ -2431,6 +2431,11 @@ CINDEX_LINKAGE unsigned clang_isStatemen
 CINDEX_LINKAGE unsigned clang_isAttribute(enum CXCursorKind);
 
 /**
+ * \brief Determine whether the given cursor has any attributes.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_hasAttrs(CXCursor C);
+
+/**
  * \brief Determine whether the given cursor kind represents an invalid
  * cursor.
  */
@@ -3170,6 +3175,24 @@ CINDEX_LINKAGE CXType clang_getCanonical
 CINDEX_LINKAGE unsigned clang_isConstQualifiedType(CXType T);
 
 /**
+ * \brief Determine whether a  CXCursor that is a macro, is
+ * function like.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_isMacroFunctionLike(CXCursor C);
+
+/**
+ * \brief Determine whether a  CXCursor that is a macro, is a
+ * builtin one.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_isMacroBuiltin(CXCursor C);
+
+/**
+ * \brief Determine whether a  CXCursor that is a function declaration, is an
+ * inline declaration.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_isFunctionInlined(CXCursor C);
+
+/**
  * \brief Determine whether a CXType has the "volatile" qualifier set,
  * without looking through typedefs that may have added "volatile" at
  * a different level.
@@ -3199,6 +3222,11 @@ CINDEX_LINKAGE CXCursor clang_getTypeDec
 CINDEX_LINKAGE CXString clang_getDeclObjCTypeEncoding(CXCursor C);
 
 /**
+ * Returns the Objective-C type encoding for the specified CXType.
+ */
+CINDEX_LINKAGE CXString clang_Type_getObjCEncoding(CXType type); 
+
+/**
  * \brief Retrieve the spelling of a given CXTypeKind.
  */
 CINDEX_LINKAGE CXString clang_getTypeKindSpelling(enum CXTypeKind K);
@@ -5077,6 +5105,59 @@ CINDEX_LINKAGE void clang_getInclusions(
                                         CXInclusionVisitor visitor,
                                         CXClientData client_data);
 
+typedef enum {
+  CXEval_Int = 1 ,
+  CXEval_Float = 2,
+  CXEval_ObjCStrLiteral = 3,
+  CXEval_StrLiteral = 4,
+  CXEval_CFStr = 5,
+  CXEval_Other = 6,
+
+  CXEval_UnExposed = 0
+
+} CXEvalResultKind ;
+
+/**
+ * \brief Evaluation result of a cursor
+ */
+typedef void * CXEvalResult;
+
+/**
+ * \brief If cursor is a statement declaration tries to evaluate the 
+ * statement and if its variable, tries to evaluate its initializer,
+ * into its corresponding type.
+ */
+CINDEX_LINKAGE CXEvalResult clang_Cursor_Evaluate(CXCursor C);
+
+/**
+ * \brief Returns the kind of the evaluated result.
+ */
+CXEvalResultKind clang_EvalResult_getKind(CXEvalResult E);
+
+/**
+ * \brief Returns the evaluation result as integer if the
+ * kind is Int.
+ */
+int clang_EvalResult_getAsInt(CXEvalResult E);
+
+/**
+ * \brief Returns the evaluation result as double if the
+ * kind is double.
+ */
+double clang_EvalResult_getAsDouble(CXEvalResult E);
+
+/**
+ * \brief Returns the evaluation result as a constant string if the
+ * kind is other than Int or float. User must not free this pointer,
+ * instead call clang_EvalResult_dispose on the CXEvalResult returned
+ * by clang_Cursor_Evaluate.
+ */
+const char* clang_EvalResult_getAsStr(CXEvalResult E);
+
+/**
+ * \brief Disposes the created Eval memory.
+ */
+void clang_EvalResult_dispose(CXEvalResult E);
 /**
  * @}
  */

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=257968&r1=257967&r2=257968&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Fri Jan 15 18:20:02 2016
@@ -5913,7 +5913,7 @@ void ASTContext::getObjCEncodingForStruc
                                                  QualType *NotEncodedT) const {
   assert(RDecl && "Expected non-null RecordDecl");
   assert(!RDecl->isUnion() && "Should not be called for unions");
-  if (!RDecl->getDefinition())
+  if (!RDecl->getDefinition() || RDecl->getDefinition()->isInvalidDecl())
     return;
 
   CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(RDecl);

Added: cfe/trunk/test/Index/evaluate-cursor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/evaluate-cursor.cpp?rev=257968&view=auto
==============================================================================
--- cfe/trunk/test/Index/evaluate-cursor.cpp (added)
+++ cfe/trunk/test/Index/evaluate-cursor.cpp Fri Jan 15 18:20:02 2016
@@ -0,0 +1,30 @@
+// Test is line- and column-sensitive. Run lines are below.
+
+struct Foo {
+  int x = 10;
+};
+
+void foo() {
+  int p = 11;
+}
+
+#define FUNC_MAC(x) x
+
+void goo() {
+  int p = FUNC_MAC(1);
+  int a = __LINE__;
+}
+
+// RUN: c-index-test -evaluate-cursor-at=%s:4:7 \
+// RUN:    -evaluate-cursor-at=%s:8:7 \
+// RUN:    -evaluate-cursor-at=%s:8:11 -std=c++11 %s | FileCheck %s
+// CHECK: Value: 10
+// CHECK: Value: 11
+// CHECK: Value: 11
+
+// RUN: c-index-test -get-macro-info-cursor-at=%s:11:9 \
+// RUN:    -get-macro-info-cursor-at=%s:14:11 \
+// RUN:    -get-macro-info-cursor-at=%s:15:11 -std=c++11 %s | FileCheck -check-prefix=CHECK-MACRO %s
+// CHECK-MACRO: [function macro]
+// CHECK-MACRO: [function macro]
+// CHECK-MACRO: [builtin macro]

Modified: cfe/trunk/tools/c-index-test/c-index-test.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/c-index-test/c-index-test.c?rev=257968&r1=257967&r2=257968&view=diff
==============================================================================
--- cfe/trunk/tools/c-index-test/c-index-test.c (original)
+++ cfe/trunk/tools/c-index-test/c-index-test.c Fri Jan 15 18:20:02 2016
@@ -2287,7 +2287,11 @@ typedef struct {
   unsigned column;
 } CursorSourceLocation;
 
-static int inspect_cursor_at(int argc, const char **argv) {
+typedef void (*cursor_handler_t)(CXCursor cursor);
+
+static int inspect_cursor_at(int argc, const char **argv,
+                             const char *locations_flag,
+                             cursor_handler_t handler) {
   CXIndex CIdx;
   int errorCode;
   struct CXUnsavedFile *unsaved_files = 0;
@@ -2301,7 +2305,7 @@ static int inspect_cursor_at(int argc, c
   unsigned I;
   
   /* Count the number of locations. */
-  while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1])
+  while (strstr(argv[NumLocations+1], locations_flag) == argv[NumLocations+1])
     ++NumLocations;
 
   /* Parse the locations. */
@@ -2309,7 +2313,7 @@ static int inspect_cursor_at(int argc, c
   Locations = (CursorSourceLocation *)malloc(
                                   NumLocations * sizeof(CursorSourceLocation));
   for (Loc = 0; Loc < NumLocations; ++Loc) {
-    const char *input = argv[Loc + 1] + strlen("-cursor-at=");
+    const char *input = argv[Loc + 1] + strlen(locations_flag);
     if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
                                             &Locations[Loc].line,
                                             &Locations[Loc].column, 0, 0)))
@@ -2368,72 +2372,7 @@ static int inspect_cursor_at(int argc, c
         return -1;
 
       if (I + 1 == Repeats) {
-        CXCompletionString completionString = clang_getCursorCompletionString(
-                                                                        Cursor);
-        CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
-        CXString Spelling;
-        const char *cspell;
-        unsigned line, column;
-        clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
-        printf("%d:%d ", line, column);
-        PrintCursor(Cursor, NULL);
-        PrintCursorExtent(Cursor);
-        Spelling = clang_getCursorSpelling(Cursor);
-        cspell = clang_getCString(Spelling);
-        if (cspell && strlen(cspell) != 0) {
-          unsigned pieceIndex;
-          printf(" Spelling=%s (", cspell);
-          for (pieceIndex = 0; ; ++pieceIndex) {
-            CXSourceRange range =
-              clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
-            if (clang_Range_isNull(range))
-              break;
-            PrintRange(range, 0);
-          }
-          printf(")");
-        }
-        clang_disposeString(Spelling);
-        if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
-          printf(" Selector index=%d",
-                 clang_Cursor_getObjCSelectorIndex(Cursor));
-        if (clang_Cursor_isDynamicCall(Cursor))
-          printf(" Dynamic-call");
-        if (Cursor.kind == CXCursor_ObjCMessageExpr) {
-          CXType T = clang_Cursor_getReceiverType(Cursor);
-          CXString S = clang_getTypeKindSpelling(T.kind);
-          printf(" Receiver-type=%s", clang_getCString(S));
-          clang_disposeString(S);
-        }
-
-        {
-          CXModule mod = clang_Cursor_getModule(Cursor);
-          CXFile astFile;
-          CXString name, astFilename;
-          unsigned i, numHeaders;
-          if (mod) {
-            astFile = clang_Module_getASTFile(mod);
-            astFilename = clang_getFileName(astFile);
-            name = clang_Module_getFullName(mod);
-            numHeaders = clang_Module_getNumTopLevelHeaders(TU, mod);
-            printf(" ModuleName=%s (%s) system=%d Headers(%d):",
-                   clang_getCString(name), clang_getCString(astFilename),
-                   clang_Module_isSystem(mod), numHeaders);
-            clang_disposeString(name);
-            clang_disposeString(astFilename);
-            for (i = 0; i < numHeaders; ++i) {
-              CXFile file = clang_Module_getTopLevelHeader(TU, mod, i);
-              CXString filename = clang_getFileName(file);
-              printf("\n%s", clang_getCString(filename));
-              clang_disposeString(filename);
-            }
-          }
-        }
-
-        if (completionString != NULL) {
-          printf("\nCompletion string: ");
-          print_completion_string(completionString, stdout);
-        }
-        printf("\n");
+        handler(Cursor);
         free(Locations[Loc].filename);
       }
     }
@@ -2447,6 +2386,184 @@ static int inspect_cursor_at(int argc, c
   return 0;
 }
 
+static void inspect_print_cursor(CXCursor Cursor) {
+  CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
+  CXCompletionString completionString = clang_getCursorCompletionString(
+                                                                  Cursor);
+  CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
+  CXString Spelling;
+  const char *cspell;
+  unsigned line, column;
+  clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
+  printf("%d:%d ", line, column);
+  PrintCursor(Cursor, NULL);
+  PrintCursorExtent(Cursor);
+  Spelling = clang_getCursorSpelling(Cursor);
+  cspell = clang_getCString(Spelling);
+  if (cspell && strlen(cspell) != 0) {
+    unsigned pieceIndex;
+    printf(" Spelling=%s (", cspell);
+    for (pieceIndex = 0; ; ++pieceIndex) {
+      CXSourceRange range =
+        clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
+      if (clang_Range_isNull(range))
+        break;
+      PrintRange(range, 0);
+    }
+    printf(")");
+  }
+  clang_disposeString(Spelling);
+  if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
+    printf(" Selector index=%d",
+           clang_Cursor_getObjCSelectorIndex(Cursor));
+  if (clang_Cursor_isDynamicCall(Cursor))
+    printf(" Dynamic-call");
+  if (Cursor.kind == CXCursor_ObjCMessageExpr) {
+    CXType T = clang_Cursor_getReceiverType(Cursor);
+    CXString S = clang_getTypeKindSpelling(T.kind);
+    printf(" Receiver-type=%s", clang_getCString(S));
+    clang_disposeString(S);
+  }
+
+  {
+    CXModule mod = clang_Cursor_getModule(Cursor);
+    CXFile astFile;
+    CXString name, astFilename;
+    unsigned i, numHeaders;
+    if (mod) {
+      astFile = clang_Module_getASTFile(mod);
+      astFilename = clang_getFileName(astFile);
+      name = clang_Module_getFullName(mod);
+      numHeaders = clang_Module_getNumTopLevelHeaders(TU, mod);
+      printf(" ModuleName=%s (%s) system=%d Headers(%d):",
+             clang_getCString(name), clang_getCString(astFilename),
+             clang_Module_isSystem(mod), numHeaders);
+      clang_disposeString(name);
+      clang_disposeString(astFilename);
+      for (i = 0; i < numHeaders; ++i) {
+        CXFile file = clang_Module_getTopLevelHeader(TU, mod, i);
+        CXString filename = clang_getFileName(file);
+        printf("\n%s", clang_getCString(filename));
+        clang_disposeString(filename);
+      }
+    }
+  }
+
+  if (completionString != NULL) {
+    printf("\nCompletion string: ");
+    print_completion_string(completionString, stdout);
+  }
+  printf("\n");
+}
+
+static void display_evaluate_results(CXEvalResult result) {
+  switch (clang_EvalResult_getKind(result)) {
+    case CXEval_Int:
+    {
+      int val = clang_EvalResult_getAsInt(result);
+      printf("Kind: Int , Value: %d", val);
+      break;
+    }
+    case CXEval_Float:
+    {
+      double val = clang_EvalResult_getAsDouble(result);
+      printf("Kind: Float , Value: %f", val);
+      break;
+    }
+    case CXEval_ObjCStrLiteral:
+    {
+      const char* str = clang_EvalResult_getAsStr(result);
+      printf("Kind: ObjCString , Value: %s", str);
+      break;
+    }
+    case CXEval_StrLiteral:
+    {
+      const char* str = clang_EvalResult_getAsStr(result);
+      printf("Kind: CString , Value: %s", str);
+      break;
+    }
+    case CXEval_CFStr:
+    {
+      const char* str = clang_EvalResult_getAsStr(result);
+      printf("Kind: CFString , Value: %s", str);
+      break;
+    }
+    default:
+      printf("Unexposed");
+      break;
+    }
+}
+
+static void inspect_evaluate_cursor(CXCursor Cursor) {
+  CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
+  CXString Spelling;
+  const char *cspell;
+  unsigned line, column;
+  CXEvalResult ER;
+
+  clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
+  printf("%d:%d ", line, column);
+  PrintCursor(Cursor, NULL);
+  PrintCursorExtent(Cursor);
+  Spelling = clang_getCursorSpelling(Cursor);
+  cspell = clang_getCString(Spelling);
+  if (cspell && strlen(cspell) != 0) {
+    unsigned pieceIndex;
+    printf(" Spelling=%s (", cspell);
+    for (pieceIndex = 0; ; ++pieceIndex) {
+      CXSourceRange range =
+         clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
+      if (clang_Range_isNull(range))
+        break;
+      PrintRange(range, 0);
+    }
+    printf(")");
+  }
+  clang_disposeString(Spelling);
+
+  ER = clang_Cursor_Evaluate(Cursor);
+  if (!ER) {
+    printf("Not Evaluatable");
+  } else {
+    display_evaluate_results(ER);
+    clang_EvalResult_dispose(ER);
+  }
+  printf("\n");
+}
+
+static void inspect_macroinfo_cursor(CXCursor Cursor) {
+  CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
+  CXString Spelling;
+  const char *cspell;
+  unsigned line, column;
+  clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
+  printf("%d:%d ", line, column);
+  PrintCursor(Cursor, NULL);
+  PrintCursorExtent(Cursor);
+  Spelling = clang_getCursorSpelling(Cursor);
+  cspell = clang_getCString(Spelling);
+  if (cspell && strlen(cspell) != 0) {
+    unsigned pieceIndex;
+    printf(" Spelling=%s (", cspell);
+    for (pieceIndex = 0; ; ++pieceIndex) {
+      CXSourceRange range =
+         clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
+      if (clang_Range_isNull(range))
+        break;
+      PrintRange(range, 0);
+    }
+    printf(")");
+  }
+  clang_disposeString(Spelling);
+
+  if (clang_Cursor_isMacroBuiltin(Cursor)) {
+    printf("[builtin macro]");
+  } else if (clang_Cursor_isMacroFunctionLike(Cursor)) {
+    printf("[function macro]");
+  }
+  printf("\n");
+}
+
 static enum CXVisitorResult findFileRefsVisit(void *context,
                                          CXCursor cursor, CXSourceRange range) {
   if (clang_Range_isNull(range))
@@ -4121,6 +4238,8 @@ static void print_usage(void) {
     "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
     "       c-index-test -code-completion-timing=<site> <compiler arguments>\n"
     "       c-index-test -cursor-at=<site> <compiler arguments>\n"
+    "       c-index-test -evaluate-cursor-at=<site> <compiler arguments>\n"
+    "       c-index-test -get-macro-info-cursor-at=<site> <compiler arguments>\n"
     "       c-index-test -file-refs-at=<site> <compiler arguments>\n"
     "       c-index-test -file-includes-in=<filename> <compiler arguments>\n");
   fprintf(stderr,
@@ -4186,7 +4305,13 @@ int cindextest_main(int argc, const char
   if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1])
     return perform_code_completion(argc, argv, 1);
   if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
-    return inspect_cursor_at(argc, argv);
+    return inspect_cursor_at(argc, argv, "-cursor-at=", inspect_print_cursor);
+  if (argc > 2 && strstr(argv[1], "-evaluate-cursor-at=") == argv[1])
+    return inspect_cursor_at(argc, argv, "-evaluate-cursor-at=",
+                             inspect_evaluate_cursor);
+  if (argc > 2 && strstr(argv[1], "-get-macro-info-cursor-at=") == argv[1])
+    return inspect_cursor_at(argc, argv, "-get-macro-info-cursor-at=",
+                             inspect_macroinfo_cursor);
   if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
     return find_file_refs_at(argc, argv);
   if (argc > 2 && strstr(argv[1], "-file-includes-in=") == argv[1])

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=257968&r1=257967&r2=257968&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Fri Jan 15 18:20:02 2016
@@ -3289,6 +3289,329 @@ enum CXErrorCode clang_parseTranslationU
   return result;
 }
 
+CXString clang_Type_getObjCEncoding(CXType CT) {
+  CXTranslationUnit tu = static_cast<CXTranslationUnit>(CT.data[1]);
+  ASTContext &Ctx = getASTUnit(tu)->getASTContext();
+  std::string encoding;
+  Ctx.getObjCEncodingForType(QualType::getFromOpaquePtr(CT.data[0]),
+                             encoding);
+
+  return cxstring::createDup(encoding);
+}
+
+static const IdentifierInfo *getMacroIdentifier(CXCursor C) {
+  if (C.kind == CXCursor_MacroDefinition) {
+    if (const MacroDefinitionRecord *MDR = getCursorMacroDefinition(C))
+      return MDR->getName();
+  } else if (C.kind == CXCursor_MacroExpansion) {
+    MacroExpansionCursor ME = getCursorMacroExpansion(C);
+    return ME.getName();
+  }
+  return nullptr;
+}
+
+unsigned clang_Cursor_isMacroFunctionLike(CXCursor C) {
+  const IdentifierInfo *II = getMacroIdentifier(C);
+  if (!II) {
+    return false;
+  }
+  ASTUnit *ASTU = getCursorASTUnit(C);
+  Preprocessor &PP = ASTU->getPreprocessor();
+  if (const MacroInfo *MI = PP.getMacroInfo(II))
+    return MI->isFunctionLike();
+  return false;
+}
+
+unsigned clang_Cursor_isMacroBuiltin(CXCursor C) {
+  const IdentifierInfo *II = getMacroIdentifier(C);
+  if (!II) {
+    return false;
+  }
+  ASTUnit *ASTU = getCursorASTUnit(C);
+  Preprocessor &PP = ASTU->getPreprocessor();
+  if (const MacroInfo *MI = PP.getMacroInfo(II))
+    return MI->isBuiltinMacro();
+  return false;
+}
+
+unsigned clang_Cursor_isFunctionInlined(CXCursor C) {
+  const Decl *D = getCursorDecl(C);
+  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
+  if (!FD) {
+    return false;
+  }
+  return FD->isInlined();
+}
+
+static StringLiteral* getCFSTR_value(CallExpr *callExpr) {
+  if (callExpr->getNumArgs() != 1) {
+    return nullptr;
+  }
+
+  StringLiteral *S = nullptr;
+  auto *arg = callExpr->getArg(0);
+  if (arg->getStmtClass() == Stmt::ImplicitCastExprClass) {
+    ImplicitCastExpr *I = static_cast<ImplicitCastExpr *>(arg);
+    auto *subExpr = I->getSubExprAsWritten();
+
+    if(subExpr->getStmtClass() != Stmt::StringLiteralClass){
+      return nullptr;
+    }
+
+    S = static_cast<StringLiteral *>(I->getSubExprAsWritten());
+  } else if (arg->getStmtClass() == Stmt::StringLiteralClass) {
+    S = static_cast<StringLiteral *>(callExpr->getArg(0));
+  } else {
+    return nullptr;
+  }
+  return S;
+}
+
+typedef struct {
+  CXEvalResultKind EvalType;
+  union {
+    int intVal;
+    double floatVal;
+    char *stringVal;
+  } EvalData;
+} ExprEvalResult;
+
+void clang_EvalResult_dispose(CXEvalResult E) {
+  ExprEvalResult *ER = (ExprEvalResult *)E;
+  if (ER) {
+    CXEvalResultKind evalType = ER->EvalType;
+
+    if (evalType != CXEval_UnExposed &&  evalType != CXEval_Float &&
+            evalType != CXEval_Int && ER->EvalData.stringVal) {
+            free((void *) ER->EvalData.stringVal);
+    }
+    free((void *)ER);
+  }
+}
+
+CXEvalResultKind clang_EvalResult_getKind(CXEvalResult E) {
+  if (!E) {
+    return CXEval_UnExposed;
+  }
+  return ((ExprEvalResult *)E)->EvalType;
+}
+
+int clang_EvalResult_getAsInt(CXEvalResult E) {
+  if (!E) {
+    return 0;
+  }
+  return ((ExprEvalResult *)E)->EvalData.intVal;
+}
+
+double clang_EvalResult_getAsDouble(CXEvalResult E) {
+  if (!E) {
+    return 0;
+  }
+  return ((ExprEvalResult *)E)->EvalData.floatVal;
+}
+
+const char* clang_EvalResult_getAsStr(CXEvalResult E) {
+  if (!E) {
+    return nullptr;
+  }
+  return ((ExprEvalResult *)E)->EvalData.stringVal;
+}
+
+static const ExprEvalResult* evaluateExpr(Expr *expr, CXCursor C) {
+  Expr::EvalResult ER;
+  ASTContext &ctx = getCursorContext(C);
+  if (!expr) {
+    return nullptr;
+  }
+  expr = expr->IgnoreParens();
+  bool res = expr->EvaluateAsRValue(ER, ctx);
+  QualType rettype;
+  CallExpr *callExpr;
+  ExprEvalResult *result = (ExprEvalResult *) malloc(sizeof(ExprEvalResult));
+  if (!result) {
+    return nullptr;
+  }
+  result->EvalType = CXEval_UnExposed;
+
+  if (res) {
+
+    if (ER.Val.isInt()) {
+      result->EvalType = CXEval_Int;
+      result->EvalData.intVal = ER.Val.getInt().getExtValue();
+      return result;
+    } else if (ER.Val.isFloat()) {
+
+      llvm::SmallVector<char, 100> Buffer;
+      ER.Val.getFloat().toString(Buffer);
+      std::string floatStr(Buffer.data(), Buffer.size());
+      result->EvalType = CXEval_Float;
+      bool ignored;
+      llvm::APFloat apFloat = ER.Val.getFloat();
+      apFloat.convert(llvm::APFloat::IEEEdouble,
+                      llvm::APFloat::rmNearestTiesToEven, &ignored);
+      result->EvalData.floatVal = apFloat.convertToDouble();
+      return result;
+
+    } else if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {
+
+      const ImplicitCastExpr *I = dyn_cast<ImplicitCastExpr>(expr);
+      auto *subExpr = I->getSubExprAsWritten();
+      if (subExpr->getStmtClass() == Stmt::StringLiteralClass ||
+          subExpr->getStmtClass() == Stmt::ObjCStringLiteralClass) {
+
+        const StringLiteral *StrE = nullptr;
+        const ObjCStringLiteral *ObjCExpr;
+        ObjCExpr = dyn_cast<ObjCStringLiteral>(subExpr);
+
+        if (ObjCExpr) {
+          StrE = ObjCExpr->getString();
+          result->EvalType = CXEval_ObjCStrLiteral;
+        } else {
+          StrE = cast<StringLiteral>(I->getSubExprAsWritten());
+          result->EvalType = CXEval_StrLiteral;
+        }
+
+        std::string strRef(StrE->getString().str());
+        result->EvalData.stringVal = (char *)malloc(strRef.size()+1);
+        strncpy((char*)result->EvalData.stringVal, strRef.c_str(),
+                   strRef.size());
+        result->EvalData.stringVal[strRef.size()] = '\0';
+        return result;
+      }
+
+    } else if (expr->getStmtClass() == Stmt::ObjCStringLiteralClass ||
+             expr->getStmtClass() == Stmt::StringLiteralClass) {
+
+      const StringLiteral *StrE = nullptr;
+      const ObjCStringLiteral *ObjCExpr;
+      ObjCExpr = dyn_cast<ObjCStringLiteral>(expr);
+
+      if (ObjCExpr) {
+        StrE = ObjCExpr->getString();
+        result->EvalType = CXEval_ObjCStrLiteral;
+      } else {
+        StrE = cast<StringLiteral>(expr);
+        result->EvalType = CXEval_StrLiteral;
+      }
+
+      std::string strRef(StrE->getString().str());
+      result->EvalData.stringVal = (char *)malloc(strRef.size()+1);
+      strncpy((char*)result->EvalData.stringVal, strRef.c_str(),
+                  strRef.size());
+      result->EvalData.stringVal[strRef.size()] = '\0';
+      return result;
+
+    } else if (expr->getStmtClass() == Stmt::CStyleCastExprClass) {
+
+      CStyleCastExpr *CC = static_cast<CStyleCastExpr *>(expr);
+
+      rettype = CC->getType();
+      if (rettype.getAsString() == "CFStringRef" &&
+            CC->getSubExpr()->getStmtClass() == Stmt::CallExprClass) {
+
+        callExpr = static_cast<CallExpr *>(CC->getSubExpr());
+        StringLiteral* S = getCFSTR_value(callExpr);
+        if (S) {
+          std::string strLiteral(S->getString().str());
+          result->EvalType = CXEval_CFStr;
+
+          result->EvalData.stringVal = (char *)malloc(strLiteral.size()+1);
+          strncpy((char*)result->EvalData.stringVal, strLiteral.c_str(),
+                     strLiteral.size());
+          result->EvalData.stringVal[strLiteral.size()] = '\0';
+          return result;
+        }
+      }
+
+    } else if (expr->getStmtClass() == Stmt::CallExprClass) {
+
+      callExpr = static_cast<CallExpr *>(expr);
+      rettype = callExpr->getCallReturnType(ctx);
+
+      if (rettype->isVectorType() || callExpr->getNumArgs() > 1) {
+        return nullptr;
+      }
+      if (rettype->isIntegralType(ctx) || rettype->isRealFloatingType()) {
+        if(callExpr->getNumArgs() == 1 &&
+              !callExpr->getArg(0)->getType()->isIntegralType(ctx)){
+
+          return nullptr;
+        }
+      } else if(rettype.getAsString() == "CFStringRef") {
+
+        StringLiteral* S = getCFSTR_value(callExpr);
+        if (S) {
+          std::string strLiteral(S->getString().str());
+          result->EvalType = CXEval_CFStr;
+          result->EvalData.stringVal = (char *)malloc(strLiteral.size()+1);
+          strncpy((char*)result->EvalData.stringVal, strLiteral.c_str(),
+                     strLiteral.size());
+          result->EvalData.stringVal[strLiteral.size()] = '\0';
+          return result;
+        }
+      }
+
+    } else if (expr->getStmtClass() == Stmt::DeclRefExprClass) {
+
+      DeclRefExpr *D = static_cast<DeclRefExpr *>(expr);
+      ValueDecl *V = D->getDecl();
+      if (V->getKind() == Decl::Function) {
+        std::string strName(V->getNameAsString());
+        result->EvalType = CXEval_Other;
+        result->EvalData.stringVal = (char *)malloc(strName.size()+1);
+        strncpy((char*)result->EvalData.stringVal, strName.c_str(),
+                   strName.size());
+        result->EvalData.stringVal[strName.size()] = '\0';
+        return result;
+      }
+    }
+
+  }
+
+  clang_EvalResult_dispose((CXEvalResult *)result);
+  return nullptr;
+}
+
+CXEvalResult clang_Cursor_Evaluate(CXCursor C) {
+  const Decl *D = getCursorDecl(C);
+  if (D) {
+    const Expr *expr = nullptr;
+    if (auto *Var = dyn_cast<VarDecl>(D)) {
+      expr = Var->getInit();
+    } else if (auto *Field = dyn_cast<FieldDecl>(D)) {
+      expr = Field->getInClassInitializer();
+    }
+    if (expr)
+      return (CXEvalResult)evaluateExpr((Expr *)expr, C);
+    return nullptr;
+  }
+
+  const CompoundStmt *compoundStmt = dyn_cast_or_null<CompoundStmt>(getCursorStmt(C));
+  if (compoundStmt) {
+    Expr *expr = nullptr;
+    for (auto *bodyIterator : compoundStmt->body()) {
+      if ((expr = dyn_cast<Expr>(bodyIterator))) {
+        break;
+      }
+    }
+    if (expr)
+      return (CXEvalResult)evaluateExpr(expr, C);
+  }
+  return nullptr;
+}
+
+unsigned clang_Cursor_hasAttrs(CXCursor C) {
+  const Decl *D = getCursorDecl(C);
+  if (!D) {
+    return 0;
+  }
+
+  if (D->hasAttrs()) {
+    return 1;
+  }
+
+  return 0;
+}
 unsigned clang_defaultSaveOptions(CXTranslationUnit TU) {
   return CXSaveTranslationUnit_None;
 }  

Modified: cfe/trunk/tools/libclang/libclang.exports
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/libclang.exports?rev=257968&r1=257967&r2=257968&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/libclang.exports (original)
+++ cfe/trunk/tools/libclang/libclang.exports Fri Jan 15 18:20:02 2016
@@ -320,3 +320,14 @@ clang_VirtualFileOverlay_create
 clang_VirtualFileOverlay_dispose
 clang_VirtualFileOverlay_setCaseSensitivity
 clang_VirtualFileOverlay_writeToBuffer
+clang_Type_getObjCEncoding
+clang_Cursor_isMacroFunctionLike
+clang_Cursor_isMacroBuiltin
+clang_Cursor_isFunctionInlined
+clang_Cursor_hasAttrs
+clang_Cursor_Evaluate
+clang_EvalResult_getKind
+clang_EvalResult_getAsInt
+clang_EvalResult_getAsDouble
+clang_EvalResult_getAsStr
+clang_EvalResult_dispose




More information about the cfe-commits mailing list