BartmanAbyss created this revision.
BartmanAbyss added reviewers: klimek, rsmith, akyrtzi.
BartmanAbyss added projects: clang-c, clang.
Herald added a subscriber: arphaman.
BartmanAbyss requested review of this revision.
Herald added a subscriber: cfe-commits.
This allows evaluating array initializer such as
int array[4]{1, 2, 3, 4};
const char* str[2]{ "hello", "world" };
Adds `CXEval_Array` to the `CXEvalResultKind` enum,
`clang_EvalResult_getArraySize()`, `clang_EvalResult_getArrayElt`
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D120061
Files:
clang/include/clang-c/Index.h
clang/test/Index/evaluate-cursor.cpp
clang/tools/c-index-test/c-index-test.c
clang/tools/libclang/CIndex.cpp
Index: clang/tools/libclang/CIndex.cpp
===================================================================
--- clang/tools/libclang/CIndex.cpp
+++ clang/tools/libclang/CIndex.cpp
@@ -3900,10 +3900,16 @@
long long intVal;
double floatVal;
char *stringVal;
+ struct {
+ ExprEvalResult *elts;
+ unsigned size;
+ } arrayVal;
} EvalData;
bool IsUnsignedInt;
~ExprEvalResult() {
- if (EvalType != CXEval_UnExposed && EvalType != CXEval_Float &&
+ if (EvalType == CXEval_Array) {
+ delete[] EvalData.arrayVal.elts;
+ } else if (EvalType != CXEval_UnExposed && EvalType != CXEval_Float &&
EvalType != CXEval_Int) {
delete[] EvalData.stringVal;
}
@@ -3964,51 +3970,75 @@
return ((ExprEvalResult *)E)->EvalData.stringVal;
}
-static const ExprEvalResult *evaluateExpr(Expr *expr, CXCursor C) {
- Expr::EvalResult ER;
- ASTContext &ctx = getCursorContext(C);
- if (!expr)
- return nullptr;
+unsigned clang_EvalResult_getArraySize(CXEvalResult E) {
+ if (!E || ((ExprEvalResult *)E)->EvalType != CXEval_Array) {
+ return 0;
+ }
+ return ((ExprEvalResult *)E)->EvalData.arrayVal.size;
+}
- expr = expr->IgnoreParens();
- if (expr->isValueDependent())
- return nullptr;
- if (!expr->EvaluateAsRValue(ER, ctx))
- return nullptr;
+CXEvalResult clang_EvalResult_getArrayElt(CXEvalResult E, unsigned index) {
+ if (E && ((ExprEvalResult *)E)->EvalType == CXEval_Array &&
+ index < ((ExprEvalResult *)E)->EvalData.arrayVal.size) {
+ return &((ExprEvalResult *)E)->EvalData.arrayVal.elts[index];
+ }
+ return nullptr;
+}
- QualType rettype;
- CallExpr *callExpr;
- auto result = std::make_unique<ExprEvalResult>();
- result->EvalType = CXEval_UnExposed;
- result->IsUnsignedInt = false;
+static bool evaluateVal(const APValue &val, ExprEvalResult &result) {
+ result.EvalType = CXEval_UnExposed;
+ result.IsUnsignedInt = false;
+
+ if (val.isArray()) {
+ result.EvalType = CXEval_Array;
+ result.EvalData.arrayVal.size = val.getArrayInitializedElts();
+ result.EvalData.arrayVal.elts =
+ new ExprEvalResult[result.EvalData.arrayVal.size];
+ bool ret = true;
+ for (unsigned i = 0; i < result.EvalData.arrayVal.size; i++) {
+ if (!evaluateVal(val.getArrayInitializedElt(i),
+ result.EvalData.arrayVal.elts[i])) {
+ ret = false;
+ }
+ }
- if (ER.Val.isInt()) {
- result->EvalType = CXEval_Int;
+ return ret;
+ }
- auto &val = ER.Val.getInt();
- if (val.isUnsigned()) {
- result->IsUnsignedInt = true;
- result->EvalData.unsignedVal = val.getZExtValue();
+ if (val.isInt()) {
+ result.EvalType = CXEval_Int;
+
+ auto &ival = val.getInt();
+ if (ival.isUnsigned()) {
+ result.IsUnsignedInt = true;
+ result.EvalData.unsignedVal = ival.getZExtValue();
} else {
- result->EvalData.intVal = val.getExtValue();
+ result.EvalData.intVal = ival.getExtValue();
}
- return result.release();
+ return true;
}
- if (ER.Val.isFloat()) {
+ if (val.isFloat()) {
llvm::SmallVector<char, 100> Buffer;
- ER.Val.getFloat().toString(Buffer);
+ val.getFloat().toString(Buffer);
std::string floatStr(Buffer.data(), Buffer.size());
- result->EvalType = CXEval_Float;
+ result.EvalType = CXEval_Float;
bool ignored;
- llvm::APFloat apFloat = ER.Val.getFloat();
+ llvm::APFloat apFloat = val.getFloat();
apFloat.convert(llvm::APFloat::IEEEdouble(),
llvm::APFloat::rmNearestTiesToEven, &ignored);
- result->EvalData.floatVal = apFloat.convertToDouble();
- return result.release();
+ result.EvalData.floatVal = apFloat.convertToDouble();
+ return true;
}
+ return false;
+}
+
+static bool evaluateStringExpr(Expr *expr, ASTContext &ctx, ExprEvalResult &result) {
+ QualType rettype;
+ CallExpr *callExpr;
+
if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {
const ImplicitCastExpr *I = dyn_cast<ImplicitCastExpr>(expr);
auto *subExpr = I->getSubExprAsWritten();
@@ -4020,18 +4050,18 @@
if (ObjCExpr) {
StrE = ObjCExpr->getString();
- result->EvalType = CXEval_ObjCStrLiteral;
+ result.EvalType = CXEval_ObjCStrLiteral;
} else {
StrE = cast<StringLiteral>(I->getSubExprAsWritten());
- result->EvalType = CXEval_StrLiteral;
+ result.EvalType = CXEval_StrLiteral;
}
std::string strRef(StrE->getString().str());
- result->EvalData.stringVal = new char[strRef.size() + 1];
- strncpy((char *)result->EvalData.stringVal, strRef.c_str(),
+ result.EvalData.stringVal = new char[strRef.size() + 1];
+ strncpy((char *)result.EvalData.stringVal, strRef.c_str(),
strRef.size());
- result->EvalData.stringVal[strRef.size()] = '\0';
- return result.release();
+ result.EvalData.stringVal[strRef.size()] = '\0';
+ return true;
}
} else if (expr->getStmtClass() == Stmt::ObjCStringLiteralClass ||
expr->getStmtClass() == Stmt::StringLiteralClass) {
@@ -4041,17 +4071,17 @@
if (ObjCExpr) {
StrE = ObjCExpr->getString();
- result->EvalType = CXEval_ObjCStrLiteral;
+ result.EvalType = CXEval_ObjCStrLiteral;
} else {
StrE = cast<StringLiteral>(expr);
- result->EvalType = CXEval_StrLiteral;
+ result.EvalType = CXEval_StrLiteral;
}
std::string strRef(StrE->getString().str());
- result->EvalData.stringVal = new char[strRef.size() + 1];
- strncpy((char *)result->EvalData.stringVal, strRef.c_str(), strRef.size());
- result->EvalData.stringVal[strRef.size()] = '\0';
- return result.release();
+ result.EvalData.stringVal = new char[strRef.size() + 1];
+ strncpy((char *)result.EvalData.stringVal, strRef.c_str(), strRef.size());
+ result.EvalData.stringVal[strRef.size()] = '\0';
+ return true;
}
if (expr->getStmtClass() == Stmt::CStyleCastExprClass) {
@@ -4065,13 +4095,13 @@
StringLiteral *S = getCFSTR_value(callExpr);
if (S) {
std::string strLiteral(S->getString().str());
- result->EvalType = CXEval_CFStr;
+ result.EvalType = CXEval_CFStr;
- result->EvalData.stringVal = new char[strLiteral.size() + 1];
- strncpy((char *)result->EvalData.stringVal, strLiteral.c_str(),
+ result.EvalData.stringVal = new char[strLiteral.size() + 1];
+ strncpy((char *)result.EvalData.stringVal, strLiteral.c_str(),
strLiteral.size());
- result->EvalData.stringVal[strLiteral.size()] = '\0';
- return result.release();
+ result.EvalData.stringVal[strLiteral.size()] = '\0';
+ return true;
}
}
@@ -4080,23 +4110,23 @@
rettype = callExpr->getCallReturnType(ctx);
if (rettype->isVectorType() || callExpr->getNumArgs() > 1)
- return nullptr;
+ return false;
if (rettype->isIntegralType(ctx) || rettype->isRealFloatingType()) {
if (callExpr->getNumArgs() == 1 &&
!callExpr->getArg(0)->getType()->isIntegralType(ctx))
- return nullptr;
+ return false;
} 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 = new char[strLiteral.size() + 1];
- strncpy((char *)result->EvalData.stringVal, strLiteral.c_str(),
+ result.EvalType = CXEval_CFStr;
+ result.EvalData.stringVal = new char[strLiteral.size() + 1];
+ strncpy((char *)result.EvalData.stringVal, strLiteral.c_str(),
strLiteral.size());
- result->EvalData.stringVal[strLiteral.size()] = '\0';
- return result.release();
+ result.EvalData.stringVal[strLiteral.size()] = '\0';
+ return true;
}
}
} else if (expr->getStmtClass() == Stmt::DeclRefExprClass) {
@@ -4104,14 +4134,53 @@
ValueDecl *V = D->getDecl();
if (V->getKind() == Decl::Function) {
std::string strName = V->getNameAsString();
- result->EvalType = CXEval_Other;
- result->EvalData.stringVal = new char[strName.size() + 1];
- strncpy(result->EvalData.stringVal, strName.c_str(), strName.size());
- result->EvalData.stringVal[strName.size()] = '\0';
+ result.EvalType = CXEval_Other;
+ result.EvalData.stringVal = new char[strName.size() + 1];
+ strncpy(result.EvalData.stringVal, strName.c_str(), strName.size());
+ result.EvalData.stringVal[strName.size()] = '\0';
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static const ExprEvalResult *evaluateExpr(Expr *expr, CXCursor C) {
+ Expr::EvalResult ER;
+ ASTContext &ctx = getCursorContext(C);
+ if (!expr)
+ return nullptr;
+
+ expr = expr->IgnoreParens();
+ if (expr->isValueDependent())
+ return nullptr;
+ if (!expr->EvaluateAsRValue(ER, ctx))
+ return nullptr;
+
+ auto result = std::make_unique<ExprEvalResult>();
+ if (evaluateVal(ER.Val, *result)) {
+ return result.release();
+ }
+
+ if (expr->getStmtClass() == Stmt::InitListExprClass) {
+ const InitListExpr *I = dyn_cast<InitListExpr>(expr);
+ // evaluateVal() has already determined that we have CXEval_Array, but some
+ // evaluations failed (because they are not CXEval_Int, CXEval_Float, etc.)
+ // so try evaluating the elements as strings
+ if (result->EvalType == CXEval_Array &&
+ result->EvalData.arrayVal.size >= I->getNumInits()) {
+ for (unsigned i = 0; i < I->getNumInits(); i++) {
+ evaluateStringExpr(const_cast<Expr *>(I->getInit(i)), ctx,
+ result->EvalData.arrayVal.elts[i]);
+ }
return result.release();
}
}
+ if (evaluateStringExpr(expr, ctx, *result)) {
+ return result.release();
+ }
+
return nullptr;
}
Index: clang/tools/c-index-test/c-index-test.c
===================================================================
--- clang/tools/c-index-test/c-index-test.c
+++ clang/tools/c-index-test/c-index-test.c
@@ -3019,6 +3019,20 @@
printf("Kind: CFString , Value: %s", str);
break;
}
+ case CXEval_Array:
+ {
+ printf("Kind: Array , Value: { ");
+ for (unsigned i = 0; i < clang_EvalResult_getArraySize(result); i++) {
+ if (i > 0) {
+ printf(" , ");
+ }
+ printf("[%d]: { ", i);
+ display_evaluate_results(clang_EvalResult_getArrayElt(result, i));
+ printf(" }");
+ }
+ printf(" }");
+ break;
+ }
default:
printf("Unexposed");
break;
Index: clang/test/Index/evaluate-cursor.cpp
===================================================================
--- clang/test/Index/evaluate-cursor.cpp
+++ clang/test/Index/evaluate-cursor.cpp
@@ -35,6 +35,11 @@
[&arr] {};
}
+class z {
+ int array[4]{1, 2, 3, 4};
+ const char* str[2]{ "hello", "world" };
+};
+
// 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
@@ -75,3 +80,15 @@
// RUN: c-index-test -evaluate-cursor-at=%s:35:5 \
// RUN: -std=c++11 %s | FileCheck -check-prefix=VLA %s
// VLA: Not Evaluatable
+
+// RUN: c-index-test -evaluate-cursor-at=%s:39:9 \
+// RUN: -std=c++11 %s | FileCheck -check-prefix=CHECK-ARRAY %s
+// CHECK-ARRAY: [0]: { Kind: Int, Value: 1 }
+// CHECK-ARRAY: [1]: { Kind: Int, Value: 2 }
+// CHECK-ARRAY: [2]: { Kind: Int, Value: 3 }
+// CHECK-ARRAY: [3]: { Kind: Int, Value: 4 }
+
+// RUN: c-index-test -evaluate-cursor-at=%s:40:15 \
+// RUN: -std=c++11 %s | FileCheck -check-prefix=CHECK-ARRAY-STR %s
+// CHECK-ARRAY-STR: [0]: { Kind: CString , Value: hello }
+// CHECK-ARRAY-STR: [1]: { Kind: CString , Value: world }
Index: clang/include/clang-c/Index.h
===================================================================
--- clang/include/clang-c/Index.h
+++ clang/include/clang-c/Index.h
@@ -33,7 +33,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 62
+#define CINDEX_VERSION_MINOR 63
#define CINDEX_VERSION_ENCODE(major, minor) (((major)*10000) + ((minor)*1))
@@ -5982,6 +5982,7 @@
CXEval_StrLiteral = 4,
CXEval_CFStr = 5,
CXEval_Other = 6,
+ CXEval_Array = 7,
CXEval_UnExposed = 0
@@ -6037,6 +6038,11 @@
*/
CINDEX_LINKAGE double clang_EvalResult_getAsDouble(CXEvalResult E);
+/**
+ * Returns the number of elements if the kind is Array.
+ */
+CINDEX_LINKAGE unsigned clang_EvalResult_getArraySize(CXEvalResult E);
+
/**
* Returns the evaluation result as a constant string if the
* kind is other than Int or float. User must not free this pointer,
@@ -6045,6 +6051,12 @@
*/
CINDEX_LINKAGE const char *clang_EvalResult_getAsStr(CXEvalResult E);
+/**
+ * Returns an element for a Array result. User must not call
+ * clang_EvalResult_dispose on the return value.
+ */
+CINDEX_LINKAGE CXEvalResult clang_EvalResult_getArrayElt(CXEvalResult E, unsigned index);
+
/**
* Disposes the created Eval memory.
*/
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits