Skip to content

Commit 23556ae

Browse files
committed
ABIChecker: teach ABI descriptor JSON to also keep track of constant values known at compile-time
Emitted at the emit-module step, ABI descriptor is of an entensible JSON format. This patch sets up a segment in the file to also keep track of all compile-time constant values for other tools to consume. As the initial step, we only keep track of string literals in the source files.
1 parent 2c273c4 commit 23556ae

File tree

3 files changed

+112
-6
lines changed

3 files changed

+112
-6
lines changed

include/swift/APIDigester/ModuleAnalyzerNodes.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ namespace api {
6666
const uint8_t DIGESTER_JSON_VERSION = 7; // push SDKNodeRoot to lower-level
6767
const uint8_t DIGESTER_JSON_DEFAULT_VERSION = 0; // Use this version number for files before we have a version number in json.
6868
const StringRef ABIRootKey = "ABIRoot";
69+
const StringRef ConstValuesKey = "ConstValues";
6970

7071
class SDKNode;
7172
typedef SDKNode* NodePtr;
@@ -737,6 +738,8 @@ struct TypeInitInfo {
737738
StringRef ValueOwnership;
738739
};
739740

741+
struct PayLoad;
742+
740743
class SwiftDeclCollector: public VisibleDeclConsumer {
741744
SDKContext &Ctx;
742745
SDKNode *RootNode;
@@ -757,7 +760,7 @@ class SwiftDeclCollector: public VisibleDeclConsumer {
757760

758761
// Serialize the content of all roots to a given file using JSON format.
759762
void serialize(StringRef Filename);
760-
static void serialize(StringRef Filename, SDKNode *Root);
763+
static void serialize(StringRef Filename, SDKNode *Root, PayLoad otherInfo);
761764

762765
// After collecting decls, either from imported modules or from a previously
763766
// serialized JSON file, using this function to get the root of the SDK.
@@ -806,6 +809,7 @@ SDKNodeRoot *getSDKNodeRoot(SDKContext &SDKCtx,
806809

807810
SDKNodeRoot *getEmptySDKNodeRoot(SDKContext &SDKCtx);
808811

812+
void dumpSDKRoot(SDKNodeRoot *Root, PayLoad load, StringRef OutputFile);
809813
void dumpSDKRoot(SDKNodeRoot *Root, StringRef OutputFile);
810814

811815
int dumpSDKContent(const CompilerInvocation &InitInvok,

lib/APIDigester/ModuleAnalyzerNodes.cpp

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,9 @@ SDKNode* SDKNode::constructSDKNode(SDKContext &Ctx,
746746
} else if (keyString == ABIRootKey) {
747747
Result = constructSDKNode(Ctx,
748748
cast<llvm::yaml::MappingNode>(Pair.getValue()));
749+
} else if (keyString == ConstValuesKey) {
750+
// We don't need to consume the const values from the compiler-side
751+
Pair.skip();
749752
} else {
750753
Ctx.diagnose(Pair.getKey(), diag::sdk_node_unrecognized_key,
751754
keyString);
@@ -2215,8 +2218,81 @@ static parseJsonEmit(SDKContext &Ctx, StringRef FileName) {
22152218
}
22162219
return {std::move(FileBufOrErr.get()), Result};
22172220
}
2221+
enum class ConstKind: uint8_t {
2222+
String = 0,
2223+
Int,
2224+
};
2225+
2226+
struct ConstExprInfo {
2227+
StringRef filePath;
2228+
ConstKind kind;
2229+
unsigned offset = 0;
2230+
unsigned length = 0;
2231+
StringRef value;
2232+
ConstExprInfo(StringRef filePath, ConstKind kind, unsigned offset,
2233+
unsigned length, StringRef value):
2234+
filePath(filePath), kind(kind), offset(offset), length(length), value(value) {}
2235+
ConstExprInfo() = default;
2236+
};
2237+
2238+
class ConstExtractor: public ASTWalker {
2239+
SDKContext &SCtx;
2240+
ASTContext &Ctx;
2241+
SourceManager &SM;
2242+
std::vector<ConstExprInfo> allConsts;
2243+
2244+
void record(Expr *E, ConstKind kind, StringRef Value) {
2245+
auto startLoc = E->getStartLoc();
2246+
// Asserts?
2247+
if (startLoc.isInvalid())
2248+
return;
2249+
auto endLoc = E->getEndLoc();
2250+
assert(endLoc.isValid());
2251+
endLoc = Lexer::getLocForEndOfToken(SM, endLoc);
2252+
auto bufferId = SM.findBufferContainingLoc(startLoc);
2253+
auto length = SM.getByteDistance(startLoc, endLoc);
2254+
auto file = SM.getIdentifierForBuffer(bufferId);
2255+
auto offset = SM.getLocOffsetInBuffer(startLoc, bufferId);
2256+
allConsts.emplace_back(file, kind, offset, length, Value);
2257+
}
2258+
2259+
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
2260+
if (E->isSemanticallyConstExpr()) {
2261+
if (auto *SL = dyn_cast<StringLiteralExpr>(E)) {
2262+
record(SL, ConstKind::String, SL->getValue());
2263+
}
2264+
}
2265+
return { true, E };
2266+
}
2267+
public:
2268+
ConstExtractor(SDKContext &SCtx, ASTContext &Ctx): SCtx(SCtx), Ctx(Ctx),
2269+
SM(Ctx.SourceMgr) {}
2270+
void extract(ModuleDecl *MD) { MD->walk(*this); }
2271+
std::vector<ConstExprInfo> &getAllConstValues() { return allConsts; }
2272+
};
22182273
} // End of anonymous namespace
22192274

2275+
template <> struct swift::json::ObjectTraits<ConstExprInfo> {
2276+
static void mapping(Output &out, ConstExprInfo &info) {
2277+
out.mapRequired("filePath", info.filePath);
2278+
StringRef kind;
2279+
switch(info.kind) {
2280+
#define CASE(X) case ConstKind::X: kind = #X; break;
2281+
CASE(String)
2282+
CASE(Int)
2283+
#undef CASE
2284+
}
2285+
out.mapRequired("kind", kind);
2286+
out.mapRequired("offset", info.offset);
2287+
out.mapRequired("length", info.length);
2288+
out.mapRequired("value", info.value);
2289+
}
2290+
};
2291+
2292+
struct swift::ide::api::PayLoad {
2293+
std::vector<ConstExprInfo> *allContsValues = nullptr;
2294+
};
2295+
22202296
// Construct all roots vector from a given file where a forest was
22212297
// previously dumped.
22222298
void SwiftDeclCollector::deSerialize(StringRef Filename) {
@@ -2225,20 +2301,24 @@ void SwiftDeclCollector::deSerialize(StringRef Filename) {
22252301
}
22262302

22272303
// Serialize the content of all roots to a given file using JSON format.
2228-
void SwiftDeclCollector::serialize(StringRef Filename, SDKNode *Root) {
2304+
void SwiftDeclCollector::serialize(StringRef Filename, SDKNode *Root,
2305+
PayLoad OtherInfo) {
22292306
std::error_code EC;
22302307
llvm::raw_fd_ostream fs(Filename, EC, llvm::sys::fs::OF_None);
22312308
json::Output yout(fs);
22322309
assert(Root->getKind() == SDKNodeKind::Root);
22332310
SDKNodeRoot &root = *static_cast<SDKNodeRoot*>(Root);
22342311
yout.beginObject();
22352312
yout.mapRequired(ABIRootKey, root);
2313+
if (auto *constValues = OtherInfo.allContsValues) {
2314+
yout.mapRequired(ConstValuesKey, *constValues);
2315+
}
22362316
yout.endObject();
22372317
}
22382318

22392319
// Serialize the content of all roots to a given file using JSON format.
22402320
void SwiftDeclCollector::serialize(StringRef Filename) {
2241-
SwiftDeclCollector::serialize(Filename, RootNode);
2321+
SwiftDeclCollector::serialize(Filename, RootNode, PayLoad());
22422322
}
22432323

22442324
SDKNodeRoot *
@@ -2304,16 +2384,21 @@ swift::ide::api::getSDKNodeRoot(SDKContext &SDKCtx,
23042384
return Collector.getSDKRoot();
23052385
}
23062386

2307-
void swift::ide::api::dumpSDKRoot(SDKNodeRoot *Root, StringRef OutputFile) {
2387+
void swift::ide::api::dumpSDKRoot(SDKNodeRoot *Root, PayLoad load,
2388+
StringRef OutputFile) {
23082389
assert(Root);
23092390
auto Opts = Root->getSDKContext().getOpts();
23102391
if (Opts.Verbose)
23112392
llvm::errs() << "Dumping SDK...\n";
2312-
SwiftDeclCollector::serialize(OutputFile, Root);
2393+
SwiftDeclCollector::serialize(OutputFile, Root, load);
23132394
if (Opts.Verbose)
23142395
llvm::errs() << "Dumped to "<< OutputFile << "\n";
23152396
}
23162397

2398+
void swift::ide::api::dumpSDKRoot(SDKNodeRoot *Root, StringRef OutputFile) {
2399+
dumpSDKRoot(Root, PayLoad(), OutputFile);
2400+
}
2401+
23172402
int swift::ide::api::dumpSDKContent(const CompilerInvocation &InitInvok,
23182403
const llvm::StringSet<> &ModuleNames,
23192404
StringRef OutputFile, CheckerOptions Opts) {
@@ -2356,7 +2441,11 @@ void swift::ide::api::dumpModuleContent(ModuleDecl *MD, StringRef OutputFile,
23562441
SDKContext ctx(opts);
23572442
SwiftDeclCollector collector(ctx);
23582443
collector.lookupVisibleDecls({MD});
2359-
dumpSDKRoot(collector.getSDKRoot(), OutputFile);
2444+
ConstExtractor extractor(ctx, MD->getASTContext());
2445+
extractor.extract(MD);
2446+
PayLoad payload;
2447+
payload.allContsValues = &extractor.getAllConstValues();
2448+
dumpSDKRoot(collector.getSDKRoot(), payload, OutputFile);
23602449
}
23612450

23622451
int swift::ide::api::findDeclUsr(StringRef dumpPath, CheckerOptions Opts) {

test/api-digester/const_values.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: echo "public func foo() { let a = \"abc\" }" > %t/t1.swift
4+
// RUN: echo "public func bar() { let a = \"def\" }" > %t/t2.swift
5+
// RUN: %target-swift-frontend -emit-module %t/t1.swift %t/t2.swift -o %t/Foo.swiftmodule -emit-abi-descriptor-path %t/abi.json
6+
// RUN: %api-digester -deserialize-sdk -input-paths %t/abi.json -o %t.result
7+
8+
// RUN: %FileCheck %s < %t/abi.json
9+
10+
// CHECK: "kind": "String"
11+
// CHECK: "value": "abc"
12+
// CHECK: "kind": "String"
13+
// CHECK: "value": "def"

0 commit comments

Comments
 (0)