[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
This commit is contained in:
parent
b6d674f6fe
commit
65317e1ca0
|
@ -3902,36 +3902,35 @@ static const ExprEvalResult* evaluateExpr(Expr *expr, CXCursor C) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CXEvalResult clang_Cursor_Evaluate(CXCursor C) {
|
static const Expr *evaluateDeclExpr(const Decl *D) {
|
||||||
const Decl *D = getCursorDecl(C);
|
if (!D)
|
||||||
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;
|
return nullptr;
|
||||||
}
|
if (auto *Var = dyn_cast<VarDecl>(D))
|
||||||
|
return Var->getInit();
|
||||||
|
else if (auto *Field = dyn_cast<FieldDecl>(D))
|
||||||
|
return Field->getInClassInitializer();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
const CompoundStmt *compoundStmt = dyn_cast_or_null<CompoundStmt>(getCursorStmt(C));
|
static const Expr *evaluateCompoundStmtExpr(const CompoundStmt *CS) {
|
||||||
if (compoundStmt) {
|
assert(CS && "invalid compound statement");
|
||||||
Expr *expr = nullptr;
|
for (auto *bodyIterator : CS->body()) {
|
||||||
for (auto *bodyIterator : compoundStmt->body()) {
|
if (const auto *E = dyn_cast<Expr>(bodyIterator))
|
||||||
if ((expr = dyn_cast<Expr>(bodyIterator))) {
|
return E;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (expr)
|
|
||||||
return const_cast<CXEvalResult>(
|
|
||||||
reinterpret_cast<const void *>(evaluateExpr(expr, C)));
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CXEvalResult clang_Cursor_Evaluate(CXCursor C) {
|
||||||
|
if (const Expr *E =
|
||||||
|
clang_getCursorKind(C) == CXCursor_CompoundStmt
|
||||||
|
? evaluateCompoundStmtExpr(cast<CompoundStmt>(getCursorStmt(C)))
|
||||||
|
: evaluateDeclExpr(getCursorDecl(C)))
|
||||||
|
return const_cast<CXEvalResult>(
|
||||||
|
reinterpret_cast<const void *>(evaluateExpr(const_cast<Expr *>(E), C)));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned clang_Cursor_hasAttrs(CXCursor C) {
|
unsigned clang_Cursor_hasAttrs(CXCursor C) {
|
||||||
const Decl *D = getCursorDecl(C);
|
const Decl *D = getCursorDecl(C);
|
||||||
if (!D) {
|
if (!D) {
|
||||||
|
|
|
@ -461,6 +461,48 @@ TEST_F(LibclangParseTest, AllSkippedRanges) {
|
||||||
clang_disposeSourceRangeList(Ranges);
|
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 {
|
class LibclangReparseTest : public LibclangParseTest {
|
||||||
public:
|
public:
|
||||||
void DisplayDiagnostics() {
|
void DisplayDiagnostics() {
|
||||||
|
|
Loading…
Reference in New Issue