Skip to content

Commit 6abf057

Browse files
committed
Teach the verifier to emit fixits
Emit nicely formatted fixits that contain the expectations the user should have written.
1 parent 3f7c89a commit 6abf057

File tree

4 files changed

+45
-7
lines changed

4 files changed

+45
-7
lines changed

lib/Frontend/DependencyVerifier.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ struct Obligation {
224224
"Cannot form negative obligation!");
225225
}
226226

227+
Expectation::Scope getScope() const { return info.second; }
227228
Expectation::Kind getKind() const { return info.first; }
228229
StringRef getName() const { return name; }
229230
bool getCascades() const {
@@ -240,6 +241,22 @@ struct Obligation {
240241
}
241242
}
242243

244+
StringRef renderAsFixit(ASTContext &Ctx) const {
245+
llvm::StringRef selector =
246+
#define MATRIX_ENTRY(SELECTOR, SCOPE, KIND) \
247+
if (getKind() == Expectation::Kind::KIND && \
248+
getScope() == Expectation::Scope::SCOPE) { \
249+
return SELECTOR; \
250+
}
251+
252+
[this]() -> StringRef {
253+
EXPECTATION_MATRIX
254+
return "";
255+
}();
256+
#undef MATRIX_ENTRY
257+
return Ctx.AllocateCopy(("// " + selector + "{{" + getName() + "}}").str());
258+
}
259+
243260
public:
244261
bool isOwed() const { return state == State::Owed; }
245262
FullfillmentToken fullfill() {
@@ -439,17 +456,19 @@ bool DependencyVerifier::constructObligations(const SourceFile *SF,
439456
auto demContext = copyDemangledTypeName(Ctx, context);
440457
auto key = Ctx.AllocateCopy((demContext + "." + name).str());
441458
Obligations.insert({Obligation::Key::forMember(key),
442-
{context, Expectation::Kind::Member,
459+
{key, Expectation::Kind::Member,
443460
isCascadingUse ? Expectation::Scope::Cascading
444461
: Expectation::Scope::Private}});
445462
}
446463
break;
447-
case NodeKind::dynamicLookup:
464+
case NodeKind::dynamicLookup: {
465+
auto contextCpy = Ctx.AllocateCopy(context);
448466
Obligations.insert({Obligation::Key::forDynamicMember(name),
449-
{context, Expectation::Kind::DynamicMember,
467+
{contextCpy, Expectation::Kind::DynamicMember,
450468
isCascadingUse ? Expectation::Scope::Cascading
451469
: Expectation::Scope::Private}});
452470
break;
471+
}
453472
case NodeKind::topLevel:
454473
case NodeKind::sourceFileProvide:
455474
Obligations.insert({Obligation::Key::forProvides(name),
@@ -564,6 +583,7 @@ bool DependencyVerifier::diagnoseUnfulfilledObligations(
564583
CharSourceRange EntireRange = SM.getRangeForBuffer(*SF->getBufferID());
565584
StringRef InputFile = SM.extractText(EntireRange);
566585
auto &diags = SF->getASTContext().Diags;
586+
auto &Ctx = SF->getASTContext();
567587
forEachOwedObligation(Obligations, [&](StringRef key, Obligation &p) {
568588
// HACK: Diagnosing the end of the buffer will print a carat pointing
569589
// at the file path, but not print any of the buffer's contents, which
@@ -576,10 +596,12 @@ bool DependencyVerifier::diagnoseUnfulfilledObligations(
576596
case Expectation::Kind::DynamicMember:
577597
case Expectation::Kind::PotentialMember:
578598
diags.diagnose(Loc, diag::unexpected_dependency, p.describeCascade(),
579-
static_cast<uint8_t>(p.getKind()), key);
599+
static_cast<uint8_t>(p.getKind()), key)
600+
.fixItInsert(Loc, p.renderAsFixit(Ctx));
580601
break;
581602
case Expectation::Kind::Provides:
582-
diags.diagnose(Loc, diag::unexpected_provided_entity, p.getName());
603+
diags.diagnose(Loc, diag::unexpected_provided_entity, p.getName())
604+
.fixItInsert(Loc, p.renderAsFixit(Ctx));
583605
break;
584606
}
585607
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// REQUIRES: OS=windows-msvc
2+
// This test is special-cased on Windows because dependencies in Two.swift don't
3+
// appear to be registered against the tracker. rdar://60030114
4+
5+
// RUN: %empty-directory(%t)
6+
// RUN: %{python} %S/../gen-output-file-map.py -o %t %S/Inputs -r %t.resp
7+
// RUN: cd %t
8+
// RUN: not %target-swiftc_driver -no-color-diagnostics -typecheck -output-file-map %t/output.json -incremental -module-name main -verify-incremental-dependencies @%t.resp 2>&1 | sort | %FileCheck %s
9+
10+
// CHECK: unexpected cascading member dependency: main.Base.init
11+
// CHECK: unexpected cascading potential member dependency: main.Base
12+
// CHECK: unexpected provided entity: Base
13+
// CHECK: unexpected provided entity: BaseProtocol

test/Incremental/fail/main.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// UNSUPPORTED: OS=windows-msvc
2+
// See its counterpart main-windows.swift
3+
14
// RUN: %empty-directory(%t)
25
// RUN: %{python} %S/../gen-output-file-map.py -o %t %S/Inputs -r %t.resp
36
// RUN: cd %t

test/Incremental/gen-output-file-map.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ def main(arguments):
6161
'swift-dependencies': './main-buildrecord.swiftdeps'
6262
}
6363

64-
with open(output_path, 'w') as f:
64+
with open(output_path, 'wb') as f:
6565
json.dump(all_records, f)
6666

6767
if args.response_output_file is not None:
68-
with open(args.response_output_file, 'w') as f:
68+
with open(args.response_output_file, 'wb') as f:
6969
for line in response_file_contents:
7070
f.write(line + " ")
7171

0 commit comments

Comments
 (0)