arphaman created this revision.
arphaman added a reviewer: dexonsmith.

There's a bug in libclang in which it tries to evaluate a statement cursor as a 
declaration cursor, because that statement still has a pointer to the 
declaration parent. This patch fixes it.

rdar://38888477


Repository:
  rC Clang

https://reviews.llvm.org/D49051

Files:
  tools/libclang/CIndex.cpp
  unittests/libclang/LibclangTest.cpp


Index: unittests/libclang/LibclangTest.cpp
===================================================================
--- unittests/libclang/LibclangTest.cpp
+++ unittests/libclang/LibclangTest.cpp
@@ -461,6 +461,47 @@
   clang_disposeSourceRangeList(Ranges);
 }
 
+TEST_F(LibclangParseTest, EvaluateChildExpression) {
+  std::string Main = "main.m";
+  WriteFile(Main, "#define kFOO @\"foo\"\n"
+                  "void foobar(void) {\n"
+                  " {kFOO;}\n"
+                  "}\n");
+  ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, 
nullptr,
+                                       0, TUFlags);
+
+  CXCursor C = clang_getTranslationUnitCursor(ClangTU);
+  clang_visitChildren(
+      C,
+      [](CXCursor cursor, CXCursor parent,
+         CXClientData client_data) -> CXChildVisitResult {
+        if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) {
+          int numberedStmt = 0;
+          clang_visitChildren(
+              cursor,
+              [](CXCursor cursor, CXCursor parent,
+                 CXClientData client_data) -> CXChildVisitResult {
+                int &numberedStmt = *((int *)client_data);
+                if (clang_getCursorKind(cursor) == CXCursor_CompoundStmt) {
+                  if (numberedStmt) {
+                    CXEvalResult RE = clang_Cursor_Evaluate(cursor);
+                    EXPECT_NE(RE, nullptr);
+                    EXPECT_EQ(clang_EvalResult_getKind(RE),
+                              CXEval_ObjCStrLiteral);
+                    return CXChildVisit_Break;
+                  }
+                  numberedStmt++;
+                }
+                return CXChildVisit_Recurse;
+              },
+              &numberedStmt);
+          EXPECT_EQ(numberedStmt, 1);
+        }
+        return CXChildVisit_Continue;
+      },
+      nullptr);
+}
+
 class LibclangReparseTest : public LibclangParseTest {
 public:
   void DisplayDiagnostics() {
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -3890,18 +3890,20 @@
 }
 
 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 (clang_isDeclaration(C.kind)) {
+    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 const_cast<CXEvalResult>(reinterpret_cast<const void *>(
+            evaluateExpr(const_cast<Expr *>(expr), C)));
+      return nullptr;
     }
-    if (expr)
-      return const_cast<CXEvalResult>(reinterpret_cast<const void *>(
-          evaluateExpr(const_cast<Expr *>(expr), C)));
-    return nullptr;
   }
 
   const CompoundStmt *compoundStmt = 
dyn_cast_or_null<CompoundStmt>(getCursorStmt(C));


Index: unittests/libclang/LibclangTest.cpp
===================================================================
--- unittests/libclang/LibclangTest.cpp
+++ unittests/libclang/LibclangTest.cpp
@@ -461,6 +461,47 @@
   clang_disposeSourceRangeList(Ranges);
 }
 
+TEST_F(LibclangParseTest, EvaluateChildExpression) {
+  std::string Main = "main.m";
+  WriteFile(Main, "#define kFOO @\"foo\"\n"
+                  "void foobar(void) {\n"
+                  " {kFOO;}\n"
+                  "}\n");
+  ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,
+                                       0, TUFlags);
+
+  CXCursor C = clang_getTranslationUnitCursor(ClangTU);
+  clang_visitChildren(
+      C,
+      [](CXCursor cursor, CXCursor parent,
+         CXClientData client_data) -> CXChildVisitResult {
+        if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) {
+          int numberedStmt = 0;
+          clang_visitChildren(
+              cursor,
+              [](CXCursor cursor, CXCursor parent,
+                 CXClientData client_data) -> CXChildVisitResult {
+                int &numberedStmt = *((int *)client_data);
+                if (clang_getCursorKind(cursor) == CXCursor_CompoundStmt) {
+                  if (numberedStmt) {
+                    CXEvalResult RE = clang_Cursor_Evaluate(cursor);
+                    EXPECT_NE(RE, nullptr);
+                    EXPECT_EQ(clang_EvalResult_getKind(RE),
+                              CXEval_ObjCStrLiteral);
+                    return CXChildVisit_Break;
+                  }
+                  numberedStmt++;
+                }
+                return CXChildVisit_Recurse;
+              },
+              &numberedStmt);
+          EXPECT_EQ(numberedStmt, 1);
+        }
+        return CXChildVisit_Continue;
+      },
+      nullptr);
+}
+
 class LibclangReparseTest : public LibclangParseTest {
 public:
   void DisplayDiagnostics() {
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -3890,18 +3890,20 @@
 }
 
 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 (clang_isDeclaration(C.kind)) {
+    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 const_cast<CXEvalResult>(reinterpret_cast<const void *>(
+            evaluateExpr(const_cast<Expr *>(expr), C)));
+      return nullptr;
     }
-    if (expr)
-      return const_cast<CXEvalResult>(reinterpret_cast<const void *>(
-          evaluateExpr(const_cast<Expr *>(expr), C)));
-    return nullptr;
   }
 
   const CompoundStmt *compoundStmt = dyn_cast_or_null<CompoundStmt>(getCursorStmt(C));
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D49051: [l... Alex Lorenz via Phabricator via cfe-commits

Reply via email to