From: Alex Lorenz Date: Tue, 8 Jan 2019 22:32:51 +0000 (+0000) Subject: [libclang] Recommit r336590 with a fix for the memory leak in the test X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1551b66a72c6b7b669edb6807810556953511649;p=clang [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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@350666 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index bc791954fc..15b2df8493 100644 --- a/tools/libclang/CIndex.cpp +++ b/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/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp index 6fddcb2cbf..b88b88dac3 100644 --- a/unittests/libclang/LibclangTest.cpp +++ b/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() {