[Frontend] Allow additional files for diagnostic verifier

This change adds a frontend flag, -verify-additional-file, which can be used to pass extra files directly to the diagnostic verifier. These files are not otherwise considered to be Swift source files; they are not compiled or even properly parsed.

This feature can be used to verify diagnostics emitted in non-source files, such as in module interfaces or header files.
This commit is contained in:
Brent Royal-Gordon
2020-09-18 17:52:38 -07:00
committed by Alexis Laferrière
parent ba00258c66
commit 5036a55550
7 changed files with 50 additions and 12 deletions

View File

@@ -41,6 +41,10 @@ public:
/// Indicates whether diagnostic passes should be skipped.
bool SkipDiagnosticPasses = false;
/// Additional non-source files which will have diagnostics emitted in them,
/// and which should be scanned for expectations by the diagnostic verifier.
std::vector<std::string> AdditionalVerifierFiles;
/// Keep emitting subsequent diagnostics after a fatal error.
bool ShowDiagnosticsAfterFatalError = false;
@@ -54,22 +58,23 @@ public:
/// Treat all warnings as errors
bool WarningsAsErrors = false;
// When printing diagnostics, include the diagnostic name at the end
/// When printing diagnostics, include the diagnostic name (diag::whatever) at
/// the end.
bool PrintDiagnosticNames = false;
/// If set to true, include educational notes in printed output if available.
/// Educational notes are documentation which supplement diagnostics.
bool PrintEducationalNotes = false;
// If set to true, use the more descriptive experimental formatting style for
// diagnostics.
/// Whether to emit diagnostics in the terse LLVM style or in a more
/// descriptive style that's specific to Swift (currently experimental).
FormattingStyle PrintedFormattingStyle = FormattingStyle::LLVM;
std::string DiagnosticDocumentationPath = "";
std::string LocalizationCode = "";
// Diagnostic messages directory path.
/// Path to a directory of diagnostic localization tables.
std::string LocalizationPath = "";
/// Return a hash code of any components from these options that should

View File

@@ -65,6 +65,7 @@ class DiagnosticVerifier : public DiagnosticConsumer {
SourceManager &SM;
std::vector<CapturedDiagnosticInfo> CapturedDiagnostics;
ArrayRef<unsigned> BufferIDs;
SmallVector<unsigned, 4> AdditionalBufferIDs;
bool AutoApplyFixes;
bool IgnoreUnknown;
@@ -74,6 +75,10 @@ public:
: SM(SM), BufferIDs(BufferIDs), AutoApplyFixes(AutoApplyFixes),
IgnoreUnknown(IgnoreUnknown) {}
void appendAdditionalBufferID(unsigned bufferID) {
AdditionalBufferIDs.push_back(bufferID);
}
virtual void handleDiagnostic(SourceManager &SM,
const DiagnosticInfo &Info) override;

View File

@@ -560,8 +560,11 @@ private:
bool setUpInputs();
bool setUpASTContextIfNeeded();
void setupStatsReporter();
void setupDiagnosticVerifierIfNeeded();
void setupDependencyTrackerIfNeeded();
/// \return false if successsful, true on error.
bool setupDiagnosticVerifierIfNeeded();
Optional<unsigned> setUpCodeCompletionBuffer();
/// Find a buffer for a given input file and ensure it is recorded in

View File

@@ -114,6 +114,8 @@ def tbd_is_installapi: Flag<["-"], "tbd-is-installapi">,
def verify : Flag<["-"], "verify">,
HelpText<"Verify diagnostics against expected-{error|warning|note} "
"annotations">;
def verify_additional_file : Separate<["-"], "verify-additional-file">,
HelpText<"Verify diagnostics in this file in addition to source files">;
def verify_apply_fixes : Flag<["-"], "verify-apply-fixes">,
HelpText<"Like -verify, but updates the original source file">;
def verify_ignore_unknown: Flag<["-"], "verify-ignore-unknown">,

View File

@@ -957,6 +957,9 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowDiagnosticsAfterFatalError |=
Args.hasArg(OPT_show_diagnostics_after_fatal);
for (Arg *A : Args.filtered(OPT_verify_additional_file))
Opts.AdditionalVerifierFiles.push_back(A->getValue());
Opts.UseColor |=
Args.hasFlag(OPT_color_diagnostics,
OPT_no_color_diagnostics,

View File

@@ -978,7 +978,9 @@ void DiagnosticVerifier::handleDiagnostic(SourceManager &SM,
bool DiagnosticVerifier::finishProcessing() {
DiagnosticVerifier::Result Result = {false, false};
for (auto &BufferID : BufferIDs) {
ArrayRef<unsigned> BufferIDLists[2] = { BufferIDs, AdditionalBufferIDs };
for (ArrayRef<unsigned> BufferIDList : BufferIDLists)
for (auto &BufferID : BufferIDList) {
DiagnosticVerifier::Result FileResult = verifyFile(BufferID);
Result.HadError |= FileResult.HadError;
Result.HadUnexpectedDiag |= FileResult.HadUnexpectedDiag;

View File

@@ -290,15 +290,31 @@ void CompilerInstance::setupStatsReporter() {
Stats = std::move(Reporter);
}
void CompilerInstance::setupDiagnosticVerifierIfNeeded() {
bool CompilerInstance::setupDiagnosticVerifierIfNeeded() {
auto &diagOpts = Invocation.getDiagnosticOptions();
bool hadError = false;
if (diagOpts.VerifyMode != DiagnosticOptions::NoVerify) {
DiagVerifier = std::make_unique<DiagnosticVerifier>(
SourceMgr, InputSourceCodeBufferIDs,
diagOpts.VerifyMode == DiagnosticOptions::VerifyAndApplyFixes,
diagOpts.VerifyIgnoreUnknown);
for (const auto &filename : diagOpts.AdditionalVerifierFiles) {
auto result = getFileSystem().getBufferForFile(filename);
if (!result) {
Diagnostics.diagnose(SourceLoc(), diag::error_open_input_file,
filename, result.getError().message());
hadError |= true;
}
auto bufferID = SourceMgr.addNewSourceBuffer(std::move(result.get()));
DiagVerifier->appendAdditionalBufferID(bufferID);
}
addDiagnosticConsumer(DiagVerifier.get());
}
return hadError;
}
void CompilerInstance::setupDependencyTrackerIfNeeded() {
@@ -347,7 +363,9 @@ bool CompilerInstance::setup(const CompilerInvocation &Invok) {
return true;
setupStatsReporter();
setupDiagnosticVerifierIfNeeded();
if (setupDiagnosticVerifierIfNeeded())
return true;
return false;
}