ConstValues: record the values of const variable references in the side-car file

This commit is contained in:
Xi Ge
2022-02-21 15:08:42 -08:00
parent 87d41a4e27
commit 0992e97e5e
6 changed files with 200 additions and 31 deletions

View File

@@ -491,6 +491,7 @@ public:
return getSemanticsProvidingExpr()->getKind() == ExprKind::InOut;
}
bool printConstExprValue(llvm::raw_ostream *OS) const;
bool isSemanticallyConstExpr() const;
/// Returns false if this expression needs to be wrapped in parens when

View File

@@ -2220,8 +2220,12 @@ static parseJsonEmit(SDKContext &Ctx, StringRef FileName) {
return {std::move(FileBufOrErr.get()), Result};
}
enum class ConstKind: uint8_t {
String = 0,
Int,
StringLiteral = 0,
IntegerLiteral,
FloatLiteral,
BooleanLiteral,
Array,
Dictionary,
};
struct ConstExprInfo {
@@ -2230,9 +2234,11 @@ struct ConstExprInfo {
unsigned offset = 0;
unsigned length = 0;
StringRef value;
StringRef referencedD;
ConstExprInfo(StringRef filePath, ConstKind kind, unsigned offset,
unsigned length, StringRef value):
filePath(filePath), kind(kind), offset(offset), length(length), value(value) {}
unsigned length, StringRef value, StringRef referencedD):
filePath(filePath), kind(kind), offset(offset), length(length), value(value),
referencedD(referencedD) {}
ConstExprInfo() = default;
};
@@ -2242,7 +2248,7 @@ class ConstExtractor: public ASTWalker {
SourceManager &SM;
std::vector<ConstExprInfo> allConsts;
void record(Expr *E, ConstKind kind, StringRef Value) {
void record(Expr *E, ConstKind kind, StringRef Value, StringRef ReferencedD) {
auto startLoc = E->getStartLoc();
// Asserts?
if (startLoc.isInvalid())
@@ -2254,14 +2260,70 @@ class ConstExtractor: public ASTWalker {
auto length = SM.getByteDistance(startLoc, endLoc);
auto file = SM.getIdentifierForBuffer(bufferId);
auto offset = SM.getLocOffsetInBuffer(startLoc, bufferId);
allConsts.emplace_back(file, kind, offset, length, Value);
allConsts.emplace_back(file, kind, offset, length, Value, ReferencedD);
}
void record(Expr *E, Expr *ValueProvider, StringRef ReferecedD = "") {
std::string content;
llvm::raw_string_ostream os(content);
ValueProvider->printConstExprValue(&os);
assert(!content.empty());
auto buffered = SCtx.buffer(content);
switch(ValueProvider->getKind()) {
#define CASE(X) case ExprKind::X: record(E, ConstKind::X, buffered, ReferecedD); break;
CASE(StringLiteral)
CASE(IntegerLiteral)
CASE(FloatLiteral)
CASE(BooleanLiteral)
CASE(Dictionary)
CASE(Array)
#undef CASE
default:
return;
}
}
StringRef getDeclName(Decl *D) {
if (auto *VD = dyn_cast<ValueDecl>(D)) {
std::string content;
llvm::raw_string_ostream os(content);
VD->getName().print(os);
return SCtx.buffer(content);
}
return StringRef();
}
bool handleSimpleReference(Expr *E) {
assert(E);
Decl *ReferencedDecl = nullptr;
if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
ReferencedDecl = MRE->getDecl().getDecl();
} else if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
ReferencedDecl = DRE->getDecl();
} else {
return false;
}
assert(ReferencedDecl);
if (auto *VAR = dyn_cast<VarDecl>(ReferencedDecl)) {
if (!VAR->getAttrs().hasAttribute<CompileTimeConstAttr>()) {
return false;
}
if (auto *PD = VAR->getParentPatternBinding()) {
if (auto *init = PD->getInit(PD->getPatternEntryIndexForVarDecl(VAR))) {
record(E, init, getDeclName(ReferencedDecl));
return true;
}
}
}
return false;
}
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
if (E->isSemanticallyConstExpr()) {
if (auto *SL = dyn_cast<StringLiteralExpr>(E)) {
record(SL, ConstKind::String, SL->getValue());
}
record(E, E);
return { false, E };
}
if (handleSimpleReference(E)) {
return { false, E };
}
return { true, E };
}
@@ -2279,14 +2341,20 @@ template <> struct swift::json::ObjectTraits<ConstExprInfo> {
StringRef kind;
switch(info.kind) {
#define CASE(X) case ConstKind::X: kind = #X; break;
CASE(String)
CASE(Int)
CASE(StringLiteral)
CASE(IntegerLiteral)
CASE(FloatLiteral)
CASE(BooleanLiteral)
CASE(Dictionary)
CASE(Array)
#undef CASE
}
out.mapRequired("kind", kind);
out.mapRequired("offset", info.offset);
out.mapRequired("length", info.length);
out.mapRequired("value", info.value);
if (!info.referencedD.empty())
out.mapRequired("decl", info.referencedD);
}
};

View File

@@ -198,35 +198,72 @@ Expr *Expr::getSemanticsProvidingExpr() {
return this;
}
bool Expr::isSemanticallyConstExpr() const {
auto E = getSemanticsProvidingExpr();
if (!E) {
return false;
}
switch(E->getKind()) {
case ExprKind::IntegerLiteral:
case ExprKind::NilLiteral:
case ExprKind::BooleanLiteral:
case ExprKind::FloatLiteral:
case ExprKind::StringLiteral:
case ExprKind::KeyPath:
bool Expr::printConstExprValue(llvm::raw_ostream *OS) const {
auto print = [&](StringRef text) {
if (OS) {
*OS << text;
}
};
auto *E = getSemanticsProvidingExpr();
assert(E);
switch(getKind()) {
case ExprKind::BooleanLiteral: {
auto isTrue = cast<BooleanLiteralExpr>(E)->getValue();
print(isTrue ? "true" : "false");
return true;
}
case ExprKind::IntegerLiteral:
case ExprKind::FloatLiteral: {
auto digits = cast<NumberLiteralExpr>(E)->getDigitsText();
assert(!digits.empty());
print(digits);
return true;
}
case ExprKind::NilLiteral: {
print("nil");
return true;
}
case ExprKind::StringLiteral: {
auto *LE = cast<StringLiteralExpr>(E);
print("\"");
print(LE->getValue());
print("\"");
return true;
}
case ExprKind::KeyPath: {
// FIXME: print keypath
print("\\.<NOT_IMPLEMENTED>");
return true;
}
case ExprKind::Array:
case ExprKind::Dictionary: {
print("[");
auto *CE = cast<CollectionExpr>(E);
for (auto *EL: CE->getElements()) {
if (!EL->isSemanticallyConstExpr())
for (unsigned N = CE->getNumElements(), I = 0; I != N; I ++) {
auto Ele = CE->getElement(I);
auto needComma = I + 1 != N;
if (!Ele->printConstExprValue(OS)) {
return false;
}
if (needComma)
print(", ");
}
print("]");
return true;
}
case ExprKind::Tuple: {
print("(");
auto *TE = cast<TupleExpr>(E);
for (auto *EL: TE->getElements()) {
if (!EL->isSemanticallyConstExpr()) {
for (unsigned N = TE->getNumElements(), I = 0; I != N; I ++) {
auto Ele = TE->getElement(I);
auto needComma = I + 1 != N;
if (!Ele->printConstExprValue(OS)) {
return false;
}
if (needComma)
print(", ");
}
print(")");
return true;
}
default:
@@ -234,6 +271,10 @@ bool Expr::isSemanticallyConstExpr() const {
}
}
bool Expr::isSemanticallyConstExpr() const {
return printConstExprValue(nullptr);
}
Expr *Expr::getValueProvidingExpr() {
Expr *E = getSemanticsProvidingExpr();

View File

@@ -0,0 +1,18 @@
_const let global_str = "abc"
_const let global_int = 3
_const let global_float = 3.2
class C {
static _const let class_bool = false
static _const let class_arr = [2, 2, 3]
static _const let class_dict = [2:1, 2:1, 3:1]
}
func foo() {
_ = global_str
_ = global_int
_ = global_float
_ = C.class_bool
_ = C.class_arr
_ = C.class_dict
}

View File

@@ -7,7 +7,7 @@
// RUN: %FileCheck %s < %t/abi.json
// CHECK: "kind": "String"
// CHECK: "value": "abc"
// CHECK: "kind": "String"
// CHECK: "value": "def"
// CHECK: "kind": "StringLiteral"
// CHECK: "value": "\"abc\""
// CHECK: "kind": "StringLiteral"
// CHECK: "value": "\"def\""

View File

@@ -0,0 +1,41 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -o %t/Foo.swiftmodule -emit-abi-descriptor-path %t/abi.json %S/Inputs/ConstExtraction/SimpleReferences.swift
// RUN: %api-digester -deserialize-sdk -input-paths %t/abi.json -o %t.result
// RUN: %FileCheck %s < %t/abi.json
// CHECK: "offset": 249,
// CHECK-NEXT: "length": 10,
// CHECK-NEXT: "value": "\"abc\"",
// CHECK-NEXT: "decl": "global_str"
// CHECK: "kind": "IntegerLiteral",
// CHECK-NEXT: "offset": 266,
// CHECK-NEXT: "length": 10,
// CHECK-NEXT: "value": "3",
// CHECK-NEXT: "decl": "global_int"
// CHECK: "kind": "FloatLiteral",
// CHECK-NEXT: "offset": 283,
// CHECK-NEXT: "length": 12,
// CHECK-NEXT: "value": "3.2",
// CHECK-NEXT: "decl": "global_float"
// CHECK: "kind": "BooleanLiteral",
// CHECK-NEXT: "offset": 302,
// CHECK-NEXT: "length": 12,
// CHECK-NEXT: "value": "false",
// CHECK-NEXT: "decl": "class_bool"
// CHECK: "kind": "Array",
// CHECK-NEXT: "offset": 321,
// CHECK-NEXT: "length": 11,
// CHECK-NEXT: "value": "[2, 2, 3]",
// CHECK-NEXT: "decl": "class_arr"
// CHECK: "kind": "Dictionary",
// CHECK-NEXT: "offset": 339,
// CHECK-NEXT: "length": 12,
// CHECK-NEXT: "value": "[(2, 1), (2, 1), (3, 1)]",
// CHECK-NEXT: "decl": "class_dict"