Skip to content

Commit d033052

Browse files
author
David Ungar
committed
suppress non-primary errors if there is no responsible primary
1 parent ee449ae commit d033052

File tree

3 files changed

+48
-13
lines changed

3 files changed

+48
-13
lines changed

include/swift/AST/DiagnosticConsumer.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,13 @@ class FileSpecificDiagnosticConsumer : public DiagnosticConsumer {
175175
/// diagnostics that are not in any of the other consumers' files.
176176
std::string inputFileName;
177177

178-
/// The consumer for diagnostics associated with the inputFileName.
179-
/// Should never be null, because diagnostics for non-primary files are
180-
/// either emitted in the corresponding primary file's .dia or are
181-
/// emitted to every .dia.
178+
/// The consumer (if any) for diagnostics associated with the inputFileName.
179+
/// A null pointer for the DiagnosticConsumer means that this file is a
180+
/// non-primary one in batch mode and we have no .dia file for it.
181+
/// If there is a responsible primary when the diagnostic is handled
182+
/// it will be shunted to that primary's .dia file.
183+
/// Otherwise it will be suppressed, assuming that the diagnostic will
184+
/// surface in another frontend job that compiles that file as a primary.
182185
std::unique_ptr<DiagnosticConsumer> consumer;
183186

184187
// Has this subconsumer ever handled a diagnostic that is an error?
@@ -198,6 +201,8 @@ class FileSpecificDiagnosticConsumer : public DiagnosticConsumer {
198201
ArrayRef<DiagnosticArgument> FormatArgs,
199202
const DiagnosticInfo &Info,
200203
const SourceLoc bufferIndirectlyCausingDiagnostic) {
204+
if (!getConsumer())
205+
return;
201206
hasAnErrorBeenConsumed |= Kind == DiagnosticKind::Error;
202207
getConsumer()->handleDiagnostic(SM, Loc, Kind, FormatString, FormatArgs,
203208
Info, bufferIndirectlyCausingDiagnostic);

lib/AST/DiagnosticConsumer.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ FileSpecificDiagnosticConsumer::subconsumerForLocation(SourceManager &SM,
117117
// Diagnostics with invalid locations always go to every consumer.
118118
if (loc.isInvalid())
119119
return None;
120+
121+
// What if a there's a consumer for fixits but there is no fixits output path?
122+
// Subconsumers will be empty in that case.
123+
if (Subconsumers.empty())
124+
return None;
120125

121126
// This map is generated on first use and cached, to allow the
122127
// FileSpecificDiagnosticConsumer to be set up before the source files are
@@ -207,13 +212,20 @@ Optional<FileSpecificDiagnosticConsumer::Subconsumer *>
207212
FileSpecificDiagnosticConsumer::findSubconsumerForNonNote(
208213
SourceManager &SM, const SourceLoc loc,
209214
const SourceLoc bufferIndirectlyCausingDiagnostic) {
210-
if (auto subconsumer = subconsumerForLocation(SM, loc))
215+
const auto subconsumer = subconsumerForLocation(SM, loc);
216+
if (!subconsumer)
217+
return None; // No place to put it; might be in an imported module
218+
if ((*subconsumer)->getConsumer())
211219
return subconsumer; // A primary file with a .dia file
212-
// The diagnostic is located in a non-primary.
213-
// Try to put it in the current primary file's .dia file.
214-
if (bufferIndirectlyCausingDiagnostic.isValid())
215-
return subconsumerForLocation(SM, bufferIndirectlyCausingDiagnostic);
216-
return None;
220+
// Try to put it in the responsible primary input
221+
if (bufferIndirectlyCausingDiagnostic.isInvalid())
222+
return None;
223+
const auto currentPrimarySubconsumer =
224+
subconsumerForLocation(SM, bufferIndirectlyCausingDiagnostic);
225+
assert(!currentPrimarySubconsumer ||
226+
(*currentPrimarySubconsumer)->getConsumer() &&
227+
"current primary must have a .dia file");
228+
return currentPrimarySubconsumer;
217229
}
218230

219231
bool FileSpecificDiagnosticConsumer::finishProcessing() {

lib/FrontendTool/FrontendTool.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,12 +1540,30 @@ createDispatchingDiagnosticConsumerIfNeeded(
15401540

15411541
inputsAndOutputs.forEachInputProducingSupplementaryOutput(
15421542
[&](const InputFile &input) -> bool {
1543-
if (auto consumer = maybeCreateConsumerForDiagnosticsFrom(input)) {
1544-
assert(consumer && "Consumer should always be non-null");
1543+
if (auto consumer = maybeCreateConsumerForDiagnosticsFrom(input))
15451544
subconsumers.emplace_back(input.file(), std::move(consumer));
1546-
}
15471545
return false;
15481546
});
1547+
// For batch mode, the compiler must sometimes swallow diagnostics pertaining to
1548+
// non-primary files in order to avoid Xcode showing the same diagnostic
1549+
// multiple times. So, create a diagnostic "eater" for those non-primary
1550+
// files.
1551+
//
1552+
// This routine gets called for \c createJSONFixItDiagnosticConsumerIfNeeded
1553+
// in cases where no primary subconsumers are created.
1554+
// Don't bother to create non-primary subconsumers if there aren't any primary
1555+
// ones.
1556+
//
1557+
// To avoid introducing bugs into WMO or single-file modes, test for multiple
1558+
// primaries.
1559+
if (!subconsumers.empty() && inputsAndOutputs.hasMultiplePrimaryInputs()) {
1560+
inputsAndOutputs.forEachNonPrimaryInput(
1561+
[&](const InputFile &input) -> bool {
1562+
subconsumers.emplace_back(input.file(), nullptr);
1563+
return false;
1564+
});
1565+
}
1566+
15491567
return FileSpecificDiagnosticConsumer::consolidateSubconsumers(subconsumers);
15501568
}
15511569

0 commit comments

Comments
 (0)