Skip to content

Commit d7d3fe3

Browse files
authored
Merge pull request #41367 from nkcsgexi/set-up-payload-for-const
ABIChecker: teach ABI descriptor JSON to also keep track of constant values known at compile-time
2 parents a8da2d5 + 23556ae commit d7d3fe3

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);
@@ -2216,8 +2219,81 @@ static parseJsonEmit(SDKContext &Ctx, StringRef FileName) {
22162219
}
22172220
return {std::move(FileBufOrErr.get()), Result};
22182221
}
2222+
enum class ConstKind: uint8_t {
2223+
String = 0,
2224+
Int,
2225+
};
2226+
2227+
struct ConstExprInfo {
2228+
StringRef filePath;
2229+
ConstKind kind;
2230+
unsigned offset = 0;
2231+
unsigned length = 0;
2232+
StringRef value;
2233+
ConstExprInfo(StringRef filePath, ConstKind kind, unsigned offset,
2234+
unsigned length, StringRef value):
2235+
filePath(filePath), kind(kind), offset(offset), length(length), value(value) {}
2236+
ConstExprInfo() = default;
2237+
};
2238+
2239+
class ConstExtractor: public ASTWalker {
2240+
SDKContext &SCtx;
2241+
ASTContext &Ctx;
2242+
SourceManager &SM;
2243+
std::vector<ConstExprInfo> allConsts;
2244+
2245+
void record(Expr *E, ConstKind kind, StringRef Value) {
2246+
auto startLoc = E->getStartLoc();
2247+
// Asserts?
2248+
if (startLoc.isInvalid())
2249+
return;
2250+
auto endLoc = E->getEndLoc();
2251+
assert(endLoc.isValid());
2252+
endLoc = Lexer::getLocForEndOfToken(SM, endLoc);
2253+
auto bufferId = SM.findBufferContainingLoc(startLoc);
2254+
auto length = SM.getByteDistance(startLoc, endLoc);
2255+
auto file = SM.getIdentifierForBuffer(bufferId);
2256+
auto offset = SM.getLocOffsetInBuffer(startLoc, bufferId);
2257+
allConsts.emplace_back(file, kind, offset, length, Value);
2258+
}
2259+
2260+
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
2261+
if (E->isSemanticallyConstExpr()) {
2262+
if (auto *SL = dyn_cast<StringLiteralExpr>(E)) {
2263+
record(SL, ConstKind::String, SL->getValue());
2264+
}
2265+
}
2266+
return { true, E };
2267+
}
2268+
public:
2269+
ConstExtractor(SDKContext &SCtx, ASTContext &Ctx): SCtx(SCtx), Ctx(Ctx),
2270+
SM(Ctx.SourceMgr) {}
2271+
void extract(ModuleDecl *MD) { MD->walk(*this); }
2272+
std::vector<ConstExprInfo> &getAllConstValues() { return allConsts; }
2273+
};
22192274
} // End of anonymous namespace
22202275

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

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

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

22452325
SDKNodeRoot *
@@ -2305,16 +2385,21 @@ swift::ide::api::getSDKNodeRoot(SDKContext &SDKCtx,
23052385
return Collector.getSDKRoot();
23062386
}
23072387

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

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

23632452
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)