From 65317e1ca0700fc124612cb6659679b6d8e73601 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 8 Jan 2019 22:32:51 +0000 Subject: [PATCH] [libclang] Recommit r336590 with a fix for the memory leak in the test The original commit had a memory leak in the test has a leak as it doesn't dispose of the evaluated cursor result. This also contains the follow-up NFC refactoring commit r336591. rdar://45893054 Original commit message: [libclang] evalute compound statement cursors before trying to evaluate the cursor like a declaration This change fixes 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. rdar://38888477 Differential Revision: https://reviews.llvm.org/D49051 llvm-svn: 350666 --- clang/tools/libclang/CIndex.cpp | 47 +++++++++++------------ clang/unittests/libclang/LibclangTest.cpp | 42 ++++++++++++++++++++ 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index bc791954fc71..15b2df84935e 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -3902,36 +3902,35 @@ static const ExprEvalResult* evaluateExpr(Expr *expr, CXCursor C) { return nullptr; } -CXEvalResult clang_Cursor_Evaluate(CXCursor C) { - const Decl *D = getCursorDecl(C); - if (D) { - const Expr *expr = nullptr; - if (auto *Var = dyn_cast(D)) { - expr = Var->getInit(); - } else if (auto *Field = dyn_cast(D)) { - expr = Field->getInClassInitializer(); - } - if (expr) - return const_cast(reinterpret_cast( - evaluateExpr(const_cast(expr), C))); +static const Expr *evaluateDeclExpr(const Decl *D) { + if (!D) return nullptr; - } + if (auto *Var = dyn_cast(D)) + return Var->getInit(); + else if (auto *Field = dyn_cast(D)) + return Field->getInClassInitializer(); + return nullptr; +} - const CompoundStmt *compoundStmt = dyn_cast_or_null(getCursorStmt(C)); - if (compoundStmt) { - Expr *expr = nullptr; - for (auto *bodyIterator : compoundStmt->body()) { - if ((expr = dyn_cast(bodyIterator))) { - break; - } - } - if (expr) - return const_cast( - reinterpret_cast(evaluateExpr(expr, C))); +static const Expr *evaluateCompoundStmtExpr(const CompoundStmt *CS) { + assert(CS && "invalid compound statement"); + for (auto *bodyIterator : CS->body()) { + if (const auto *E = dyn_cast(bodyIterator)) + return E; } return nullptr; } +CXEvalResult clang_Cursor_Evaluate(CXCursor C) { + if (const Expr *E = + clang_getCursorKind(C) == CXCursor_CompoundStmt + ? evaluateCompoundStmtExpr(cast(getCursorStmt(C))) + : evaluateDeclExpr(getCursorDecl(C))) + return const_cast( + reinterpret_cast(evaluateExpr(const_cast(E), C))); + return nullptr; +} + unsigned clang_Cursor_hasAttrs(CXCursor C) { const Decl *D = getCursorDecl(C); if (!D) { diff --git a/clang/unittests/libclang/LibclangTest.cpp b/clang/unittests/libclang/LibclangTest.cpp index 6fddcb2cbf26..b88b88dac338 100644 --- a/clang/unittests/libclang/LibclangTest.cpp +++ b/clang/unittests/libclang/LibclangTest.cpp @@ -461,6 +461,48 @@ TEST_F(LibclangParseTest, AllSkippedRanges) { 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); + clang_EvalResult_dispose(RE); + return CXChildVisit_Break; + } + numberedStmt++; + } + return CXChildVisit_Recurse; + }, + &numberedStmt); + EXPECT_EQ(numberedStmt, 1); + } + return CXChildVisit_Continue; + }, + nullptr); +} + class LibclangReparseTest : public LibclangParseTest { public: void DisplayDiagnostics() {