Skip to content

Commit 9fc850a

Browse files
committed
[CodeCompletion] Lazily compute contextual diagnostics
1 parent 341bc34 commit 9fc850a

12 files changed

+146
-138
lines changed

include/swift/AST/DiagnosticsIDE.def

+8-4
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,21 @@
1717

1818
ERROR(ide_async_in_nonasync_context, none,
1919
"async %0 used in a context that does not support concurrency",
20-
(DeclName))
20+
(StringRef))
2121

2222
// NOTE: This is WARNING because this is emitted for cross actor references with
2323
// non-'Sendable' types. That is optionally ('-warn-concurrency') warning in
2424
// Swift 5.5.
2525
WARNING(ide_cross_actor_reference_swift5, none,
2626
"actor-isolated %0 should only be referenced from inside the actor",
27-
(DeclName))
27+
(StringRef))
2828

2929
WARNING(ide_redundant_import, none,
30-
"module %0 is already imported", (DeclName))
30+
"module %0 is already imported", (StringRef))
3131

3232
// FIXME: Inform which other 'import' this module came from.
3333
NOTE(ide_redundant_import_indirect, none,
34-
"module %0 is already imported via another module import", (DeclName))
34+
"module %0 is already imported via another module import", (StringRef))
3535

3636
WARNING(ide_availability_softdeprecated, Deprecation,
3737
"%select{getter for |setter for |}0%1 will be deprecated"
@@ -46,6 +46,10 @@ WARNING(ide_availability_softdeprecated_rename, Deprecation,
4646
": renamed to '%6'",
4747
(unsigned, DeclName, bool, StringRef, bool, llvm::VersionTuple, StringRef))
4848

49+
WARNING(ide_recursive_accessor_reference,none,
50+
"attempting to %select{access|modify}1 %0 within its own "
51+
"%select{getter|setter}1", (StringRef, bool))
52+
4953
//===----------------------------------------------------------------------===//
5054

5155
#define UNDEFINE_DIAGNOSTIC_MACROS

include/swift/IDE/CodeCompletionResult.h

+30-45
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,10 @@ class ContextFreeCodeCompletionResult {
341341
NullTerminatedStringRef DiagnosticMessage;
342342
NullTerminatedStringRef FilterName;
343343

344+
/// If the result represents a \c ValueDecl the name by which this decl should
345+
/// be refered to in diagnostics.
346+
NullTerminatedStringRef NameForDiagnostics;
347+
344348
public:
345349
/// Memberwise initializer. \p AssociatedKInd is opaque and will be
346350
/// interpreted based on \p Kind. If \p KnownOperatorKind is \c None and the
@@ -361,13 +365,15 @@ class ContextFreeCodeCompletionResult {
361365
ContextFreeNotRecommendedReason NotRecommended,
362366
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
363367
NullTerminatedStringRef DiagnosticMessage,
364-
NullTerminatedStringRef FilterName)
368+
NullTerminatedStringRef FilterName,
369+
NullTerminatedStringRef NameForDiagnostics)
365370
: Kind(Kind), KnownOperatorKind(KnownOperatorKind), IsSystem(IsSystem),
366371
CompletionString(CompletionString), ModuleName(ModuleName),
367372
BriefDocComment(BriefDocComment), AssociatedUSRs(AssociatedUSRs),
368373
ResultType(ResultType), NotRecommended(NotRecommended),
369374
DiagnosticSeverity(DiagnosticSeverity),
370-
DiagnosticMessage(DiagnosticMessage), FilterName(FilterName) {
375+
DiagnosticMessage(DiagnosticMessage), FilterName(FilterName),
376+
NameForDiagnostics(NameForDiagnostics) {
371377
this->AssociatedKind.Opaque = AssociatedKind;
372378
assert((NotRecommended == ContextFreeNotRecommendedReason::None) ==
373379
(DiagnosticSeverity == CodeCompletionDiagnosticSeverity::None) &&
@@ -491,6 +497,10 @@ class ContextFreeCodeCompletionResult {
491497

492498
NullTerminatedStringRef getFilterName() const { return FilterName; }
493499

500+
NullTerminatedStringRef getNameForDiagnostics() const {
501+
return NameForDiagnostics;
502+
}
503+
494504
bool isOperator() const {
495505
if (getKind() == CodeCompletionResultKind::Declaration) {
496506
switch (getAssociatedDeclKind()) {
@@ -528,11 +538,6 @@ class CodeCompletionResult {
528538
ContextualNotRecommendedReason NotRecommended : 4;
529539
static_assert(int(ContextualNotRecommendedReason::MAX_VALUE) < 1 << 4, "");
530540

531-
CodeCompletionDiagnosticSeverity DiagnosticSeverity : 3;
532-
static_assert(int(CodeCompletionDiagnosticSeverity::MAX_VALUE) < 1 << 3, "");
533-
534-
NullTerminatedStringRef DiagnosticMessage;
535-
536541
/// The number of bytes to the left of the code completion point that
537542
/// should be erased first if this completion string is inserted in the
538543
/// editor buffer.
@@ -553,14 +558,10 @@ class CodeCompletionResult {
553558
SemanticContextKind SemanticContext,
554559
CodeCompletionFlair Flair, uint8_t NumBytesToErase,
555560
CodeCompletionResultTypeRelation TypeDistance,
556-
ContextualNotRecommendedReason NotRecommended,
557-
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
558-
NullTerminatedStringRef DiagnosticMessage)
561+
ContextualNotRecommendedReason NotRecommended)
559562
: ContextFree(ContextFree), SemanticContext(SemanticContext),
560563
Flair(Flair.toRaw()), NotRecommended(NotRecommended),
561-
DiagnosticSeverity(DiagnosticSeverity),
562-
DiagnosticMessage(DiagnosticMessage), NumBytesToErase(NumBytesToErase),
563-
TypeDistance(TypeDistance) {}
564+
NumBytesToErase(NumBytesToErase), TypeDistance(TypeDistance) {}
564565

565566
public:
566567
/// Enrich a \c ContextFreeCodeCompletionResult with the following contextual
@@ -578,9 +579,7 @@ class CodeCompletionResult {
578579
const ExpectedTypeContext *TypeContext,
579580
const DeclContext *DC,
580581
const USRBasedTypeContext *USRTypeContext,
581-
ContextualNotRecommendedReason NotRecommended,
582-
CodeCompletionDiagnosticSeverity DiagnosticSeverity,
583-
NullTerminatedStringRef DiagnosticMessage);
582+
ContextualNotRecommendedReason NotRecommended);
584583

585584
const ContextFreeCodeCompletionResult &getContextFreeResult() const {
586585
return ContextFree;
@@ -699,37 +698,23 @@ class CodeCompletionResult {
699698
return getContextFreeResult().getAssociatedUSRs();
700699
}
701700

702-
/// Get the contextual diagnostic severity. This disregards context-free
703-
/// diagnostics.
704-
CodeCompletionDiagnosticSeverity getContextualDiagnosticSeverity() const {
705-
return DiagnosticSeverity;
706-
}
707-
708-
/// Get the contextual diagnostic message. This disregards context-free
709-
/// diagnostics.
710-
NullTerminatedStringRef getContextualDiagnosticMessage() const {
711-
return DiagnosticMessage;
712-
}
713-
714-
/// Return the contextual diagnostic severity if there was a contextual
715-
/// diagnostic. If there is no contextual diagnostic, return the context-free
716-
/// diagnostic severity.
717-
CodeCompletionDiagnosticSeverity getDiagnosticSeverity() const {
718-
if (NotRecommended != ContextualNotRecommendedReason::None) {
719-
return DiagnosticSeverity;
720-
} else {
721-
return getContextFreeResult().getDiagnosticSeverity();
722-
}
723-
}
724-
725-
/// Return the contextual diagnostic message if there was a contextual
726-
/// diagnostic. If there is no contextual diagnostic, return the context-free
727-
/// diagnostic message.
728-
NullTerminatedStringRef getDiagnosticMessage() const {
701+
/// Get the contextual diagnostic severity and message. This disregards
702+
/// context-free diagnostics.
703+
std::pair<CodeCompletionDiagnosticSeverity, NullTerminatedStringRef>
704+
getContextualDiagnosticSeverityAndMessage(SmallVectorImpl<char> &Scratch,
705+
const ASTContext &Ctx) const;
706+
707+
/// Return the contextual diagnostic severity and message if there was a
708+
/// contextual diagnostic. If there is no contextual diagnostic, return the
709+
/// context-free diagnostic severity and message.
710+
std::pair<CodeCompletionDiagnosticSeverity, NullTerminatedStringRef>
711+
getDiagnosticSeverityAndMessage(SmallVectorImpl<char> &Scratch,
712+
const ASTContext &Ctx) const {
729713
if (NotRecommended != ContextualNotRecommendedReason::None) {
730-
return DiagnosticMessage;
714+
return getContextualDiagnosticSeverityAndMessage(Scratch, Ctx);
731715
} else {
732-
return getContextFreeResult().getDiagnosticMessage();
716+
return std::make_pair(getContextFreeResult().getDiagnosticSeverity(),
717+
getContextFreeResult().getDiagnosticMessage());
733718
}
734719
}
735720

lib/IDE/CodeCompletionCache.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ CodeCompletionCache::~CodeCompletionCache() {}
103103
///
104104
/// This should be incremented any time we commit a change to the format of the
105105
/// cached results. This isn't expected to change very often.
106-
static constexpr uint32_t onDiskCompletionCacheVersion = 7; // Store whether a type can be used as attribute
106+
static constexpr uint32_t onDiskCompletionCacheVersion =
107+
8; // Store name for diagnostics
107108

108109
/// Deserializes CodeCompletionResults from \p in and stores them in \p V.
109110
/// \see writeCacheModule.
@@ -239,6 +240,7 @@ static bool readCachedModule(llvm::MemoryBuffer *in,
239240
auto briefDocIndex = read32le(cursor);
240241
auto diagMessageIndex = read32le(cursor);
241242
auto filterNameIndex = read32le(cursor);
243+
auto nameForDiagnosticsIndex = read32le(cursor);
242244

243245
auto assocUSRCount = read32le(cursor);
244246
SmallVector<NullTerminatedStringRef, 4> assocUSRs;
@@ -258,13 +260,14 @@ static bool readCachedModule(llvm::MemoryBuffer *in,
258260
auto briefDocComment = getString(briefDocIndex);
259261
auto diagMessage = getString(diagMessageIndex);
260262
auto filterName = getString(filterNameIndex);
263+
auto nameForDiagnostics = getString(nameForDiagnosticsIndex);
261264

262265
ContextFreeCodeCompletionResult *result =
263266
new (*V.Allocator) ContextFreeCodeCompletionResult(
264267
kind, associatedKind, opKind, isSystem, string, moduleName,
265268
briefDocComment, makeArrayRef(assocUSRs).copy(*V.Allocator),
266269
CodeCompletionResultType(resultTypes), notRecommended, diagSeverity,
267-
diagMessage, filterName);
270+
diagMessage, filterName, nameForDiagnostics);
268271

269272
V.Results.push_back(result);
270273
}
@@ -426,6 +429,7 @@ static void writeCachedModule(llvm::raw_ostream &out,
426429
LE.write(addString(R->getBriefDocComment())); // index into strings
427430
LE.write(addString(R->getDiagnosticMessage())); // index into strings
428431
LE.write(addString(R->getFilterName())); // index into strings
432+
LE.write(addString(R->getNameForDiagnostics())); // index into strings
429433

430434
LE.write(static_cast<uint32_t>(R->getAssociatedUSRs().size()));
431435
for (unsigned i = 0; i < R->getAssociatedUSRs().size(); ++i) {

lib/IDE/CodeCompletionConsumer.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,7 @@ static MutableArrayRef<CodeCompletionResult *> copyCodeCompletionResults(
8787
*contextFreeResult, SemanticContextKind::OtherModule,
8888
CodeCompletionFlair(),
8989
/*numBytesToErase=*/0, TypeContext, DC, &USRTypeContext,
90-
ContextualNotRecommendedReason::None,
91-
CodeCompletionDiagnosticSeverity::None, /*DiagnosticMessage=*/"");
90+
ContextualNotRecommendedReason::None);
9291
targetSink.Results.push_back(contextualResult);
9392
}
9493

lib/IDE/CodeCompletionDiagnostics.cpp

+16-13
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,12 @@ CodeCompletionDiagnosticSeverity getSeverity(DiagnosticKind DiagKind) {
4242
}
4343

4444
class CodeCompletionDiagnostics {
45-
ASTContext &Ctx;
45+
const ASTContext &Ctx;
4646
DiagnosticEngine &Engine;
4747

4848
public:
49-
CodeCompletionDiagnostics(ASTContext &Ctx) : Ctx(Ctx), Engine(Ctx.Diags) {}
49+
CodeCompletionDiagnostics(const ASTContext &Ctx)
50+
: Ctx(Ctx), Engine(Ctx.Diags) {}
5051

5152
template <typename... ArgTypes>
5253
bool
@@ -159,27 +160,29 @@ bool swift::ide::getContextFreeCompletionDiagnostics(
159160
}
160161

161162
bool swift::ide::getContextualCompletionDiagnostics(
162-
ContextualNotRecommendedReason Reason, const ValueDecl *D,
163-
CodeCompletionDiagnosticSeverity &Severity, llvm::raw_ostream &Out) {
164-
CodeCompletionDiagnostics Diag(D->getASTContext());
163+
ContextualNotRecommendedReason Reason, StringRef NameForDiagnostics,
164+
CodeCompletionDiagnosticSeverity &Severity, llvm::raw_ostream &Out,
165+
const ASTContext &Ctx) {
166+
CodeCompletionDiagnostics Diag(Ctx);
165167
switch (Reason) {
166168
case ContextualNotRecommendedReason::InvalidAsyncContext:
167169
// FIXME: Could we use 'diag::async_in_nonasync_function'?
168170
return Diag.getDiagnostics(
169-
Severity, Out, diag::ide_async_in_nonasync_context, D->getName());
171+
Severity, Out, diag::ide_async_in_nonasync_context, NameForDiagnostics);
170172
case ContextualNotRecommendedReason::CrossActorReference:
171-
return Diag.getDiagnostics(
172-
Severity, Out, diag::ide_cross_actor_reference_swift5, D->getName());
173+
return Diag.getDiagnostics(Severity, Out,
174+
diag::ide_cross_actor_reference_swift5,
175+
NameForDiagnostics);
173176
case ContextualNotRecommendedReason::RedundantImport:
174177
return Diag.getDiagnostics(Severity, Out, diag::ide_redundant_import,
175-
D->getName());
178+
NameForDiagnostics);
176179
case ContextualNotRecommendedReason::RedundantImportIndirect:
177180
return Diag.getDiagnostics(
178-
Severity, Out, diag::ide_redundant_import_indirect, D->getName());
181+
Severity, Out, diag::ide_redundant_import_indirect, NameForDiagnostics);
179182
case ContextualNotRecommendedReason::VariableUsedInOwnDefinition:
180-
return Diag.getDiagnostics(
181-
Severity, Out, diag::recursive_accessor_reference,
182-
D->getName().getBaseIdentifier(), /*"getter"*/ 0);
183+
return Diag.getDiagnostics(Severity, Out,
184+
diag::ide_recursive_accessor_reference,
185+
NameForDiagnostics, /*"getter"*/ 0);
183186
case ContextualNotRecommendedReason::None:
184187
llvm_unreachable("invalid not recommended reason");
185188
}

lib/IDE/CodeCompletionDiagnostics.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,17 @@ bool getContextFreeCompletionDiagnostics(
2929
ContextFreeNotRecommendedReason reason, const ValueDecl *D,
3030
CodeCompletionDiagnosticSeverity &severity, llvm::raw_ostream &Out);
3131

32-
/// Populate \p severity and \p Out with the contextual diagnostics for \p D.
32+
/// Populate \p severity and \p Out with the contextual for \p reason.
33+
/// \p NameForDiagnostic is the name of the decl that produced this diagnostic.
34+
/// \p Ctx is a context that's purely used to have a reference to a diagnostic
35+
/// engine.
3336
/// See \c NotRecommendedReason for an explaination of context-free vs.
3437
/// contextual diagnostics.
3538
/// Returns \c true if it fails to generate the diagnostics.
3639
bool getContextualCompletionDiagnostics(
37-
ContextualNotRecommendedReason reason, const ValueDecl *D,
38-
CodeCompletionDiagnosticSeverity &severity, llvm::raw_ostream &Out);
40+
ContextualNotRecommendedReason Reason, StringRef NameForDiagnostics,
41+
CodeCompletionDiagnosticSeverity &Severity, llvm::raw_ostream &Out,
42+
const ASTContext &Ctx);
3943

4044
} // namespace ide
4145
} // namespace swift

0 commit comments

Comments
 (0)