From bb9482bab59f0f4e163098a5cda9cc64fc10a072 Mon Sep 17 00:00:00 2001 From: fischertony Date: Fri, 5 Oct 2018 23:05:56 +0300 Subject: [PATCH 1/4] [CodeCompletion][Parser] Completions for overridable static members --- include/swift/AST/PrintOptions.h | 3 + lib/AST/ASTPrinter.cpp | 4 +- lib/IDE/CodeCompletion.cpp | 32 +++++++--- lib/Parse/ParseDecl.cpp | 5 ++ test/IDE/complete_override.swift | 88 +++++++++++++++++++++++++-- test/IDE/complete_override_objc.swift | 10 ++- 6 files changed, 128 insertions(+), 14 deletions(-) diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index c1a8290d1c1..117a0ca19c6 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -275,6 +275,9 @@ struct PrintOptions { /// '@sil_weak', '@sil_unmanaged'. bool PrintStorageRepresentationAttrs = false; + /// Whether to print 'static' or 'class' on static decls. + bool PrintStaticKeyword = true; + /// Whether to print 'override' keyword on overridden decls. bool PrintOverrideKeyword = true; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index aca9114739d..4f31d370c0b 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2403,7 +2403,7 @@ void PrintAST::visitVarDecl(VarDecl *decl) { printAttributes(decl); printAccess(decl); if (!Options.SkipIntroducerKeywords) { - if (decl->isStatic()) + if (decl->isStatic() && Options.PrintStaticKeyword) printStaticKeyword(decl->getCorrectStaticSpelling()); if (decl->getKind() == DeclKind::Var || Options.PrintParameterSpecifiers) { @@ -2679,7 +2679,7 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) { printSourceRange(Range, Ctx); } else { if (!Options.SkipIntroducerKeywords) { - if (decl->isStatic()) + if (decl->isStatic() && Options.PrintStaticKeyword) printStaticKeyword(decl->getCorrectStaticSpelling()); if (decl->isMutating() && !decl->getAttrs().hasAttribute()) { Printer.printKeyword("mutating", Options, " "); diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index c1af15fa07e..53351aee00e 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -3867,6 +3867,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer { bool hasAccessModifier = false; bool hasOverride = false; bool hasOverridabilityModifier = false; + bool hasStaticOrClass = false; public: CompletionOverrideLookup(CodeCompletionResultSink &Sink, ASTContext &Ctx, @@ -3891,6 +3892,8 @@ public: hasOverride = isKeywordSpecified("override"); hasOverridabilityModifier = isKeywordSpecified("final") || isKeywordSpecified("open"); + hasStaticOrClass = isKeywordSpecified(getTokenText(tok::kw_class)) || + isKeywordSpecified(getTokenText(tok::kw_static)); } bool isKeywordSpecified(StringRef Word) { @@ -3942,6 +3945,7 @@ public: Options.ExclusiveAttrList.push_back(TAK_escaping); Options.PrintOverrideKeyword = false; Options.PrintPropertyAccessors = false; + Options.PrintStaticKeyword = !hasStaticOrClass; VD->print(Printer, Options); NameOffset = Printer.NameOffset.getValue(); } @@ -3951,7 +3955,7 @@ public: // FIXME: if we're missing 'override', but have the decl introducer we // should delete it and re-add both in the correct order. - if (!hasDeclIntroducer && missingOverride(Reason)) + if (!hasDeclIntroducer && !hasStaticOrClass && missingOverride(Reason)) Builder.addOverrideKeyword(); if (!hasDeclIntroducer) @@ -4048,7 +4052,9 @@ public: if (D->shouldHideFromEditor()) return; - if (D->getAttrs().hasAttribute()) + if (D->getAttrs().hasAttribute() || + // A 'class' member with an initial value cannot be overriden either. + (D->isStatic() && D->getAttrs().hasAttribute())) return; if (!D->hasInterfaceType()) @@ -4058,6 +4064,15 @@ public: hasVarIntroducer || hasTypealiasIntroducer; + if (hasStaticOrClass && !D->isStatic()) + return; + + // As per the current convention, only instance members are + // suggested if an introducer is not accompanied by a 'static' or + // 'class' modifier. + if (hasIntroducer && !hasStaticOrClass && D->isStatic()) + return; + if (auto *FD = dyn_cast(D)) { // We cannot override operators as members. if (FD->isBinaryOperator() || FD->isUnaryOperator()) @@ -4081,7 +4096,8 @@ public: if (auto *CD = dyn_cast(D)) { if (!isa(CD->getDeclContext())) return; - if (hasIntroducer || hasOverride || hasOverridabilityModifier) + if (hasIntroducer || hasOverride || hasOverridabilityModifier || + hasStaticOrClass) return; if (CD->isRequired() || CD->isDesignatedInit()) addConstructor(CD, Reason); @@ -4091,7 +4107,7 @@ public: void addDesignatedInitializers(NominalTypeDecl *NTD) { if (hasFuncIntroducer || hasVarIntroducer || hasTypealiasIntroducer || - hasOverridabilityModifier) + hasOverridabilityModifier || hasStaticOrClass) return; const auto *CD = dyn_cast(NTD); @@ -4114,7 +4130,7 @@ public: void addAssociatedTypes(NominalTypeDecl *NTD) { if (!hasTypealiasIntroducer && (hasFuncIntroducer || hasVarIntroducer || hasInitializerModifier || - hasOverride || hasOverridabilityModifier)) + hasOverride || hasOverridabilityModifier || hasStaticOrClass)) return; for (auto Conformance : NTD->getAllConformances()) { @@ -4145,9 +4161,11 @@ public: Type CurrTy = CurrDeclContext->getSelfTypeInContext(); auto *NTD = CurrDeclContext->getSelfNominalTypeDecl(); if (CurrTy && !CurrTy->is()) { - lookupVisibleMemberDecls(*this, CurrTy, CurrDeclContext, + // Look for overridable static members too. + Type Meta = MetatypeType::get(CurrTy); + lookupVisibleMemberDecls(*this, Meta, CurrDeclContext, TypeResolver, - /*includeInstanceMembers=*/false); + /*includeInstanceMembers=*/true); addDesignatedInitializers(NTD); addAssociatedTypes(NTD); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 4fdc230654b..f2cf7a0ef67 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2944,6 +2944,11 @@ Parser::parseDecl(ParseDeclOptions Flags, // Other tokens are already accounted for. break; } + if (StaticSpelling == StaticSpellingKind::KeywordStatic) { + Keywords.push_back(getTokenText(tok::kw_static)); + } else if (StaticSpelling == StaticSpellingKind::KeywordClass) { + Keywords.push_back(getTokenText(tok::kw_class)); + } for (auto attr : Attributes) { Keywords.push_back(attr->getAttrName()); } diff --git a/test/IDE/complete_override.swift b/test/IDE/complete_override.swift index 0d455a99735..abf17c2320f 100644 --- a/test/IDE/complete_override.swift +++ b/test/IDE/complete_override.swift @@ -130,6 +130,16 @@ // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER12 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER9 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER13 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER13 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER14 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER9 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER15 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER15 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER16 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER15 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER17 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER15 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER18 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER15 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER19 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER13 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER20 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER13 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER21 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER21 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER22 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER21 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER23 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER23 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER24 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER23 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=PROTOINIT_NORM -code-completion-keywords=false | %FileCheck %s -check-prefix=PROTOINIT_NORM // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=PROTOINIT_FINAL -code-completion-keywords=false | %FileCheck %s -check-prefix=PROTOINIT_FINAL @@ -563,13 +573,26 @@ class Escaping : EscapingBase { // ESCAPING_1: Decl[InstanceMethod]/Super: method(_ x: @escaping (@escaping () -> ()) -> (() -> ())) -> ((@escaping () -> ()) -> ()) {|}; class OverrideBase { + static let staticLet = 0 + static var staticVar = 0 + static var staticGetOnlyVar: Int { return 0 } + + class let classLet = 0 + class var classVar = 0 + class var classGetOnlyVar: Int { return 0 } + + static func staticMethod() {} + class func classMethod() {} + + let letDecl = 0 + var varDecl: Int = 0 + init(x: Int) {} convenience init(y: Int) { self.init(x: y) } required init(a: Int) {} required convenience init(b: Int) {} func defaultMethod() {} final func finalMethod() {} - var varDecl: Int = 0 open func openMethod() {} } protocol OverrideP { @@ -631,9 +654,49 @@ class Override14 : OverrideBase, OverrideP { override let #^MODIFIER14^# // Same as MODIFIER9. } +class Override15 : OverrideBase, OverrideP { + required static var #^MODIFIER15^# +} +class Override16 : OverrideBase, OverrideP { + override class var #^MODIFIER16^# + // Same as MODIFIER15 +} +class Override17 : OverrideBase, OverrideP { + // Note: This *does* emit variables. See MODIFIER14 + override static let #^MODIFIER17^# + // Same as MODIFIER15 +} +class Override18 : OverrideBase, OverrideP { + class var #^MODIFIER18^# + // Same as MODIFIER15 +} +class Override19 : OverrideBase, OverrideP { + // No completions. + class let #^MODIFIER19^# +} +class Override20 : OverrideBase, OverrideP { + // No completions. + static let #^MODIFIER20^# +} +class Override21 : OverrideBase, OverrideP { + override class func #^MODIFIER21^# +} +class Override22 : OverrideBase, OverrideP { + class func #^MODIFIER22^# + // Same as MODIFIER21 +} +class Override23 : OverrideBase, OverrideP { + static #^MODIFIER23^# +} +class Override24 : OverrideBase, OverrideP { + override static #^MODIFIER24^# + // Same as MODIFIER23 +} -// MODIFIER1: Begin completions, 7 items +// MODIFIER1: Begin completions, 9 items // MODIFIER1-DAG: Decl[Constructor]/Super: required init(p: Int) {|}; name=required init(p: Int) +// MODIFIER1-DAG: Decl[StaticMethod]/Super: override class func classMethod() {|}; name=classMethod() +// MODIFIER1-DAG: Decl[StaticVar]/Super: override class var classGetOnlyVar: Int; name=classGetOnlyVar: Int // MODIFIER1-DAG: Decl[InstanceMethod]/Super: override func defaultMethod() {|}; name=defaultMethod() // MODIFIER1-DAG: Decl[InstanceMethod]/Super: override func openMethod() {|}; name=openMethod() // MODIFIER1-DAG: Decl[InstanceVar]/Super: override var varDecl: Int; name=varDecl: Int @@ -642,7 +705,9 @@ class Override14 : OverrideBase, OverrideP { // MODIFIER1-DAG: Decl[AssociatedType]/Super: typealias Assoc = {#(Type)#}; name=Assoc = Type // MODIFIER1: End completions -// MODIFIER2: Begin completions, 3 items +// MODIFIER2: Begin completions, 5 items +// MODIFIER2-DAG: Decl[StaticVar]/Super: override class var classGetOnlyVar: Int; name=classGetOnlyVar: Int +// MODIFIER2-DAG: Decl[StaticMethod]/Super: override class func classMethod() {|}; name=classMethod() // MODIFIER2-DAG: Decl[InstanceMethod]/Super: override func defaultMethod() {|}; name=defaultMethod() // MODIFIER2-DAG: Decl[InstanceMethod]/Super: override func openMethod() {|}; name=openMethod() // MODIFIER2-DAG: Decl[InstanceVar]/Super: override var varDecl: Int; name=varDecl: Int @@ -664,7 +729,9 @@ class Override14 : OverrideBase, OverrideP { // MODIFIER6-DAG: Decl[AssociatedType]/Super: Assoc = {#(Type)#}; name=Assoc = Type // MODIFIER6: End completions -// MODIFIER7: Begin completions, 5 items +// MODIFIER7: Begin completions, 7 items +// MODIFIER7-DAG: Decl[StaticVar]/Super: class var classGetOnlyVar: Int; name=classGetOnlyVar: Int +// MODIFIER7-DAG: Decl[StaticMethod]/Super: class func classMethod() {|}; name=classMethod() // MODIFIER7-DAG: Decl[InstanceMethod]/Super: func defaultMethod() {|}; name=defaultMethod() // MODIFIER7-DAG: Decl[InstanceVar]/Super: var varDecl: Int; name=varDecl: Int // MODIFIER7-DAG: Decl[InstanceMethod]/Super: func openMethod() {|}; name=openMethod() @@ -683,6 +750,19 @@ class Override14 : OverrideBase, OverrideP { // MODIFIER13-NOT: Begin completions +// MODIFIER15: Begin completions, 1 items +// MODIFIER15-DAG: Decl[StaticVar]/Super: classGetOnlyVar: Int; name=classGetOnlyVar: Int +// MODIFIER15: End completions + +// MODIFIER21: Begin completions, 1 items +// MODIFIER21: Decl[StaticMethod]/Super: classMethod() {|}; name=classMethod() +// MODIFIER21: End completions + +// MODIFIER23: Begin completions, 2 items +// MODIFIER23-DAG: Decl[StaticMethod]/Super: func classMethod() {|}; name=classMethod() +// MODIFIER23-DAG: Decl[StaticVar]/Super: var classGetOnlyVar: Int; name=classGetOnlyVar: Int +// MODIFIER23: End completions + protocol RequiredP { init(p: Int) } diff --git a/test/IDE/complete_override_objc.swift b/test/IDE/complete_override_objc.swift index a5a8036aba3..5966a96021a 100644 --- a/test/IDE/complete_override_objc.swift +++ b/test/IDE/complete_override_objc.swift @@ -10,13 +10,21 @@ class Sub : FooClassBase { #^PA^# } -// CHECK1: Begin completions, 8 items +// CHECK1: Begin completions, 16 items +// CHECK1: Decl[StaticMethod]/Super: override class func fooBaseInstanceFunc0() {|} // CHECK1: Decl[InstanceMethod]/Super: override func fooBaseInstanceFunc0() {|} +// CHECK1: Decl[StaticMethod]/Super: override class func fooBaseInstanceFunc1(_ anObject: Any!) -> FooClassBase! {|} // CHECK1: Decl[InstanceMethod]/Super: override func fooBaseInstanceFunc1(_ anObject: Any!) -> FooClassBase! {|} +// CHECK1: Decl[StaticMethod]/Super: override class func fooBaseInstanceFuncOverridden() {|} // CHECK1: Decl[InstanceMethod]/Super: override func fooBaseInstanceFuncOverridden() {|} +// CHECK1: Decl[StaticMethod]/Super: override class func fooBaseClassFunc0() {|} +// CHECK1: Decl[StaticMethod]/Super: override class func _internalMeth3() -> Any! {|} // CHECK1: Decl[InstanceMethod]/Super: override func _internalMeth3() -> Any! {|} +// CHECK1: Decl[StaticMethod]/Super: override class func _internalMeth2() -> Any! {|} // CHECK1: Decl[InstanceMethod]/Super: override func _internalMeth2() -> Any! {|} +// CHECK1: Decl[StaticMethod]/Super: override class func nonInternalMeth() -> Any! {|} // CHECK1: Decl[InstanceMethod]/Super: override func nonInternalMeth() -> Any! {|} +// CHECK1: Decl[StaticMethod]/Super: override class func _internalMeth1() -> Any! {|} // CHECK1: Decl[InstanceMethod]/Super: override func _internalMeth1() -> Any! {|} // CHECK1: Decl[Constructor]/Super: override init!() {|} // CHECK1: End completions From 86d9d7a6b5534b0eebd023593b0a9efafb8de640 Mon Sep 17 00:00:00 2001 From: fischertony Date: Wed, 13 Feb 2019 19:33:46 +0300 Subject: [PATCH 2/4] Fix override completions when a valid introducer is present but the override keyword is not. --- include/swift/Parse/CodeCompletionCallbacks.h | 2 +- lib/IDE/CodeCompletion.cpp | 32 ++++++---- lib/Parse/ParseDecl.cpp | 5 +- test/IDE/complete_declname.swift | 2 +- test/IDE/complete_override.swift | 59 +++++++++++-------- test/IDE/complete_override_objc.swift | 6 +- 6 files changed, 67 insertions(+), 39 deletions(-) diff --git a/include/swift/Parse/CodeCompletionCallbacks.h b/include/swift/Parse/CodeCompletionCallbacks.h index f26f554e66b..ebe19822ff1 100644 --- a/include/swift/Parse/CodeCompletionCallbacks.h +++ b/include/swift/Parse/CodeCompletionCallbacks.h @@ -174,7 +174,7 @@ public: /// Complete at the beginning of member of a nominal decl member -- no tokens /// provided by user. virtual void completeNominalMemberBeginning( - SmallVectorImpl &Keywords) {}; + SmallVectorImpl &Keywords, SourceLoc introducerLoc) {}; /// Complete at the beginning of accessor in a accessor block. virtual void completeAccessorBeginning() {}; diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 53351aee00e..d9b27447bc6 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -1250,6 +1250,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks { Optional ParentStmtKind; SmallVector ParsedKeywords; + SourceLoc introducerLoc; std::vector> SubModuleNameVisibilityPairs; @@ -1348,7 +1349,7 @@ public: void completeDeclAttrParam(DeclAttrKind DK, int Index) override; void completeInPrecedenceGroup(SyntaxKind SK) override; void completeNominalMemberBeginning( - SmallVectorImpl &Keywords) override; + SmallVectorImpl &Keywords, SourceLoc introducerLoc) override; void completeAccessorBeginning() override; void completePoundAvailablePlatform() override; @@ -3856,9 +3857,11 @@ public: class CompletionOverrideLookup : public swift::VisibleDeclConsumer { CodeCompletionResultSink &Sink; + ASTContext &Ctx; const DeclContext *CurrDeclContext; LazyResolver *TypeResolver; SmallVectorImpl &ParsedKeywords; + SourceLoc introducerLoc; bool hasFuncIntroducer = false; bool hasVarIntroducer = false; @@ -3872,9 +3875,10 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer { public: CompletionOverrideLookup(CodeCompletionResultSink &Sink, ASTContext &Ctx, const DeclContext *CurrDeclContext, - SmallVectorImpl &ParsedKeywords) - : Sink(Sink), - CurrDeclContext(CurrDeclContext), ParsedKeywords(ParsedKeywords) { + SmallVectorImpl &ParsedKeywords, + SourceLoc introducerLoc) + : Sink(Sink), Ctx(Ctx), CurrDeclContext(CurrDeclContext), + ParsedKeywords(ParsedKeywords), introducerLoc(introducerLoc) { (void)createTypeChecker(Ctx); TypeResolver = Ctx.getLazyResolver(); @@ -3953,10 +3957,17 @@ public: if (!hasDeclIntroducer && !hasAccessModifier) addAccessControl(VD, Builder); - // FIXME: if we're missing 'override', but have the decl introducer we - // should delete it and re-add both in the correct order. - if (!hasDeclIntroducer && !hasStaticOrClass && missingOverride(Reason)) - Builder.addOverrideKeyword(); + if (missingOverride(Reason)) { + if (!hasDeclIntroducer) + Builder.addOverrideKeyword(); + else { + auto dist = Ctx.SourceMgr.getByteDistance( + introducerLoc, Ctx.SourceMgr.getCodeCompletionLoc()); + Builder.setNumBytesToErase(dist); + Builder.addOverrideKeyword(); + Builder.addDeclIntroducer(DeclStr.str().substr(0, NameOffset)); + } + } if (!hasDeclIntroducer) Builder.addDeclIntroducer(DeclStr.str().substr(0, NameOffset)); @@ -4487,8 +4498,9 @@ void CodeCompletionCallbacksImpl::completeGenericParams(TypeLoc TL) { } void CodeCompletionCallbacksImpl::completeNominalMemberBeginning( - SmallVectorImpl &Keywords) { + SmallVectorImpl &Keywords, SourceLoc introducerLoc) { assert(!InEnumElementRawValue); + this->introducerLoc = introducerLoc; ParsedKeywords.clear(); ParsedKeywords.append(Keywords.begin(), Keywords.end()); Kind = CompletionKind::NominalMemberBeginning; @@ -5043,7 +5055,7 @@ void CodeCompletionCallbacksImpl::doneParsing() { case CompletionKind::NominalMemberBeginning: { CompletionOverrideLookup OverrideLookup(CompletionContext.getResultSink(), P.Context, CurDeclContext, - ParsedKeywords); + ParsedKeywords, introducerLoc); OverrideLookup.getOverrideCompletions(SourceLoc()); break; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index f2cf7a0ef67..c632438ca28 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2932,6 +2932,7 @@ Parser::parseDecl(ParseDeclOptions Flags, // specified so that we do not duplicate them in code completion // strings. SmallVector Keywords; + SourceLoc introducerLoc; switch (OrigTok.getKind()) { case tok::kw_func: case tok::kw_subscript: @@ -2939,6 +2940,7 @@ Parser::parseDecl(ParseDeclOptions Flags, case tok::kw_let: case tok::kw_typealias: Keywords.push_back(OrigTok.getText()); + introducerLoc = OrigTok.getLoc(); break; default: // Other tokens are already accounted for. @@ -2952,7 +2954,8 @@ Parser::parseDecl(ParseDeclOptions Flags, for (auto attr : Attributes) { Keywords.push_back(attr->getAttrName()); } - CodeCompletion->completeNominalMemberBeginning(Keywords); + CodeCompletion->completeNominalMemberBeginning(Keywords, + introducerLoc); } DeclResult = makeParserCodeCompletionStatus(); diff --git a/test/IDE/complete_declname.swift b/test/IDE/complete_declname.swift index 18b5bf82149..f16981d9879 100644 --- a/test/IDE/complete_declname.swift +++ b/test/IDE/complete_declname.swift @@ -43,7 +43,7 @@ class MyCls { class MySub : MyCls { func #^METHODNAME_OVERRIDE^# // METHODNAME_OVERRIDE: Begin completions, 1 items -// METHODNAME_OVERRIDE-NEXT: Decl[InstanceMethod]/Super: foo() {|}; name=foo() +// METHODNAME_OVERRIDE-NEXT: Decl[InstanceMethod]/Super/Erase[5]: override func foo() {|}; name=foo() // METHODNAME_OVERRIDE-NEXT: End completions } diff --git a/test/IDE/complete_override.swift b/test/IDE/complete_override.swift index abf17c2320f..a6410fb3f95 100644 --- a/test/IDE/complete_override.swift +++ b/test/IDE/complete_override.swift @@ -127,19 +127,19 @@ // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER9 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER9 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER10 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER6 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER11 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER9 -// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER12 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER9 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER12 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER12 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER13 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER13 -// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER14 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER9 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER14 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER12 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER15 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER15 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER16 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER15 -// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER17 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER15 -// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER18 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER15 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER17 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER17 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER18 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER17 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER19 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER13 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER20 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER13 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER21 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER21 -// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER22 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER21 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER22 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER22 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER23 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER23 -// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER24 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER23 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER24 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER24 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=PROTOINIT_NORM -code-completion-keywords=false | %FileCheck %s -check-prefix=PROTOINIT_NORM // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=PROTOINIT_FINAL -code-completion-keywords=false | %FileCheck %s -check-prefix=PROTOINIT_FINAL @@ -642,7 +642,6 @@ class Override11 : OverrideBase, OverrideP { } class Override12 : OverrideBase, OverrideP { override var #^MODIFIER12^# - // Same as MODIFIER9. } class Override13 : OverrideBase, OverrideP { // No completions. @@ -652,23 +651,22 @@ class Override14 : OverrideBase, OverrideP { // Note: This *does* emit variables. It will result invalid decl, but a // diagnostic will tell the user what to do. override let #^MODIFIER14^# - // Same as MODIFIER9. + // Same as MODIFIER12. } class Override15 : OverrideBase, OverrideP { required static var #^MODIFIER15^# } class Override16 : OverrideBase, OverrideP { - override class var #^MODIFIER16^# + class var #^MODIFIER16^# // Same as MODIFIER15 } class Override17 : OverrideBase, OverrideP { - // Note: This *does* emit variables. See MODIFIER14 - override static let #^MODIFIER17^# - // Same as MODIFIER15 + override class var #^MODIFIER17^# } class Override18 : OverrideBase, OverrideP { - class var #^MODIFIER18^# - // Same as MODIFIER15 + // Note: This *does* emit variables. See MODIFIER14 + override static let #^MODIFIER18^# + // Same as MODIFIER17 } class Override19 : OverrideBase, OverrideP { // No completions. @@ -683,14 +681,12 @@ class Override21 : OverrideBase, OverrideP { } class Override22 : OverrideBase, OverrideP { class func #^MODIFIER22^# - // Same as MODIFIER21 } class Override23 : OverrideBase, OverrideP { static #^MODIFIER23^# } class Override24 : OverrideBase, OverrideP { override static #^MODIFIER24^# - // Same as MODIFIER23 } // MODIFIER1: Begin completions, 9 items @@ -740,29 +736,46 @@ class Override24 : OverrideBase, OverrideP { // MODIFIER7: End completions // MODIFIER8: Begin completions, 2 items -// MODIFIER8-DAG: Decl[InstanceMethod]/Super: defaultMethod() {|}; name=defaultMethod() -// MODIFIER8-DAG: Decl[InstanceMethod]/Super: openMethod() {|}; name=openMethod() +// MODIFIER8-DAG: Decl[InstanceMethod]/Super/Erase[5]: override func defaultMethod() {|}; name=defaultMethod() +// MODIFIER8-DAG: Decl[InstanceMethod]/Super/Erase[5]: override func openMethod() {|}; name=openMethod() // MODIFIER8: End completions // MODIFIER9: Begin completions, 1 items -// MODIFIER9-DAG: Decl[InstanceVar]/Super: varDecl: Int; name=varDecl: Int +// MODIFIER9-DAG: Decl[InstanceVar]/Super/Erase[4]: override var varDecl: Int; name=varDecl: Int // MODIFIER9: End completions +// MODIFIER12: Begin completions, 1 items +// MODIFIER12-DAG: Decl[InstanceVar]/Super: varDecl: Int; name=varDecl: Int +// MODIFIER12: End completions + // MODIFIER13-NOT: Begin completions // MODIFIER15: Begin completions, 1 items -// MODIFIER15-DAG: Decl[StaticVar]/Super: classGetOnlyVar: Int; name=classGetOnlyVar: Int +// MODIFIER15-DAG: Decl[StaticVar]/Super/Erase[4]: override var classGetOnlyVar: Int; name=classGetOnlyVar: Int // MODIFIER15: End completions +// MODIFIER17: Begin completions, 1 items +// MODIFIER17-DAG: Decl[StaticVar]/Super: classGetOnlyVar: Int; name=classGetOnlyVar: Int +// MODIFIER17: End completions + // MODIFIER21: Begin completions, 1 items -// MODIFIER21: Decl[StaticMethod]/Super: classMethod() {|}; name=classMethod() +// MODIFIER21: Decl[StaticMethod]/Super: classMethod() {|}; name=classMethod() // MODIFIER21: End completions +// MODIFIER22: Begin completions, 1 items +// MODIFIER22: Decl[StaticMethod]/Super/Erase[5]: override func classMethod() {|}; name=classMethod() +// MODIFIER22: End completions + // MODIFIER23: Begin completions, 2 items -// MODIFIER23-DAG: Decl[StaticMethod]/Super: func classMethod() {|}; name=classMethod() -// MODIFIER23-DAG: Decl[StaticVar]/Super: var classGetOnlyVar: Int; name=classGetOnlyVar: Int +// MODIFIER23-DAG: Decl[StaticMethod]/Super: override func classMethod() {|}; name=classMethod() +// MODIFIER23-DAG: Decl[StaticVar]/Super: override var classGetOnlyVar: Int; name=classGetOnlyVar: Int // MODIFIER23: End completions +// MODIFIER24: Begin completions, 2 items +// MODIFIER24-DAG: Decl[StaticMethod]/Super: func classMethod() {|}; name=classMethod() +// MODIFIER24-DAG: Decl[StaticVar]/Super: var classGetOnlyVar: Int; name=classGetOnlyVar: Int +// MODIFIER24: End completions + protocol RequiredP { init(p: Int) } diff --git a/test/IDE/complete_override_objc.swift b/test/IDE/complete_override_objc.swift index 5966a96021a..783a76b330d 100644 --- a/test/IDE/complete_override_objc.swift +++ b/test/IDE/complete_override_objc.swift @@ -33,7 +33,7 @@ class Sub : FooClassDerived { var #^PROPERTY^# } // PROPERTY: Begin completions -// PROPERTY-DAG: Decl[InstanceVar]/Super: fooProperty1: Int32 -// PROPERTY-DAG: Decl[InstanceVar]/Super: fooProperty2: Int32 -// PROPERTY-DAG: Decl[InstanceVar]/Super: fooProperty3: Int32 +// PROPERTY-DAG: Decl[InstanceVar]/Super/Erase[4]: override var fooProperty1: Int32; +// PROPERTY-DAG: Decl[InstanceVar]/Super/Erase[4]: override var fooProperty2: Int32; +// PROPERTY-DAG: Decl[InstanceVar]/Super/Erase[4]: override var fooProperty3: Int32; // PROPERTY: End completions From ecfce5611013b89232de0b883da3611ae90aa215 Mon Sep 17 00:00:00 2001 From: fischertony Date: Thu, 14 Feb 2019 13:12:02 +0300 Subject: [PATCH 3/4] Don't exclude @autoclosure from the attribute list when printing override completions --- lib/IDE/CodeCompletion.cpp | 1 + test/IDE/complete_override.swift | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index d9b27447bc6..12645de2166 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -3947,6 +3947,7 @@ public: Options.setBaseType(transformType); Options.PrintImplicitAttrs = false; Options.ExclusiveAttrList.push_back(TAK_escaping); + Options.ExclusiveAttrList.push_back(TAK_autoclosure); Options.PrintOverrideKeyword = false; Options.PrintPropertyAccessors = false; Options.PrintStaticKeyword = !hasStaticOrClass; diff --git a/test/IDE/complete_override.swift b/test/IDE/complete_override.swift index a6410fb3f95..6cdb62b8ab9 100644 --- a/test/IDE/complete_override.swift +++ b/test/IDE/complete_override.swift @@ -566,12 +566,13 @@ class Deprecated2 : Deprecated1 { class EscapingBase { func method(_ x: @escaping (@escaping ()->()) -> (()->())) -> (@escaping (@escaping ()->() )->()) { } + func autoclosure(arg: @autoclosure () -> Bool) {} } class Escaping : EscapingBase { override func #^ESCAPING_1^# } // ESCAPING_1: Decl[InstanceMethod]/Super: method(_ x: @escaping (@escaping () -> ()) -> (() -> ())) -> ((@escaping () -> ()) -> ()) {|}; - +// ESCAPING_1: Decl[InstanceMethod]/Super: autoclosure(arg: @autoclosure () -> Bool) {|}; class OverrideBase { static let staticLet = 0 static var staticVar = 0 From ae415b2a4b3c54fa4d9eede16ef6a4979238f538 Mon Sep 17 00:00:00 2001 From: fischertony Date: Sat, 16 Feb 2019 13:59:24 +0300 Subject: [PATCH 4/4] When followed by an 'override' or CC token inside a class, treat 'class' as a modifier rather than an introducer. --- lib/IDE/CodeCompletion.cpp | 5 +++-- lib/Parse/ParseDecl.cpp | 11 ++++++++++- test/IDE/complete_override.swift | 10 ++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 12645de2166..de4e8c274c4 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -4680,10 +4680,11 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink, break; case CompletionKind::NominalMemberBeginning: { - bool HasDeclIntroducer = llvm::find_if(ParsedKeywords, [](const StringRef kw) { + bool HasDeclIntroducer = llvm::find_if(ParsedKeywords, + [this](const StringRef kw) { return llvm::StringSwitch(kw) .Case("associatedtype", true) - .Case("class", true) + .Case("class", !CurDeclContext || !isa(CurDeclContext)) .Case("deinit", true) .Case("enum", true) .Case("extension", true) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index c632438ca28..350ec1cb1a3 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2281,9 +2281,18 @@ bool Parser::parseDeclModifierList(DeclAttributes &Attributes, { BacktrackingScope Scope(*this); consumeToken(tok::kw_class); - if (!isStartOfDecl()) + // When followed by an 'override' or CC token inside a class, + // treat 'class' as a modifier; in the case of a following CC + // token, we cannot be sure there is no intention to override + // or witness something static. + if (isStartOfDecl() || (isa(CurDeclContext) && + (Tok.is(tok::code_complete) || + Tok.getRawText().equals("override")))) { + /* We're OK */ + } else { // This 'class' is a real ClassDecl introducer. break; + } } if (StaticLoc.isValid()) { diagnose(Tok, diag::decl_already_static, diff --git a/test/IDE/complete_override.swift b/test/IDE/complete_override.swift index 6cdb62b8ab9..6206d6b22a8 100644 --- a/test/IDE/complete_override.swift +++ b/test/IDE/complete_override.swift @@ -140,6 +140,8 @@ // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER22 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER22 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER23 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER23 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER24 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER24 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER25 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER23 +// RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=MODIFIER26 -code-completion-keywords=false | %FileCheck %s -check-prefix=MODIFIER24 // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=PROTOINIT_NORM -code-completion-keywords=false | %FileCheck %s -check-prefix=PROTOINIT_NORM // RUN: %target-swift-ide-test -enable-objc-interop -code-completion -source-filename %s -code-completion-token=PROTOINIT_FINAL -code-completion-keywords=false | %FileCheck %s -check-prefix=PROTOINIT_FINAL @@ -689,6 +691,14 @@ class Override23 : OverrideBase, OverrideP { class Override24 : OverrideBase, OverrideP { override static #^MODIFIER24^# } +class Override25 : OverrideBase, OverrideP { + class #^MODIFIER25^# + // Same as MODIFIER23 +} +class Override26 : OverrideBase, OverrideP { + class override #^MODIFIER26^# + // Same as MODIFIER24 +} // MODIFIER1: Begin completions, 9 items // MODIFIER1-DAG: Decl[Constructor]/Super: required init(p: Int) {|}; name=required init(p: Int)