1818#include " swift/Basic/LLVM.h"
1919#include " swift/Basic/LLVMInitialize.h"
2020#include " swift/Basic/Version.h"
21+ #include " swift/Frontend/CachingUtils.h"
2122#include " swift/Frontend/CompileJobCacheKey.h"
2223#include " swift/Frontend/Frontend.h"
2324#include " swift/Frontend/PrintingDiagnosticConsumer.h"
2829#include " llvm/Option/OptTable.h"
2930#include " llvm/Support/Error.h"
3031#include " llvm/Support/JSON.h"
32+ #include " llvm/Support/MemoryBuffer.h"
3133#include < memory>
3234
3335using namespace swift ;
@@ -39,7 +41,15 @@ namespace {
3941enum class SwiftCacheToolAction {
4042 Invalid,
4143 PrintBaseKey,
42- PrintOutputKeys
44+ PrintOutputKeys,
45+ ValidateOutputs
46+ };
47+
48+ struct OutputEntry {
49+ std::string InputPath;
50+ std::string OutputPath;
51+ std::string OutputKind;
52+ std::string CacheKey;
4353};
4454
4555enum ID {
@@ -77,6 +87,7 @@ class SwiftCacheToolInvocation {
7787 PrintingDiagnosticConsumer PDC;
7888 std::string MainExecutablePath;
7989 std::string CASPath;
90+ std::vector<std::string> Inputs;
8091 std::vector<std::string> FrontendArgs;
8192 SwiftCacheToolAction ActionKind = SwiftCacheToolAction::Invalid;
8293
@@ -115,17 +126,19 @@ class SwiftCacheToolInvocation {
115126 CASPath =
116127 ParsedArgs.getLastArgValue (OPT_cas_path, getDefaultOnDiskCASPath ());
117128
129+ Inputs = ParsedArgs.getAllArgValues (OPT_INPUT);
118130 FrontendArgs = ParsedArgs.getAllArgValues (OPT__DASH_DASH);
119131 if (auto *A = ParsedArgs.getLastArg (OPT_cache_tool_action))
120132 ActionKind =
121133 llvm::StringSwitch<SwiftCacheToolAction>(A->getValue ())
122134 .Case (" print-base-key" , SwiftCacheToolAction::PrintBaseKey)
123135 .Case (" print-output-keys" , SwiftCacheToolAction::PrintOutputKeys)
136+ .Case (" validate-outputs" , SwiftCacheToolAction::ValidateOutputs)
124137 .Default (SwiftCacheToolAction::Invalid);
125138
126139 if (ActionKind == SwiftCacheToolAction::Invalid) {
127140 llvm::errs () << " Invalid option specified for -cache-tool-action: "
128- << " use print-base-key|print-output-keys\n " ;
141+ << " use print-base-key|print-output-keys|validate-outputs \n " ;
129142 return 1 ;
130143 }
131144
@@ -138,6 +151,8 @@ class SwiftCacheToolInvocation {
138151 return printBaseKey ();
139152 case SwiftCacheToolAction::PrintOutputKeys:
140153 return printOutputKeys ();
154+ case SwiftCacheToolAction::ValidateOutputs:
155+ return validateOutputs ();
141156 case SwiftCacheToolAction::Invalid:
142157 return 0 ; // No action. Probably just print help. Return.
143158 }
@@ -217,6 +232,7 @@ class SwiftCacheToolInvocation {
217232 }
218233
219234 int printOutputKeys ();
235+ int validateOutputs ();
220236};
221237
222238} // end anonymous namespace
@@ -230,12 +246,6 @@ int SwiftCacheToolInvocation::printOutputKeys() {
230246 if (!BaseKey)
231247 return 1 ;
232248
233- struct OutputEntry {
234- std::string InputPath;
235- std::string OutputPath;
236- std::string OutputKind;
237- std::string CacheKey;
238- };
239249 std::vector<OutputEntry> OutputKeys;
240250 bool hasError = false ;
241251 auto addOutputKey = [&](StringRef InputPath, file_types::ID OutputKind,
@@ -291,6 +301,55 @@ int SwiftCacheToolInvocation::printOutputKeys() {
291301 return 0 ;
292302}
293303
304+ int SwiftCacheToolInvocation::validateOutputs () {
305+ auto DB = llvm::cas::createOnDiskUnifiedCASDatabases (CASPath);
306+ if (!DB)
307+ report_fatal_error (DB.takeError ());
308+
309+ PrintingDiagnosticConsumer PDC;
310+ Instance.getDiags ().addConsumer (PDC);
311+
312+ auto validateCacheKeysFromFile = [&](const std::string &Path) {
313+ auto JSONContent = llvm::MemoryBuffer::getFile (Path);
314+ if (!JSONContent) {
315+ llvm::errs () << " failed to read " << Path << " : "
316+ << JSONContent.getError ().message () << " \n " ;
317+ return true ;
318+ }
319+ auto JSONValue = llvm::json::parse ((*JSONContent)->getBuffer ());
320+ if (!JSONValue) {
321+ llvm::errs () << " failed to parse " << Path << " : "
322+ << toString (JSONValue.takeError ()) << " \n " ;
323+ return true ;
324+ }
325+
326+ auto Keys = JSONValue->getAsArray ();
327+ if (!Keys) {
328+ llvm::errs () << " invalid keys format in " << Path << " \n " ;
329+ return true ;
330+ }
331+
332+ for (const auto & Entry : *Keys) {
333+ if (auto *Obj = Entry.getAsObject ()) {
334+ if (auto Key = Obj->getString (" CacheKey" )) {
335+ if (auto Buffer = loadCachedCompileResultFromCacheKey (
336+ *DB->first , *DB->second , Instance.getDiags (), *Key))
337+ continue ;
338+ llvm::errs () << " failed to find output for cache key " << *Key
339+ << " \n " ;
340+ return true ;
341+ }
342+ }
343+ llvm::errs () << " can't read cache key from " << Path << " \n " ;
344+ return true ;
345+ }
346+
347+ return false ;
348+ };
349+
350+ return llvm::any_of (Inputs, validateCacheKeysFromFile);
351+ }
352+
294353int swift_cache_tool_main (ArrayRef<const char *> Args, const char *Argv0,
295354 void *MainAddr) {
296355 INITIALIZE_LLVM ();
0 commit comments