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
This commit is contained in:
Xi Ge
2022-02-15 11:21:42 -08:00
committed by GitHub
3 changed files with 112 additions and 6 deletions

View File

@@ -746,6 +746,9 @@ SDKNode* SDKNode::constructSDKNode(SDKContext &Ctx,
} else if (keyString == ABIRootKey) {
Result = constructSDKNode(Ctx,
cast<llvm::yaml::MappingNode>(Pair.getValue()));
} else if (keyString == ConstValuesKey) {
// We don't need to consume the const values from the compiler-side
Pair.skip();
} else {
Ctx.diagnose(Pair.getKey(), diag::sdk_node_unrecognized_key,
keyString);
@@ -2216,8 +2219,81 @@ static parseJsonEmit(SDKContext &Ctx, StringRef FileName) {
}
return {std::move(FileBufOrErr.get()), Result};
}
enum class ConstKind: uint8_t {
String = 0,
Int,
};
struct ConstExprInfo {
StringRef filePath;
ConstKind kind;
unsigned offset = 0;
unsigned length = 0;
StringRef value;
ConstExprInfo(StringRef filePath, ConstKind kind, unsigned offset,
unsigned length, StringRef value):
filePath(filePath), kind(kind), offset(offset), length(length), value(value) {}
ConstExprInfo() = default;
};
class ConstExtractor: public ASTWalker {
SDKContext &SCtx;
ASTContext &Ctx;
SourceManager &SM;
std::vector<ConstExprInfo> allConsts;
void record(Expr *E, ConstKind kind, StringRef Value) {
auto startLoc = E->getStartLoc();
// Asserts?
if (startLoc.isInvalid())
return;
auto endLoc = E->getEndLoc();
assert(endLoc.isValid());
endLoc = Lexer::getLocForEndOfToken(SM, endLoc);
auto bufferId = SM.findBufferContainingLoc(startLoc);
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);
}
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
if (E->isSemanticallyConstExpr()) {
if (auto *SL = dyn_cast<StringLiteralExpr>(E)) {
record(SL, ConstKind::String, SL->getValue());
}
}
return { true, E };
}
public:
ConstExtractor(SDKContext &SCtx, ASTContext &Ctx): SCtx(SCtx), Ctx(Ctx),
SM(Ctx.SourceMgr) {}
void extract(ModuleDecl *MD) { MD->walk(*this); }
std::vector<ConstExprInfo> &getAllConstValues() { return allConsts; }
};
} // End of anonymous namespace
template <> struct swift::json::ObjectTraits<ConstExprInfo> {
static void mapping(Output &out, ConstExprInfo &info) {
out.mapRequired("filePath", info.filePath);
StringRef kind;
switch(info.kind) {
#define CASE(X) case ConstKind::X: kind = #X; break;
CASE(String)
CASE(Int)
#undef CASE
}
out.mapRequired("kind", kind);
out.mapRequired("offset", info.offset);
out.mapRequired("length", info.length);
out.mapRequired("value", info.value);
}
};
struct swift::ide::api::PayLoad {
std::vector<ConstExprInfo> *allContsValues = nullptr;
};
// Construct all roots vector from a given file where a forest was
// previously dumped.
void SwiftDeclCollector::deSerialize(StringRef Filename) {
@@ -2226,7 +2302,8 @@ void SwiftDeclCollector::deSerialize(StringRef Filename) {
}
// Serialize the content of all roots to a given file using JSON format.
void SwiftDeclCollector::serialize(StringRef Filename, SDKNode *Root) {
void SwiftDeclCollector::serialize(StringRef Filename, SDKNode *Root,
PayLoad OtherInfo) {
std::error_code EC;
llvm::raw_fd_ostream fs(Filename, EC, llvm::sys::fs::OF_None);
json::Output yout(fs);
@@ -2234,12 +2311,15 @@ void SwiftDeclCollector::serialize(StringRef Filename, SDKNode *Root) {
SDKNodeRoot &root = *static_cast<SDKNodeRoot*>(Root);
yout.beginObject();
yout.mapRequired(ABIRootKey, root);
if (auto *constValues = OtherInfo.allContsValues) {
yout.mapRequired(ConstValuesKey, *constValues);
}
yout.endObject();
}
// Serialize the content of all roots to a given file using JSON format.
void SwiftDeclCollector::serialize(StringRef Filename) {
SwiftDeclCollector::serialize(Filename, RootNode);
SwiftDeclCollector::serialize(Filename, RootNode, PayLoad());
}
SDKNodeRoot *
@@ -2305,16 +2385,21 @@ swift::ide::api::getSDKNodeRoot(SDKContext &SDKCtx,
return Collector.getSDKRoot();
}
void swift::ide::api::dumpSDKRoot(SDKNodeRoot *Root, StringRef OutputFile) {
void swift::ide::api::dumpSDKRoot(SDKNodeRoot *Root, PayLoad load,
StringRef OutputFile) {
assert(Root);
auto Opts = Root->getSDKContext().getOpts();
if (Opts.Verbose)
llvm::errs() << "Dumping SDK...\n";
SwiftDeclCollector::serialize(OutputFile, Root);
SwiftDeclCollector::serialize(OutputFile, Root, load);
if (Opts.Verbose)
llvm::errs() << "Dumped to "<< OutputFile << "\n";
}
void swift::ide::api::dumpSDKRoot(SDKNodeRoot *Root, StringRef OutputFile) {
dumpSDKRoot(Root, PayLoad(), OutputFile);
}
int swift::ide::api::dumpSDKContent(const CompilerInvocation &InitInvok,
const llvm::StringSet<> &ModuleNames,
StringRef OutputFile, CheckerOptions Opts) {
@@ -2357,7 +2442,11 @@ void swift::ide::api::dumpModuleContent(ModuleDecl *MD, StringRef OutputFile,
SDKContext ctx(opts);
SwiftDeclCollector collector(ctx);
collector.lookupVisibleDecls({MD});
dumpSDKRoot(collector.getSDKRoot(), OutputFile);
ConstExtractor extractor(ctx, MD->getASTContext());
extractor.extract(MD);
PayLoad payload;
payload.allContsValues = &extractor.getAllConstValues();
dumpSDKRoot(collector.getSDKRoot(), payload, OutputFile);
}
int swift::ide::api::findDeclUsr(StringRef dumpPath, CheckerOptions Opts) {