diff --git a/include/swift/IDE/CodeCompletion.h b/include/swift/IDE/CodeCompletion.h index bf391272600ed..5cfa91ebb0af5 100644 --- a/include/swift/IDE/CodeCompletion.h +++ b/include/swift/IDE/CodeCompletion.h @@ -492,6 +492,7 @@ enum class CompletionKind { TypeSimpleBeginning, TypeIdentifierWithDot, TypeIdentifierWithoutDot, + CaseStmtKeyword, CaseStmtBeginning, CaseStmtDotPrefix, NominalMemberBeginning, diff --git a/include/swift/Parse/CodeCompletionCallbacks.h b/include/swift/Parse/CodeCompletionCallbacks.h index ebe19822ff1e6..9079a293c4842 100644 --- a/include/swift/Parse/CodeCompletionCallbacks.h +++ b/include/swift/Parse/CodeCompletionCallbacks.h @@ -165,6 +165,9 @@ class CodeCompletionCallbacks { /// Complete a given type-identifier when there is no trailing dot. virtual void completeTypeIdentifierWithoutDot(IdentTypeRepr *ITR) {}; + /// Complete the beginning of a case statement at the top of switch stmt. + virtual void completeCaseStmtKeyword() {}; + /// Complete at the beginning of a case stmt pattern. virtual void completeCaseStmtBeginning() {}; diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 1490fb4ff6c4b..b61b5d967bc33 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -1185,8 +1185,6 @@ void CodeCompletionString::getName(raw_ostream &OS) const { } } } - assert((TextSize > 0) && - "code completion string should have non-empty name!"); } void CodeCompletionContext::sortCompletionResults( @@ -1348,6 +1346,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks { void completeTypeIdentifierWithDot(IdentTypeRepr *ITR) override; void completeTypeIdentifierWithoutDot(IdentTypeRepr *ITR) override; + void completeCaseStmtKeyword() override; void completeCaseStmtBeginning() override; void completeCaseStmtDotPrefix() override; void completeDeclAttrKeyword(Decl *D, bool Sil, bool Param) override; @@ -1823,6 +1822,32 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { llvm_unreachable("unhandled kind"); } + void addValueBaseName(CodeCompletionResultBuilder &Builder, + DeclBaseName Name) { + auto NameStr = Name.userFacingName(); + bool shouldEscapeKeywords; + if (Name.isSpecial()) { + // Special names (i.e. 'init') are always displayed as its user facing + // name. + shouldEscapeKeywords = false; + } else if (ExprType) { + // After dot. User can write any keyword after '.' except for `init` and + // `self`. E.g. 'func `init`()' must be called by 'expr.`init`()'. + shouldEscapeKeywords = NameStr == "self" || NameStr == "init"; + } else { + // As primary expresson. We have to escape almost every keywords except + // for 'self' and 'Self'. + shouldEscapeKeywords = NameStr != "self" && NameStr != "Self"; + } + + if (!shouldEscapeKeywords) { + Builder.addTextChunk(NameStr); + } else { + SmallString<16> buffer; + Builder.addTextChunk(Builder.escapeKeyword(NameStr, true, buffer)); + } + } + void addLeadingDot(CodeCompletionResultBuilder &Builder) { if (NeedOptionalUnwrap) { Builder.setNumBytesToErase(NumBytesToEraseForOptionalUnwrap); @@ -1995,7 +2020,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { VD->shouldHideFromEditor()) return; - StringRef Name = VD->getName().get(); + Identifier Name = VD->getName(); assert(!Name.empty() && "name should not be empty"); CommandWordsPairs Pairs; @@ -2005,7 +2030,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { getSemanticContext(VD, Reason), ExpectedTypes); Builder.setAssociatedDecl(VD); addLeadingDot(Builder); - Builder.addTextChunk(Name); + addValueBaseName(Builder, Name); setClangDeclKeywords(VD, Pairs, Builder); if (!VD->hasValidSignature()) @@ -2013,7 +2038,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { // Add a type annotation. Type VarType = getTypeOfMember(VD); - if (VD->getName() != Ctx.Id_self && VD->isInOut()) { + if (Name != Ctx.Id_self && VD->isInOut()) { // It is useful to show inout for function parameters. // But for 'self' it is just noise. VarType = InOutType::get(VarType); @@ -2222,14 +2247,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { else Builder.addAnnotatedLeftParen(); - bool anyParam = addCallArgumentPatterns(Builder, AFT->getParams(), - declParams, includeDefaultArgs); - - if (HaveLParen && !anyParam) { - // Empty result, don't add it. - Builder.cancel(); - return; - } + addCallArgumentPatterns(Builder, AFT->getParams(), declParams, + includeDefaultArgs); // The rparen matches the lparen here so that we insert both or neither. if (!HaveLParen) @@ -2319,7 +2338,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { return; foundFunction(FD); - StringRef Name = FD->getName().get(); + Identifier Name = FD->getName(); assert(!Name.empty() && "name should not be empty"); Type FunctionType = getTypeOfMember(FD); @@ -2350,7 +2369,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { setClangDeclKeywords(FD, Pairs, Builder); Builder.setAssociatedDecl(FD); addLeadingDot(Builder); - Builder.addTextChunk(Name); + addValueBaseName(Builder, Name); if (IsDynamicLookup) Builder.addDynamicLookupMethodCallTail(); else if (FD->getAttrs().hasAttribute()) @@ -2475,14 +2494,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { else Builder.addAnnotatedLeftParen(); - bool anyParam = addCallArgumentPatterns( - Builder, ConstructorType, CD->getParameters(), includeDefaultArgs); - - if (HaveLParen && !anyParam) { - // Empty result, don't add it. - Builder.cancel(); - return; - } + addCallArgumentPatterns(Builder, ConstructorType, CD->getParameters(), + includeDefaultArgs); // The rparen matches the lparen here so that we insert both or neither. if (!HaveLParen) @@ -2680,8 +2693,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { Builder.setAssociatedDecl(EED); setClangDeclKeywords(EED, Pairs, Builder); addLeadingDot(Builder); - - Builder.addTextChunk(EED->getName().str()); + addValueBaseName(Builder, EED->getName()); // Enum element is of function type; (Self.type) -> Self or // (Self.Type) -> (Args...) -> Self. @@ -2705,7 +2717,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { void addKeyword(StringRef Name, Type TypeAnnotation = Type(), SemanticContextKind SK = SemanticContextKind::None, CodeCompletionKeywordKind KeyKind - = CodeCompletionKeywordKind::None) { + = CodeCompletionKeywordKind::None, + unsigned NumBytesToErase = 0) { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Keyword, SK, ExpectedTypes); @@ -2714,6 +2727,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { Builder.setKeywordKind(KeyKind); if (TypeAnnotation) addTypeAnnotation(Builder, TypeAnnotation); + if (NumBytesToErase > 0) + Builder.setNumBytesToErase(NumBytesToErase); } void addKeyword(StringRef Name, StringRef TypeAnnotation, @@ -2759,7 +2774,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { // Base name addLeadingDot(Builder); - Builder.addTextChunk(AFD->getBaseName().userFacingName()); + addValueBaseName(Builder, AFD->getBaseName()); // Add the argument labels. auto ArgLabels = AFD->getFullName().getArgumentNames(); @@ -3600,6 +3615,15 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { return false; } + if (T->getOptionalObjectType() && + VD->getModuleContext()->isStdlibModule()) { + // In optional context, ignore '.init()', 'init(nilLiteral:)', + if (isa(VD)) + return false; + // TODO: Ignore '.some()' and '.none' too *in expression + // context*. They are useful in pattern context though. + } + // Enum element decls can always be referenced by implicit member // expression. if (isa(VD)) @@ -3670,6 +3694,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { // If this is optional type, perform completion for the object type. // i.e. 'let _: Enum??? = .enumMember' is legal. getUnresolvedMemberCompletions(objT->lookThroughAllOptionalTypes()); + + // Add 'nil' keyword with erasing '.' instruction. + unsigned bytesToErase = 0; + auto &SM = CurrDeclContext->getASTContext().SourceMgr; + if (DotLoc.isValid()) + bytesToErase = SM.getByteDistance(DotLoc, SM.getCodeCompletionLoc()); + addKeyword("nil", T, SemanticContextKind::ExpressionSpecific, + CodeCompletionKeywordKind::kw_nil, bytesToErase); } getUnresolvedMemberCompletions(T); } @@ -4417,6 +4449,11 @@ void CodeCompletionCallbacksImpl::completeTypeIdentifierWithoutDot( CurDeclContext = P.CurDeclContext; } +void CodeCompletionCallbacksImpl::completeCaseStmtKeyword() { + Kind = CompletionKind::CaseStmtKeyword; + CurDeclContext = P.CurDeclContext; +} + void CodeCompletionCallbacksImpl::completeCaseStmtBeginning() { assert(!InEnumElementRawValue); @@ -4598,6 +4635,11 @@ static void addStmtKeywords(CodeCompletionResultSink &Sink, bool MaybeFuncBody) #include "swift/Syntax/TokenKinds.def" } +static void addCaseStmtKeywords(CodeCompletionResultSink &Sink) { + addKeyword(Sink, "case", CodeCompletionKeywordKind::kw_case); + addKeyword(Sink, "default", CodeCompletionKeywordKind::kw_default); +} + static void addLetVarKeywords(CodeCompletionResultSink &Sink) { addKeyword(Sink, "let", CodeCompletionKeywordKind::kw_let); addKeyword(Sink, "var", CodeCompletionKeywordKind::kw_var); @@ -4687,6 +4729,10 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink, addAnyTypeKeyword(Sink); break; + case CompletionKind::CaseStmtKeyword: + addCaseStmtKeywords(Sink); + break; + case CompletionKind::PostfixExpr: case CompletionKind::PostfixExprParen: case CompletionKind::SuperExpr: @@ -4954,19 +5000,30 @@ void CodeCompletionCallbacksImpl::doneParsing() { bool OnRoot = !KPE->getComponents().front().isValid(); Lookup.setIsSwiftKeyPathExpr(OnRoot); - auto ParsedType = BGT->getGenericArgs()[1]; - auto Components = KPE->getComponents(); - if (Components.back().getKind() == - KeyPathExpr::Component::Kind::OptionalWrap) { + Type baseType = BGT->getGenericArgs()[OnRoot ? 0 : 1]; + if (OnRoot && baseType->is()) { + // Infer the root type of the keypath from the context type. + ExprContextInfo ContextInfo(CurDeclContext, ParsedExpr); + for (auto T : ContextInfo.getPossibleTypes()) { + if (auto unwrapped = T->getOptionalObjectType()) + T = unwrapped; + if (!T->getAnyNominal() || !T->getAnyNominal()->getKeyPathTypeKind() || + T->hasUnresolvedType() || !T->is()) + continue; + // Use the first KeyPath context type found. + baseType = T->castTo()->getGenericArgs()[0]; + break; + } + } + if (!OnRoot && KPE->getComponents().back().getKind() == + KeyPathExpr::Component::Kind::OptionalWrap) { // KeyPath expr with '?' (e.g. '\Ty.[0].prop?.another'). // Althogh expected type is optional, we should unwrap it because it's // unwrapped. - ParsedType = ParsedType->getOptionalObjectType(); + baseType = baseType->getOptionalObjectType(); } - // The second generic type argument of KeyPath should be - // the value we pull code completion results from. - Lookup.getValueExprCompletions(ParsedType); + Lookup.getValueExprCompletions(baseType); break; } @@ -5189,12 +5246,13 @@ void CodeCompletionCallbacksImpl::doneParsing() { } } break; - case CompletionKind::AfterIfStmtElse: - // Handled earlier by keyword completions. - break; case CompletionKind::PrecedenceGroup: Lookup.getPrecedenceGroupCompletions(SyntxKind); break; + case CompletionKind::AfterIfStmtElse: + case CompletionKind::CaseStmtKeyword: + // Handled earlier by keyword completions. + break; } for (auto &Request: Lookup.RequestedCachedResults) { diff --git a/lib/IDE/CodeCompletionResultBuilder.h b/lib/IDE/CodeCompletionResultBuilder.h index b28e678fb9853..be36cde1998b0 100644 --- a/lib/IDE/CodeCompletionResultBuilder.h +++ b/lib/IDE/CodeCompletionResultBuilder.h @@ -267,9 +267,8 @@ class CodeCompletionResultBuilder { addTypeAnnotation(Annotation); } - StringRef escapeArgumentLabel(StringRef Word, - bool escapeAllKeywords, - llvm::SmallString<16> &EscapedKeyword) { + StringRef escapeKeyword(StringRef Word, bool escapeAllKeywords, + llvm::SmallString<16> &EscapedKeyword) { bool shouldEscape = false; if (escapeAllKeywords) { #define KEYWORD(kw) .Case(#kw, true) @@ -325,7 +324,7 @@ class CodeCompletionResultBuilder { llvm::SmallString<16> EscapedKeyword; addChunkWithText( CodeCompletionString::Chunk::ChunkKind::CallParameterName, - escapeArgumentLabel(Name.str(), false, EscapedKeyword)); + escapeKeyword(Name.str(), false, EscapedKeyword)); addChunkWithTextNoCopy( CodeCompletionString::Chunk::ChunkKind::CallParameterColon, ": "); } else if (!LocalName.empty()) { @@ -333,7 +332,7 @@ class CodeCompletionResultBuilder { llvm::SmallString<16> EscapedKeyword; addChunkWithText( CodeCompletionString::Chunk::ChunkKind::CallParameterInternalName, - escapeArgumentLabel(LocalName.str(), false, EscapedKeyword)); + escapeKeyword(LocalName.str(), false, EscapedKeyword)); addChunkWithTextNoCopy( CodeCompletionString::Chunk::ChunkKind::CallParameterColon, ": "); } diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 32a1df2b8cdb0..5f3b2ede153f5 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -176,8 +176,8 @@ class ExprFinder : public ASTWalker { Expr *get() const { return FoundExpr; } std::pair walkToExprPre(Expr *E) override { - if (TargetRange == E->getSourceRange() && !isa(E) && - !isa(E) && !isa(E)) { + if (TargetRange == E->getSourceRange() && !E->isImplicit() && + !isa(E)) { assert(!FoundExpr && "non-nullptr for found expr"); FoundExpr = E; return {false, nullptr}; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 8f1fabcd1a3e6..d468395f1beb4 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -2273,6 +2273,11 @@ Parser::parseStmtCases(SmallVectorImpl &cases, bool IsActive) { if (auto PDD = PoundDiagnosticResult.getPtrOrNull()) { cases.emplace_back(PDD); } + } else if (Tok.is(tok::code_complete)) { + if (CodeCompletion) + CodeCompletion->completeCaseStmtKeyword(); + consumeToken(tok::code_complete); + return makeParserCodeCompletionStatus(); } else { // If there are non-case-label statements at the start of the switch body, // raise an error and recover by discarding them. diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index f41db09f6c3e1..9ecfd2bdfbdac 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -388,12 +388,18 @@ static void lookupDeclsFromProtocolsBeingConformedTo( NominalTypeDecl *CurrNominal = BaseTy->getAnyNominal(); if (!CurrNominal) return; + ModuleDecl *Module = FromContext->getParentModule(); for (auto Conformance : CurrNominal->getAllConformances()) { auto Proto = Conformance->getProtocol(); if (!Proto->isAccessibleFrom(FromContext)) continue; + // Skip unsatisfied conditional conformances. + if (Conformance->getConditionalRequirementsIfAvailable() && + !Module->conformsToProtocol(BaseTy, Proto)) + continue; + DeclVisibilityKind ReasonForThisProtocol; if (Reason == DeclVisibilityKind::MemberOfCurrentNominal) ReasonForThisProtocol = @@ -794,7 +800,10 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer { OtherSignature, OtherSignatureType, /*wouldConflictInSwift5*/nullptr, /*skipProtocolExtensionCheck*/true)) { - if (VD->getFormalAccess() > OtherVD->getFormalAccess()) { + if (VD->getFormalAccess() > OtherVD->getFormalAccess() || + //Prefer available one. + (!AvailableAttr::isUnavailable(VD) && + AvailableAttr::isUnavailable(OtherVD))) { PossiblyConflicting.erase(I); PossiblyConflicting.insert(VD); diff --git a/test/IDE/complete_after_super.swift b/test/IDE/complete_after_super.swift index ffedc24cfce09..1089743f4d30e 100644 --- a/test/IDE/complete_after_super.swift +++ b/test/IDE/complete_after_super.swift @@ -262,7 +262,9 @@ class SuperDerivedA : SuperBaseA { } init (b: Float) { super.init(#^CONSTRUCTOR_SUPER_INIT_PAREN_1^# -// CONSTRUCTOR_SUPER_INIT_PAREN_1-NOT: Pattern/ +// CONSTRUCTOR_SUPER_INIT_PAREN_1: Begin completions, 1 items +// CONSTRUCTOR_SUPER_INIT_PAREN_1: Pattern/CurrModule: ['('][')'][#SuperBaseA#]; name= +// CONSTRUCTOR_SUPER_INIT_PAREN_1: End completions } deinit { diff --git a/test/IDE/complete_call_arg.swift b/test/IDE/complete_call_arg.swift index 37f62ea6ac5e4..2583d18a1d17d 100644 --- a/test/IDE/complete_call_arg.swift +++ b/test/IDE/complete_call_arg.swift @@ -483,8 +483,9 @@ _ = EmptyOverload(foo: #^EMPTY_OVERLOAD_2^#) public func fopen() -> TestBoundGeneric1! { fatalError() } func other() { _ = fopen(#^CALLARG_IUO^#) -// CALLARG_IUO-NOT: Begin completions -// CALLARG_IUO-NOT: End completions +// CALLARG_IUO: Begin completions, 1 items +// CALLARG_IUO: Pattern/CurrModule: ['('][')'][#TestBoundGeneric1!#]; name= +// CALLARG_IUO: End completions } class Foo { let x: Int } diff --git a/test/IDE/complete_constrained.swift b/test/IDE/complete_constrained.swift index 3922d3f86393e..61e47121c2b13 100644 --- a/test/IDE/complete_constrained.swift +++ b/test/IDE/complete_constrained.swift @@ -48,19 +48,31 @@ extension MyStruct { func concreteExt_None_TConformsToSomeProto(_ x: U) -> Int where T: SomeProto { return 1 } } +protocol Proto_Int {} +extension Proto_Int { + func conditional_Int() -> Int { return 1 } +} +protocol Proto_String {} +extension Proto_String { + func conditional_String() -> Int { return 1 } +} +extension MyStruct: Proto_Int where T == Int{} +extension MyStruct: Proto_String where T == String {} + func foo(s: MyStruct) { let _ = s.#^MYSTRUCT_INT_DOT^# -// MYSTRUCT_INT_DOT: Begin completions, 6 items +// MYSTRUCT_INT_DOT: Begin completions, 7 items // MYSTRUCT_INT_DOT-DAG: Keyword[self]/CurrNominal: self[#MyStruct#]; name=self // MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/CurrNominal: methodWithConstrainedGenericParam({#x: SomeProto#})[#Int#]; name=methodWithConstrainedGenericParam(x: SomeProto) // MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/CurrNominal: concreteExt_TEqInt_None()[#Int#]; name=concreteExt_TEqInt_None() // MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/CurrNominal: concreteExt_None_TEqInt({#(x): U#})[#Int#]; name=concreteExt_None_TEqInt(x: U) // MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/Super: protoExt_AssocEqInt_None()[#Int#]; name=protoExt_AssocEqInt_None() // MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/Super: protoExt_None_AssocEqInt({#(x): U#})[#Int#]; name=protoExt_None_AssocEqInt(x: U) +// MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/Super: conditional_Int()[#Int#]; name=conditional_Int() // MYSTRUCT_INT_DOT: End completions let _ = MyStruct.#^META_MYSTRUCT_INT_DOT^# -// META_MYSTRUCT_INT_DOT: Begin completions, 10 items +// META_MYSTRUCT_INT_DOT: Begin completions, 11 items // META_MYSTRUCT_INT_DOT-DAG: Keyword[self]/CurrNominal: self[#MyStruct.Type#]; name=self // META_MYSTRUCT_INT_DOT-DAG: Keyword/CurrNominal: Type[#MyStruct.Type#]; name=Type // META_MYSTRUCT_INT_DOT-DAG: Decl[TypeAlias]/CurrNominal: Assoc[#T#]; name=Assoc @@ -71,6 +83,7 @@ func foo(s: MyStruct) { // META_MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/CurrNominal: concreteExt_None_TEqInt({#(self): MyStruct#})[#(U) -> Int#]; name=concreteExt_None_TEqInt(self: MyStruct) // META_MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/Super: protoExt_AssocEqInt_None({#(self): MyStruct#})[#() -> Int#]; name=protoExt_AssocEqInt_None(self: MyStruct) // META_MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/Super: protoExt_None_AssocEqInt({#(self): MyStruct#})[#(U) -> Int#]; name=protoExt_None_AssocEqInt(self: MyStruct) +// META_MYSTRUCT_INT_DOT-DAG: Decl[InstanceMethod]/Super: conditional_Int({#(self): MyStruct#})[#() -> Int#]; name=conditional_Int(self: MyStruct) // META_MYSTRUCT_INT_DOT: End completions } diff --git a/test/IDE/complete_constructor.swift b/test/IDE/complete_constructor.swift index ca65fd02efc13..f9788ade5f87c 100644 --- a/test/IDE/complete_constructor.swift +++ b/test/IDE/complete_constructor.swift @@ -47,6 +47,9 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CLOSURE_IN_INIT_3 | %FileCheck %s -check-prefix=CLOSURE_IN_INIT_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CLOSURE_IN_INIT_4 | %FileCheck %s -check-prefix=CLOSURE_IN_INIT_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=AVAILABLE_1 | %FileCheck %s -check-prefix=AVAILABLE_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=AVAILABLE_2 | %FileCheck %s -check-prefix=AVAILABLE_2 + func freeFunc() {} //===--- @@ -66,7 +69,9 @@ func testImplicitConstructors1() { } func testImplicitConstructors1P() { ImplicitConstructors1(#^IMPLICIT_CONSTRUCTORS_1P^# -// IMPLICIT_CONSTRUCTORS_1P-NOT: Begin completions +// IMPLICIT_CONSTRUCTORS_1P: Begin completions, 1 items +// IMPLICIT_CONSTRUCTORS_1P: Decl[Constructor]/CurrNominal: ['('][')'][#ImplicitConstructors1#]; name= +// IMPLICIT_CONSTRUCTORS_1P: End completions } struct ImplicitConstructors2 { @@ -86,6 +91,7 @@ func testImplicitConstructors2P() { ImplicitConstructors2(#^IMPLICIT_CONSTRUCTORS_2P^# // IMPLICIT_CONSTRUCTORS_2P: Begin completions // IMPLICIT_CONSTRUCTORS_2P-NEXT: Decl[Constructor]/CurrNominal: ['(']{#instanceVar: Int#}[')'][#ImplicitConstructors2#]{{; name=.+$}} +// IMPLICIT_CONSTRUCTORS_2P-NEXT: Decl[Constructor]/CurrNominal: ['('][')'][#ImplicitConstructors2#]; name= // IMPLICIT_CONSTRUCTORS_2P-NEXT: End completions } @@ -108,6 +114,7 @@ func testExplicitConstructors1() { func testExplicitConstructors1P() { ExplicitConstructors1(#^EXPLICIT_CONSTRUCTORS_1P^# // EXPLICIT_CONSTRUCTORS_1P: Begin completions +// EXPLICIT_CONSTRUCTORS_1P-NEXT: Decl[Constructor]/CurrNominal: ['('][')'][#ExplicitConstructors1#]; name= // EXPLICIT_CONSTRUCTORS_1P-NEXT: Decl[Constructor]/CurrNominal: ['(']{#a: Int#}[')'][#ExplicitConstructors1#]{{; name=.+$}} // EXPLICIT_CONSTRUCTORS_1P-NEXT: Decl[Constructor]/CurrNominal: ['(']{#a: Int#}, {#b: Float#}[')'][#ExplicitConstructors1#]{{; name=.+$}} // EXPLICIT_CONSTRUCTORS_1P-NEXT: End completions @@ -273,13 +280,16 @@ struct ExplicitConstructorsDerived3 { func testHaveRParen1() { ImplicitConstructors1(#^HAVE_RPAREN_1^#) -// HAVE_RPAREN_1-NOT: Decl[Constructor] +// HAVE_RPAREN_1: Begin completions, 1 items +// HAVE_RPAREN_1: Decl[Constructor]/CurrNominal: ['('][')'][#ImplicitConstructors1#]; name= +// HAVE_RPAREN_1: End completions } func testHaveRParen2() { ImplicitConstructors2(#^HAVE_RPAREN_2^#) // HAVE_RPAREN_2-NOT: Decl[Constructor] // HAVE_RPAREN_2: Decl[Constructor]/CurrNominal: ['(']{#instanceVar: Int#}[')'][#ImplicitConstructors2#]{{; name=.+$}} +// HAVE_RPAREN_2: Decl[Constructor]/CurrNominal: ['('][')'][#ImplicitConstructors2#]; name= // HAVE_RPAREN_2-NOT: Decl[Constructor] } @@ -332,3 +342,33 @@ struct ClosureInInit1 { S(#^CLOSURE_IN_INIT_4^# }() } + +public class AvailableTest { + + @available(swift, obsoleted: 4) + init(opt: Int) { } + + @available(swift, introduced: 4) + init?(opt: Int) { } + + init(normal1: Int) { } + init(normal2: Int) { } + + +} +func testAvailable() { + let _ = AvailableTest(#^AVAILABLE_1^# +// AVAILABLE_1: Begin completions, 3 items +// AVAILABLE_1-DAG: Decl[Constructor]/CurrNominal: ['(']{#opt: Int#}[')'][#AvailableTest?#]; name=opt: Int +// AVAILABLE_1-DAG: Decl[Constructor]/CurrNominal: ['(']{#normal1: Int#}[')'][#AvailableTest#]; name=normal1: Int +// AVAILABLE_1-DAG: Decl[Constructor]/CurrNominal: ['(']{#normal2: Int#}[')'][#AvailableTest#]; name=normal2: Int +// AVAILABLE_1: End completions + + let _ = AvailableTest.init(#^AVAILABLE_2^# +// AVAILABLE_2: Begin completions, 3 items +// AVAILABLE_2-DAG: Pattern/CurrModule: ['(']{#opt: Int#}[')'][#AvailableTest?#]; name=opt: Int +// AVAILABLE_2-DAG: Pattern/CurrModule: ['(']{#normal1: Int#}[')'][#AvailableTest#]; name=normal1: Int +// AVAILABLE_2-DAG: Pattern/CurrModule: ['(']{#normal2: Int#}[')'][#AvailableTest#]; name=normal2: Int +// AVAILABLE_2: End completions + +} diff --git a/test/IDE/complete_escaped_keyword.swift b/test/IDE/complete_escaped_keyword.swift new file mode 100644 index 0000000000000..43563f0a181f6 --- /dev/null +++ b/test/IDE/complete_escaped_keyword.swift @@ -0,0 +1,97 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_PRIMARY | %FileCheck %s -check-prefix=STATIC_PRIMARY +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_SELF_NODOT | %FileCheck %s -check-prefix=STATIC_SELF_NODOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STATIC_SELF_DOT | %FileCheck %s -check-prefix=STATIC_SELF_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=META_NODOT | %FileCheck %s -check-prefix=STATIC_SELF_NODOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=META_DOT | %FileCheck %s -check-prefix=STATIC_SELF_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_PRIMARY | %FileCheck %s -check-prefix=INSTANCE_PRIMARY +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_SELF_NODOT | %FileCheck %s -check-prefix=INSTANCE_SELF_NODOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INSTANCE_SELF_DOT | %FileCheck %s -check-prefix=INSTANCE_SELF_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=VALUE_NODOT | %FileCheck %s -check-prefix=INSTANCE_SELF_NODOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=VALUE_DOT | %FileCheck %s -check-prefix=INSTANCE_SELF_DOT + + +enum MyEnum { + case `class`(struct: String) + case `let`(`var`: String) + + init(`init`: String) {} + static func `public`(private: String) -> Int {} + + func `init`(deinit: String) -> Int {} + func `if`(else: String) -> Int {} + + var `self`: Int { return 0 } + + static func testStatic(meta: MyEnum.Type) { + let _ = #^STATIC_PRIMARY^# +// STATIC_PRIMARY: Begin completion +// STATIC_PRIMARY-DAG: Decl[LocalVar]/Local: self[#MyEnum.Type#]; name=self +// STATIC_PRIMARY-DAG: Decl[EnumElement]/CurrNominal: `class`({#struct: String#})[#MyEnum#]; name=`class`(struct: String) +// STATIC_PRIMARY-DAG: Decl[EnumElement]/CurrNominal: `let`({#`var`: String#})[#MyEnum#]; name=`let`(`var`: String) +// STATIC_PRIMARY-DAG: Decl[StaticMethod]/CurrNominal: `public`({#private: String#})[#Int#]; name=`public`(private: String) +// STATIC_PRIMARY-DAG: Decl[InstanceMethod]/CurrNominal: `init`({#(self): MyEnum#})[#(deinit: String) -> Int#]; name=`init`(self: MyEnum) +// STATIC_PRIMARY-DAG: Decl[InstanceMethod]/CurrNominal: `if`({#(self): MyEnum#})[#(else: String) -> Int#]; name=`if`(self: MyEnum) +// STATIC_PRIMARY: End completion + + let _ = self#^STATIC_SELF_NODOT^# +// STATIC_SELF_NODOT: Begin completions +// STATIC_SELF_NODOT-DAG: Keyword[self]/CurrNominal: .self[#MyEnum.Type#]; name=self +// STATIC_SELF_NODOT-DAG: Decl[EnumElement]/CurrNominal: .class({#struct: String#})[#MyEnum#]; name=class(struct: String) +// STATIC_SELF_NODOT-DAG: Decl[EnumElement]/CurrNominal: .let({#`var`: String#})[#MyEnum#]; name=let(`var`: String) +// STATIC_SELF_NODOT-DAG: Decl[Constructor]/CurrNominal: .init({#init: String#})[#MyEnum#]; name=init(init: String) +// STATIC_SELF_NODOT-DAG: Decl[StaticMethod]/CurrNominal: .public({#private: String#})[#Int#]; name=public(private: String) +// STATIC_SELF_NODOT-DAG: Decl[InstanceMethod]/CurrNominal: .`init`({#(self): MyEnum#})[#(deinit: String) -> Int#]; name=`init`(self: MyEnum) +// STATIC_SELF_NODOT-DAG: Decl[InstanceMethod]/CurrNominal: .if({#(self): MyEnum#})[#(else: String) -> Int#]; name=if(self: MyEnum) +// STATIC_SELF_NODOT: End completion + + let _ = self.#^STATIC_SELF_DOT^# +// STATIC_SELF_DOT: Begin completions +// STATIC_SELF_DOT-DAG: Keyword[self]/CurrNominal: self[#MyEnum.Type#]; name=self +// STATIC_SELF_DOT-DAG: Decl[EnumElement]/CurrNominal: class({#struct: String#})[#MyEnum#]; name=class(struct: String) +// STATIC_SELF_DOT-DAG: Decl[EnumElement]/CurrNominal: let({#`var`: String#})[#MyEnum#]; name=let(`var`: String) +// STATIC_SELF_DOT-DAG: Decl[Constructor]/CurrNominal: init({#init: String#})[#MyEnum#]; name=init(init: String) +// STATIC_SELF_DOT-DAG: Decl[StaticMethod]/CurrNominal: public({#private: String#})[#Int#]; name=public(private: String) +// STATIC_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal: `init`({#(self): MyEnum#})[#(deinit: String) -> Int#]; name=`init`(self: MyEnum) +// STATIC_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal: if({#(self): MyEnum#})[#(else: String) -> Int#]; name=if(self: MyEnum) +// STATIC_SELF_DOT: End completion + + let _ = meta#^META_NODOT^# +// SAME AS 'STATIC_SELF_NODOT'. + + let _ = meta.#^META_DOT^# +// SAME AS 'STATIC_SELF_DOT'. + } + + func testInstance(val: MyEnum) { + let _ = #^INSTANCE_PRIMARY^# +// INSTANCE_PRIMARY: Begin completion +// INSTANCE_PRIMARY-DAG: Decl[LocalVar]/Local: self[#MyEnum#]; name=self +// INSTANCE_PRIMARY-DAG: Decl[InstanceVar]/CurrNominal: self[#Int#]; name=self +// FIXME: ^ This is shadowed. We should hide this. +// INSTANCE_PRIMARY-DAG: Decl[InstanceMethod]/CurrNominal: `init`({#deinit: String#})[#Int#]; name=`init`(deinit: String) +// INSTANCE_PRIMARY-DAG: Decl[InstanceMethod]/CurrNominal: `if`({#else: String#})[#Int#]; name=`if`(else: String) +// INSTANCE_PRIMARY: End completion + + let _ = self#^INSTANCE_SELF_NODOT^# +// INSTANCE_SELF_NODOT: Begin completions +// INSTANCE_SELF_NODOT-DAG: Decl[InstanceMethod]/CurrNominal: .`init`({#deinit: String#})[#Int#]; name=`init`(deinit: String) +// INSTANCE_SELF_NODOT-DAG: Decl[InstanceMethod]/CurrNominal: .if({#else: String#})[#Int#]; name=if(else: String) +// INSTANCE_SELF_NODOT-DAG: Decl[InstanceVar]/CurrNominal: .`self`[#Int#]; name=`self` +// INSTANCE_SELF_NODOT-DAG: Keyword[self]/CurrNominal: .self[#MyEnum#]; name=self + +// INSTANCE_SELF_NODOT: End completions + + let _ = self.#^INSTANCE_SELF_DOT^# +// INSTANCE_SELF_DOT: Begin completions +// INSTANCE_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal: `init`({#deinit: String#})[#Int#]; name=`init`(deinit: String) +// INSTANCE_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal: if({#else: String#})[#Int#]; name=if(else: String) +// INSTANCE_SELF_DOT-DAG: Decl[InstanceVar]/CurrNominal: `self`[#Int#]; name=`self` +// INSTANCE_SELF_DOT-DAG: Keyword[self]/CurrNominal: self[#MyEnum#]; name=self +// INSTANCE_SELF_DOT: End completions + + let _ = val#^VALUE_NODOT^# +// SAME AS 'INSTANCE_SELF_NODOT'. + let _ = val.#^VALUE_DOT^# +// SAME AS 'INSTANCE_SELF_DOT'. + } +} diff --git a/test/IDE/complete_in_closures.swift b/test/IDE/complete_in_closures.swift index 2c5686dc3a8be..4b31be20239cd 100644 --- a/test/IDE/complete_in_closures.swift +++ b/test/IDE/complete_in_closures.swift @@ -55,6 +55,7 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_IIFE_2 | %FileCheck %s -check-prefix=IN_IIFE_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_IIFE_3 | %FileCheck %s -check-prefix=IN_IIFE_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_IIFE_4 | %FileCheck %s -check-prefix=IN_IIFE_1 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=ERROR_IN_CLOSURE_IN_INITIALIZER | %FileCheck %s -check-prefix=ERROR_IN_CLOSURE_IN_INITIALIZER // ERROR_COMMON: found code completion token // ERROR_COMMON-NOT: Begin completions @@ -369,3 +370,22 @@ func testIIFE() { // IN_IIFE_1: Begin completions // IN_IIFE_1-DAG: Decl[EnumElement]/ExprSpecific: north[#SomeEnum#] // IN_IIFE_1-DAG: Decl[EnumElement]/ExprSpecific: south[#SomeEnum#] + +extension Error { + var myErrorNumber: Int { return 0 } +} + +class C { + var foo: String = { + do { + } catch { + error.#^ERROR_IN_CLOSURE_IN_INITIALIZER^# +// ERROR_IN_CLOSURE_IN_INITIALIZER: Begin completions +// ERROR_IN_CLOSURE_IN_INITIALIZER-DAG: Keyword[self]/CurrNominal: self[#Error#]; name=self +// ERROR_IN_CLOSURE_IN_INITIALIZER-DAG: Decl[InstanceVar]/CurrNominal: myErrorNumber[#Int#]; name=myErrorNumber +// ERROR_IN_CLOSURE_IN_INITIALIZER: End completions + } + return "" + }() +} + diff --git a/test/IDE/complete_keywords.swift b/test/IDE/complete_keywords.swift index df191e55e86f8..8c648c6abec13 100644 --- a/test/IDE/complete_keywords.swift +++ b/test/IDE/complete_keywords.swift @@ -90,6 +90,9 @@ // RUN: %FileCheck %s -check-prefix=KW_EXPR < %t.expr6 // RUN: %FileCheck %s -check-prefix=KW_EXPR_NEG < %t.expr6 +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SWITCH_TOP | %FileCheck %s -check-prefix=KW_CASE +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SWITCH_IN_CASE | %FileCheck %s -check-prefix=KW_CASE + // KW_RETURN: Keyword[return]/None: return{{; name=.+$}} // KW_NO_RETURN-NOT: Keyword[return] @@ -401,3 +404,16 @@ func inExpr5() { func inExpr6() -> Int { return #^EXPR_6^# } + +func inSwitch(val: Int) { + switch val { + #^SWITCH_TOP^# + case 1: + foo() + #^SWITCH_IN_CASE^# + } +// Begin completions +// KW_CASE-DAG: Keyword[case]/None: case; name=case +// KW_CASE-DAG: Keyword[default]/None: default; name=default +// End completions +} diff --git a/test/IDE/complete_swift_key_path.swift b/test/IDE/complete_swift_key_path.swift index afe1963558aa4..f381cc4ec64e9 100644 --- a/test/IDE/complete_swift_key_path.swift +++ b/test/IDE/complete_swift_key_path.swift @@ -21,7 +21,9 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=EMPTY_2 | %FileCheck %s -check-prefix=INVALID // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXT_BASEONLY | %FileCheck %s -check-prefix=PERSONTYPE-DOT -// FIXME: RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXT_EXPLICIT | %FileCheck %s -check-prefix=INVALID +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXT_EXPLICIT | %FileCheck %s -check-prefix=PERSONTYPE-DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXT_GENERIC_RESULT | %FileCheck %s -check-prefix=PERSONTYPE-DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CONTEXT_GENERIC_RESULT_OPTIONAL | %FileCheck %s -check-prefix=PERSONTYPE-DOT class Person { var name: String @@ -131,9 +133,19 @@ let _ = \.#^EMPTY_1^# let _ = \.friends.#^EMPTY_2^# // INVALID-NOT: Begin completions -let _: PartialKeyPath = \.#^CONTEXT_BASEONLY^# -// Same as TYPE_DOT. - -let _: KeyPath = \.#^CONTEXT_EXPLICIT^# -// FIXME: Currently, it's suggest nothing. Since we know the base type is -// 'Person', we should suggest at least '.name'. +func recvPartialKP(_ kp: PartialKeyPath) { + recvPartialKP(\.#^CONTEXT_BASEONLY^#) + // Same as TYPE_DOT. +} +func recvExplicitKP(_ kp: KeyPath) { + recvExplicitKP(\.#^CONTEXT_EXPLICIT^#) + // Same as TYPE_DOT. +} +func recvExplicitKPWithGenericResult(_ kp: KeyPath) { + recvExplicitKPWithGenericResult(\.#^CONTEXT_GENERIC_RESULT^#) + // Same as TYPE_DOT. +} +func recvExplicitKPWithGenericResultOpt(_ kp: KeyPath?) { + recvExplicitKPWithGenericResult(\.#^CONTEXT_GENERIC_RESULT_OPTIONAL^# + // Same as TYPE_DOT. +} diff --git a/test/IDE/complete_unresolved_members.swift b/test/IDE/complete_unresolved_members.swift index dd7afdd82ed02..0695069fbfab4 100644 --- a/test/IDE/complete_unresolved_members.swift +++ b/test/IDE/complete_unresolved_members.swift @@ -14,6 +14,7 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_1 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPT // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_2 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPT // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_3 | %FileCheck %s -check-prefix=UNRESOLVED_3_OPTOPTOPT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_4 | %FileCheck %s -check-prefix=UNRESOLVED_OPT_4 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_12 | %FileCheck %s -check-prefix=UNRESOLVED_3 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_13 | %FileCheck %s -check-prefix=UNRESOLVED_3 @@ -240,7 +241,7 @@ class C4 { var _: SomeEnum1??? = .#^UNRESOLVED_OPT_3^# } } -// UNRESOLVED_3: Begin completions +// UNRESOLVED_3: Begin completions, 2 items // UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#]; name=North // UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#]; name=South // UNRESOLVED_3-NOT: SomeOptions1 @@ -248,21 +249,46 @@ class C4 { // UNRESOLVED_3-NOT: none // UNRESOLVED_3-NOT: some( -// UNRESOLVED_3_OPT: Begin completions +// UNRESOLVED_3_OPT: Begin completions, 5 items // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#]; // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#]; +// UNRESOLVED_3_OPT-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#SomeEnum1?#]; name=nil // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional#]; name=none // UNRESOLVED_3_OPT-DAG: Decl[EnumElement]/ExprSpecific: some({#SomeEnum1#})[#Optional#]; -// UNRESOLVED_3_OPT-DAG: Decl[Constructor]/CurrNominal: init({#(some): SomeEnum1#})[#Optional#]; -// UNRESOLVED_3_OPT-DAG: Decl[Constructor]/CurrNominal: init({#nilLiteral: ()#})[#Optional#]; +// UNRESOLVED_3_OPT-NOT: init({#(some): +// UNRESOLVED_3_OPT-NOT: init({#nilLiteral: -// UNRESOLVED_3_OPTOPTOPT: Begin completions +// UNRESOLVED_3_OPTOPTOPT: Begin completions, 5 items // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#]; // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: South[#SomeEnum1#]; +// UNRESOLVED_3_OPTOPTOPT-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#SomeEnum1???#]; name=nil // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional#]; name=none // UNRESOLVED_3_OPTOPTOPT-DAG: Decl[EnumElement]/ExprSpecific: some({#SomeEnum1??#})[#Optional#]; -// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[Constructor]/CurrNominal: init({#(some): SomeEnum1??#})[#Optional#]; -// UNRESOLVED_3_OPTOPTOPT-DAG: Decl[Constructor]/CurrNominal: init({#nilLiteral: ()#})[#Optional#]; +// UNRESOLVED_3_OPTOPTOPT-NOT: init({#(some): +// UNRESOLVED_3_OPTOPTOPT-NOT: init({#nilLiteral: + +enum Somewhere { + case earth, mars +} +extension Optional where Wrapped == Somewhere { + init(str: String) { fatalError() } + static var nowhere: Self { return nil } +} +func testOptionalWithCustomExtension() { + var _: Somewhere? = .#^UNRESOLVED_OPT_4^# +// UNRESOLVED_OPT_4: Begin completions, 7 items +// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: earth[#Somewhere#]; +// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: mars[#Somewhere#]; +// UNRESOLVED_OPT_4-DAG: Keyword[nil]/ExprSpecific/Erase[1]: nil[#Somewhere?#]; name=nil +// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: none[#Optional#]; name=none +// UNRESOLVED_OPT_4-DAG: Decl[EnumElement]/ExprSpecific: some({#Somewhere#})[#Optional#]; +// UNRESOLVED_OPT_4-DAG: Decl[Constructor]/CurrNominal: init({#str: String#})[#Optional#]; name=init(str: String) +// UNRESOLVED_OPT_4-DAG: Decl[StaticVar]/CurrNominal/TypeRelation[Identical]: nowhere[#Optional#]; name=nowhere +// UNRESOLVED_OPT_4-NOT: init({#(some): +// UNRESOLVED_OPT_4-NOT: init({#nilLiteral: +// UNRESOLVED_OPT_4: End completions +} + class C5 { func f1() { diff --git a/test/IDE/complete_value_expr.swift b/test/IDE/complete_value_expr.swift index 804c965e982ca..70756212ba6de 100644 --- a/test/IDE/complete_value_expr.swift +++ b/test/IDE/complete_value_expr.swift @@ -195,6 +195,11 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CLOSURE_IN_MEMBERDECLINIT_2 | %FileCheck %s -check-prefix=FOO_OBJECT_DOT // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=CLOSURE_IN_MEMBERDECLINIT_3 | %FileCheck %s -check-prefix=FOO_OBJECT_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_ARRAY_LITERAL_1 | %FileCheck %s -check-prefix=SIMPLE_OBJECT_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_ARRAY_LITERAL_2 | %FileCheck %s -check-prefix=SIMPLE_OBJECT_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_DICTIONARY_LITERAL_1 | %FileCheck %s -check-prefix=SIMPLE_OBJECT_DOT +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_DICTIONARY_LITERAL_2 | %FileCheck %s -check-prefix=SIMPLE_OBJECT_DOT + // Test code completion of expressions that produce a value. struct FooStruct { @@ -729,9 +734,9 @@ func testInsideFunctionCall0() { func testInsideFunctionCall1() { var a = FooStruct() a.instanceFunc0(#^INSIDE_FUNCTION_CALL_1^# -// There should be no results here because the function call -// unambiguously resolves to overload that takes 0 arguments. -// INSIDE_FUNCTION_CALL_1-NOT: Begin completions +// INSIDE_FUNCTION_CALL_1: Begin completions, 1 items +// INSIDE_FUNCTION_CALL_1: Pattern/CurrModule: ['('][')'][#Void#]; name= +// INSIDE_FUNCTION_CALL_1: End completions } func testInsideFunctionCall2() { @@ -782,8 +787,9 @@ func testInsideFunctionCall7() { func testInsideFunctionCall8(_ x: inout FooStruct) { x.instanceFunc0(#^INSIDE_FUNCTION_CALL_8^#) -// Since we already have '()', there is no pattern to complete. -// INSIDE_FUNCTION_CALL_8-NOT: Pattern/{{.*}}: +// INSIDE_FUNCTION_CALL_8: Begin completions +// INSIDE_FUNCTION_CALL_8: Pattern/CurrModule: ['('][')'][#Void#]; name= +// INSIDE_FUNCTION_CALL_8: End completions } func testInsideFunctionCall9(_ x: inout FooStruct) { x.instanceFunc1(#^INSIDE_FUNCTION_CALL_9^#) @@ -2143,3 +2149,25 @@ extension String { obj.#^CLOSURE_IN_MEMBERDECLINIT_3^# } } + +struct SimpleStruct { + func foo() -> SimpleStruct {} +} +// SIMPLE_OBJECT_DOT: Begin completions +// SIMPLE_OBJECT_DOT-DAG: Keyword[self]/CurrNominal: self[#SimpleStruct#]; name=self +// SIMPLE_OBJECT_DOT-DAG: Decl[InstanceMethod]/CurrNominal{{(/TypeRelation\[Identical\])?}}: foo()[#SimpleStruct#]; name=foo() +// SIMPLE_OBJECT_DOT: End completions +func testInCollectionLiteral(value: SimpleStruct) { + let _ = [ + value.#^IN_ARRAY_LITERAL_1^# + ] + let _ = [ + value.#^IN_ARRAY_LITERAL_2^#, + ] + let _: [String: String] = [ + value.#^IN_DICTIONARY_LITERAL_1^# + ] + let _: [String: String] = [ + value.#^IN_DICTIONARY_LITERAL_2^# : "test" + ] +}