Skip to content

Commit dbf848e

Browse files
committed
[CodeCompletion] Protect against a couple of null Types
Fix two crashes related to unresolved-member completion where either the EnumDecl itself is missing, or its elements have not been type-checked. Incidentally, resolve the type of the enum elements in the case where I have observed this happening. rdar://problem/26860249
1 parent 2141eac commit dbf848e

File tree

3 files changed

+41
-6
lines changed

3 files changed

+41
-6
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
26212621
(EED->hasAccessibility() && !EED->isAccessibleFrom(CurrDeclContext)) ||
26222622
shouldHideDeclFromCompletionResults(EED))
26232623
return;
2624+
26242625
CommandWordsPairs Pairs;
26252626
CodeCompletionResultBuilder Builder(
26262627
Sink,
@@ -2633,14 +2634,18 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
26332634
Builder.addTextChunk(EED->getName().str());
26342635
if (EED->hasArgumentType())
26352636
addPatternFromType(Builder, EED->getArgumentType());
2636-
Type EnumType = EED->getType();
26372637

26382638
// Enum element is of function type such as EnumName.type -> Int ->
26392639
// EnumName; however we should show Int -> EnumName as the type
2640-
if (auto FuncType = EED->getType()->getAs<AnyFunctionType>()) {
2641-
EnumType = FuncType->getResult();
2640+
Type EnumType;
2641+
if (EED->hasType()) {
2642+
EnumType = EED->getType();
2643+
if (auto FuncType = EnumType->getAs<AnyFunctionType>()) {
2644+
EnumType = FuncType->getResult();
2645+
}
26422646
}
2643-
addTypeAnnotation(Builder, EnumType);
2647+
if (EnumType)
2648+
addTypeAnnotation(Builder, EnumType);
26442649
}
26452650

26462651
void addKeyword(StringRef Name, Type TypeAnnotation,
@@ -2936,14 +2941,19 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
29362941
}
29372942
}
29382943

2939-
bool handleEnumElement(Decl *D, DeclVisibilityKind Reason) {
2944+
bool handleEnumElement(ValueDecl *D, DeclVisibilityKind Reason) {
2945+
if (!D->hasType())
2946+
TypeResolver->resolveDeclSignature(D);
2947+
29402948
if (auto *EED = dyn_cast<EnumElementDecl>(D)) {
29412949
addEnumElementRef(EED, Reason, /*HasTypeContext=*/true);
29422950
return true;
29432951
} else if (auto *ED = dyn_cast<EnumDecl>(D)) {
29442952
llvm::DenseSet<EnumElementDecl *> Elements;
29452953
ED->getAllElements(Elements);
29462954
for (auto *Ele : Elements) {
2955+
if (!Ele->hasType())
2956+
TypeResolver->resolveDeclSignature(Ele);
29472957
addEnumElementRef(Ele, Reason, /*HasTypeContext=*/true);
29482958
}
29492959
return true;
@@ -3655,7 +3665,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
36553665
LookupByName Lookup(*this, FuncNames);
36563666
lookupVisibleDecls(Lookup, CurrDeclContext, TypeResolver.get(), true);
36573667
if (HasReturn)
3658-
Lookup.unboxType(getReturnTypeFromContext(CurrDeclContext));
3668+
if (auto ReturnType = getReturnTypeFromContext(CurrDeclContext))
3669+
Lookup.unboxType(ReturnType);
36593670
}
36603671

36613672
static bool getPositionInTupleExpr(DeclContext &DC, Expr *Target,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
enum EnumFromOtherFile {
2+
case a(Int)
3+
case b(String)
4+
case c
5+
}

test/IDE/complete_unresolved_members.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=WITH_LITERAL_2 | FileCheck %s -check-prefix=WITH_LITERAL_1
4242
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=WITH_LITERAL_3 | FileCheck %s -check-prefix=WITH_LITERAL_1
4343

44+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INVALID_1
45+
46+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OTHER_FILE_1 %S/Inputs/EnumFromOtherFile.swift | FileCheck %s -check-prefix=OTHER_FILE_1
47+
4448
enum SomeEnum1 {
4549
case South
4650
case North
@@ -309,3 +313,18 @@ func testWithLiteral3() {
309313
}
310314
}
311315
}
316+
317+
func testInvalid1() {
318+
func invalid() -> NoSuchEnum {
319+
return .#^INVALID_1^# // Don't crash.
320+
}
321+
}
322+
323+
func enumFromOtherFile() -> EnumFromOtherFile {
324+
return .#^OTHER_FILE_1^# // Don't crash.
325+
}
326+
OTHER_FILE_1: Begin completions
327+
OTHER_FILE_1-DAG: Decl[EnumElement]/ExprSpecific: b({#String#})[#(String) -> EnumFromOtherFile#];
328+
OTHER_FILE_1-DAG: Decl[EnumElement]/ExprSpecific: a({#Int#})[#(Int) -> EnumFromOtherFile#];
329+
OTHER_FILE_1-DAG: Decl[EnumElement]/ExprSpecific: c[#EnumFromOtherFile#];
330+
OTHER_FILE_1: End completions

0 commit comments

Comments
 (0)