Skip to content

Commit b480643

Browse files
authored
Merge pull request swiftlang#41502 from nkcsgexi/side-car-const-referece
ConstValues: record the values of const variable references in the sidecar file
2 parents e35261f + 0992e97 commit b480643

File tree

6 files changed

+198
-29
lines changed

6 files changed

+198
-29
lines changed

include/swift/AST/Expr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
491491
return getSemanticsProvidingExpr()->getKind() == ExprKind::InOut;
492492
}
493493

494+
bool printConstExprValue(llvm::raw_ostream *OS) const;
494495
bool isSemanticallyConstExpr() const;
495496

496497
/// Returns false if this expression needs to be wrapped in parens when

lib/APIDigester/ModuleAnalyzerNodes.cpp

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2220,8 +2220,12 @@ static parseJsonEmit(SDKContext &Ctx, StringRef FileName) {
22202220
return {std::move(FileBufOrErr.get()), Result};
22212221
}
22222222
enum class ConstKind: uint8_t {
2223-
String = 0,
2224-
Int,
2223+
StringLiteral = 0,
2224+
IntegerLiteral,
2225+
FloatLiteral,
2226+
BooleanLiteral,
2227+
Array,
2228+
Dictionary,
22252229
};
22262230

22272231
struct ConstExprInfo {
@@ -2230,9 +2234,11 @@ struct ConstExprInfo {
22302234
unsigned offset = 0;
22312235
unsigned length = 0;
22322236
StringRef value;
2237+
StringRef referencedD;
22332238
ConstExprInfo(StringRef filePath, ConstKind kind, unsigned offset,
2234-
unsigned length, StringRef value):
2235-
filePath(filePath), kind(kind), offset(offset), length(length), value(value) {}
2239+
unsigned length, StringRef value, StringRef referencedD):
2240+
filePath(filePath), kind(kind), offset(offset), length(length), value(value),
2241+
referencedD(referencedD) {}
22362242
ConstExprInfo() = default;
22372243
};
22382244

@@ -2242,7 +2248,7 @@ class ConstExtractor: public ASTWalker {
22422248
SourceManager &SM;
22432249
std::vector<ConstExprInfo> allConsts;
22442250

2245-
void record(Expr *E, ConstKind kind, StringRef Value) {
2251+
void record(Expr *E, ConstKind kind, StringRef Value, StringRef ReferencedD) {
22462252
auto startLoc = E->getStartLoc();
22472253
// Asserts?
22482254
if (startLoc.isInvalid())
@@ -2254,14 +2260,70 @@ class ConstExtractor: public ASTWalker {
22542260
auto length = SM.getByteDistance(startLoc, endLoc);
22552261
auto file = SM.getIdentifierForBuffer(bufferId);
22562262
auto offset = SM.getLocOffsetInBuffer(startLoc, bufferId);
2257-
allConsts.emplace_back(file, kind, offset, length, Value);
2263+
allConsts.emplace_back(file, kind, offset, length, Value, ReferencedD);
2264+
}
2265+
2266+
void record(Expr *E, Expr *ValueProvider, StringRef ReferecedD = "") {
2267+
std::string content;
2268+
llvm::raw_string_ostream os(content);
2269+
ValueProvider->printConstExprValue(&os);
2270+
assert(!content.empty());
2271+
auto buffered = SCtx.buffer(content);
2272+
switch(ValueProvider->getKind()) {
2273+
#define CASE(X) case ExprKind::X: record(E, ConstKind::X, buffered, ReferecedD); break;
2274+
CASE(StringLiteral)
2275+
CASE(IntegerLiteral)
2276+
CASE(FloatLiteral)
2277+
CASE(BooleanLiteral)
2278+
CASE(Dictionary)
2279+
CASE(Array)
2280+
#undef CASE
2281+
default:
2282+
return;
2283+
}
2284+
}
2285+
2286+
StringRef getDeclName(Decl *D) {
2287+
if (auto *VD = dyn_cast<ValueDecl>(D)) {
2288+
std::string content;
2289+
llvm::raw_string_ostream os(content);
2290+
VD->getName().print(os);
2291+
return SCtx.buffer(content);
2292+
}
2293+
return StringRef();
22582294
}
22592295

2296+
bool handleSimpleReference(Expr *E) {
2297+
assert(E);
2298+
Decl *ReferencedDecl = nullptr;
2299+
if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
2300+
ReferencedDecl = MRE->getDecl().getDecl();
2301+
} else if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
2302+
ReferencedDecl = DRE->getDecl();
2303+
} else {
2304+
return false;
2305+
}
2306+
assert(ReferencedDecl);
2307+
if (auto *VAR = dyn_cast<VarDecl>(ReferencedDecl)) {
2308+
if (!VAR->getAttrs().hasAttribute<CompileTimeConstAttr>()) {
2309+
return false;
2310+
}
2311+
if (auto *PD = VAR->getParentPatternBinding()) {
2312+
if (auto *init = PD->getInit(PD->getPatternEntryIndexForVarDecl(VAR))) {
2313+
record(E, init, getDeclName(ReferencedDecl));
2314+
return true;
2315+
}
2316+
}
2317+
}
2318+
return false;
2319+
}
22602320
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
22612321
if (E->isSemanticallyConstExpr()) {
2262-
if (auto *SL = dyn_cast<StringLiteralExpr>(E)) {
2263-
record(SL, ConstKind::String, SL->getValue());
2264-
}
2322+
record(E, E);
2323+
return { false, E };
2324+
}
2325+
if (handleSimpleReference(E)) {
2326+
return { false, E };
22652327
}
22662328
return { true, E };
22672329
}
@@ -2279,14 +2341,20 @@ template <> struct swift::json::ObjectTraits<ConstExprInfo> {
22792341
StringRef kind;
22802342
switch(info.kind) {
22812343
#define CASE(X) case ConstKind::X: kind = #X; break;
2282-
CASE(String)
2283-
CASE(Int)
2344+
CASE(StringLiteral)
2345+
CASE(IntegerLiteral)
2346+
CASE(FloatLiteral)
2347+
CASE(BooleanLiteral)
2348+
CASE(Dictionary)
2349+
CASE(Array)
22842350
#undef CASE
22852351
}
22862352
out.mapRequired("kind", kind);
22872353
out.mapRequired("offset", info.offset);
22882354
out.mapRequired("length", info.length);
22892355
out.mapRequired("value", info.value);
2356+
if (!info.referencedD.empty())
2357+
out.mapRequired("decl", info.referencedD);
22902358
}
22912359
};
22922360

lib/AST/Expr.cpp

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -198,42 +198,83 @@ Expr *Expr::getSemanticsProvidingExpr() {
198198
return this;
199199
}
200200

201-
bool Expr::isSemanticallyConstExpr() const {
202-
auto E = getSemanticsProvidingExpr();
203-
if (!E) {
204-
return false;
201+
bool Expr::printConstExprValue(llvm::raw_ostream *OS) const {
202+
auto print = [&](StringRef text) {
203+
if (OS) {
204+
*OS << text;
205+
}
206+
};
207+
auto *E = getSemanticsProvidingExpr();
208+
assert(E);
209+
switch(getKind()) {
210+
case ExprKind::BooleanLiteral: {
211+
auto isTrue = cast<BooleanLiteralExpr>(E)->getValue();
212+
print(isTrue ? "true" : "false");
213+
return true;
205214
}
206-
switch(E->getKind()) {
207215
case ExprKind::IntegerLiteral:
208-
case ExprKind::NilLiteral:
209-
case ExprKind::BooleanLiteral:
210-
case ExprKind::FloatLiteral:
211-
case ExprKind::StringLiteral:
212-
case ExprKind::KeyPath:
216+
case ExprKind::FloatLiteral: {
217+
auto digits = cast<NumberLiteralExpr>(E)->getDigitsText();
218+
assert(!digits.empty());
219+
print(digits);
213220
return true;
221+
}
222+
case ExprKind::NilLiteral: {
223+
print("nil");
224+
return true;
225+
}
226+
case ExprKind::StringLiteral: {
227+
auto *LE = cast<StringLiteralExpr>(E);
228+
print("\"");
229+
print(LE->getValue());
230+
print("\"");
231+
return true;
232+
}
233+
case ExprKind::KeyPath: {
234+
// FIXME: print keypath
235+
print("\\.<NOT_IMPLEMENTED>");
236+
return true;
237+
}
214238
case ExprKind::Array:
215239
case ExprKind::Dictionary: {
240+
print("[");
216241
auto *CE = cast<CollectionExpr>(E);
217-
for (auto *EL: CE->getElements()) {
218-
if (!EL->isSemanticallyConstExpr())
242+
for (unsigned N = CE->getNumElements(), I = 0; I != N; I ++) {
243+
auto Ele = CE->getElement(I);
244+
auto needComma = I + 1 != N;
245+
if (!Ele->printConstExprValue(OS)) {
219246
return false;
247+
}
248+
if (needComma)
249+
print(", ");
220250
}
251+
print("]");
221252
return true;
222253
}
223254
case ExprKind::Tuple: {
255+
print("(");
224256
auto *TE = cast<TupleExpr>(E);
225-
for (auto *EL: TE->getElements()) {
226-
if (!EL->isSemanticallyConstExpr()) {
257+
for (unsigned N = TE->getNumElements(), I = 0; I != N; I ++) {
258+
auto Ele = TE->getElement(I);
259+
auto needComma = I + 1 != N;
260+
if (!Ele->printConstExprValue(OS)) {
227261
return false;
228262
}
263+
if (needComma)
264+
print(", ");
229265
}
266+
print(")");
230267
return true;
231268
}
232269
default:
233270
return false;
234271
}
235272
}
236273

274+
bool Expr::isSemanticallyConstExpr() const {
275+
return printConstExprValue(nullptr);
276+
}
277+
237278
Expr *Expr::getValueProvidingExpr() {
238279
Expr *E = getSemanticsProvidingExpr();
239280

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
_const let global_str = "abc"
2+
_const let global_int = 3
3+
_const let global_float = 3.2
4+
5+
class C {
6+
static _const let class_bool = false
7+
static _const let class_arr = [2, 2, 3]
8+
static _const let class_dict = [2:1, 2:1, 3:1]
9+
}
10+
11+
func foo() {
12+
_ = global_str
13+
_ = global_int
14+
_ = global_float
15+
_ = C.class_bool
16+
_ = C.class_arr
17+
_ = C.class_dict
18+
}

test/api-digester/const_values.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
// RUN: %FileCheck %s < %t/abi.json
99

10-
// CHECK: "kind": "String"
11-
// CHECK: "value": "abc"
12-
// CHECK: "kind": "String"
13-
// CHECK: "value": "def"
10+
// CHECK: "kind": "StringLiteral"
11+
// CHECK: "value": "\"abc\""
12+
// CHECK: "kind": "StringLiteral"
13+
// CHECK: "value": "\"def\""
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -emit-module -o %t/Foo.swiftmodule -emit-abi-descriptor-path %t/abi.json %S/Inputs/ConstExtraction/SimpleReferences.swift
4+
// RUN: %api-digester -deserialize-sdk -input-paths %t/abi.json -o %t.result
5+
6+
// RUN: %FileCheck %s < %t/abi.json
7+
8+
// CHECK: "offset": 249,
9+
// CHECK-NEXT: "length": 10,
10+
// CHECK-NEXT: "value": "\"abc\"",
11+
// CHECK-NEXT: "decl": "global_str"
12+
13+
// CHECK: "kind": "IntegerLiteral",
14+
// CHECK-NEXT: "offset": 266,
15+
// CHECK-NEXT: "length": 10,
16+
// CHECK-NEXT: "value": "3",
17+
// CHECK-NEXT: "decl": "global_int"
18+
19+
// CHECK: "kind": "FloatLiteral",
20+
// CHECK-NEXT: "offset": 283,
21+
// CHECK-NEXT: "length": 12,
22+
// CHECK-NEXT: "value": "3.2",
23+
// CHECK-NEXT: "decl": "global_float"
24+
25+
// CHECK: "kind": "BooleanLiteral",
26+
// CHECK-NEXT: "offset": 302,
27+
// CHECK-NEXT: "length": 12,
28+
// CHECK-NEXT: "value": "false",
29+
// CHECK-NEXT: "decl": "class_bool"
30+
31+
// CHECK: "kind": "Array",
32+
// CHECK-NEXT: "offset": 321,
33+
// CHECK-NEXT: "length": 11,
34+
// CHECK-NEXT: "value": "[2, 2, 3]",
35+
// CHECK-NEXT: "decl": "class_arr"
36+
37+
// CHECK: "kind": "Dictionary",
38+
// CHECK-NEXT: "offset": 339,
39+
// CHECK-NEXT: "length": 12,
40+
// CHECK-NEXT: "value": "[(2, 1), (2, 1), (3, 1)]",
41+
// CHECK-NEXT: "decl": "class_dict"

0 commit comments

Comments
 (0)