@@ -25,16 +25,20 @@ import com.intellij.patterns.StandardPatterns
25
25
import com.intellij.util.ProcessingContext
26
26
import org.jetbrains.kotlin.descriptors.CallableDescriptor
27
27
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
28
+ import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
28
29
import org.jetbrains.kotlin.idea.core.ExpectedInfo
29
30
import org.jetbrains.kotlin.idea.kdoc.getKDocLinkResolutionScope
30
31
import org.jetbrains.kotlin.idea.kdoc.getParamDescriptors
32
+ import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
31
33
import org.jetbrains.kotlin.idea.util.CallType
32
34
import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable
33
35
import org.jetbrains.kotlin.kdoc.lexer.KDocTokens
34
36
import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
35
37
import org.jetbrains.kotlin.kdoc.psi.api.KDoc
36
38
import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink
37
39
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
40
+ import org.jetbrains.kotlin.name.FqName
41
+ import org.jetbrains.kotlin.name.Name
38
42
import org.jetbrains.kotlin.psi.KtClassOrObject
39
43
import org.jetbrains.kotlin.psi.KtDeclaration
40
44
import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -43,26 +47,29 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
43
47
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
44
48
import org.jetbrains.kotlin.resolve.BindingContext
45
49
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
50
+ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
51
+ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
46
52
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
53
+ import org.jetbrains.kotlin.resolve.scopes.LexicalScope
47
54
import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
48
55
import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy
49
56
50
- class KDocCompletionContributor (): CompletionContributor() {
57
+ class KDocCompletionContributor () : CompletionContributor() {
51
58
init {
52
59
extend(CompletionType .BASIC , psiElement().inside(KDocName ::class .java),
53
60
KDocNameCompletionProvider )
54
61
55
62
extend(CompletionType .BASIC ,
56
63
psiElement().afterLeaf(
57
- StandardPatterns .or (psiElement(KDocTokens .LEADING_ASTERISK ), psiElement(KDocTokens .START ))),
64
+ StandardPatterns .or (psiElement(KDocTokens .LEADING_ASTERISK ), psiElement(KDocTokens .START ))),
58
65
KDocTagCompletionProvider )
59
66
60
67
extend(CompletionType .BASIC ,
61
68
psiElement(KDocTokens .TAG_NAME ), KDocTagCompletionProvider )
62
69
}
63
70
}
64
71
65
- object KDocNameCompletionProvider: CompletionProvider<CompletionParameters>() {
72
+ object KDocNameCompletionProvider : CompletionProvider<CompletionParameters>() {
66
73
override fun addCompletions (parameters : CompletionParameters , context : ProcessingContext , result : CompletionResultSet ) {
67
74
KDocNameCompletionSession (parameters, ToFromOriginalFileMapper .create(parameters), result).complete()
68
75
}
@@ -72,7 +79,7 @@ class KDocNameCompletionSession(
72
79
parameters : CompletionParameters ,
73
80
toFromOriginalFileMapper : ToFromOriginalFileMapper ,
74
81
resultSet : CompletionResultSet
75
- ): CompletionSession(CompletionSessionConfiguration (parameters), parameters, toFromOriginalFileMapper, resultSet) {
82
+ ) : CompletionSession(CompletionSessionConfiguration (parameters), parameters, toFromOriginalFileMapper, resultSet) {
76
83
override val descriptorKindFilter: DescriptorKindFilter ? get() = null
77
84
override val expectedInfos: Collection <ExpectedInfo > get() = emptyList()
78
85
@@ -83,11 +90,13 @@ class KDocNameCompletionSession(
83
90
val declarationDescriptor = bindingContext[BindingContext .DECLARATION_TO_DESCRIPTOR , declaration] ? : return
84
91
if (kdocLink.getTagIfSubject()?.knownTag == KDocKnownTag .PARAM ) {
85
92
addParamCompletions(position, declarationDescriptor)
86
- } else {
87
- addLinkCompletions(declarationDescriptor)
93
+ }
94
+ else {
95
+ addLinkCompletions(declarationDescriptor, kdocLink)
88
96
}
89
97
}
90
98
99
+
91
100
private fun addParamCompletions (position : KDocName ,
92
101
declarationDescriptor : DeclarationDescriptor ) {
93
102
val section = position.getContainingSection()
@@ -100,8 +109,13 @@ class KDocNameCompletionSession(
100
109
}
101
110
}
102
111
103
- private fun addLinkCompletions (declarationDescriptor : DeclarationDescriptor ) {
104
- val scope = getKDocLinkResolutionScope(resolutionFacade, declarationDescriptor)
112
+ fun collectPackageViewDescriptors (qualifiedLink : List <String >, nameFilter : (Name ) -> Boolean ): Sequence <PackageViewDescriptor > {
113
+ val fqName = if (qualifiedLink.isEmpty()) FqName .ROOT else FqName .fromSegments(qualifiedLink)
114
+ return moduleDescriptor.getSubPackagesOf(fqName, nameFilter).asSequence()
115
+ .map { moduleDescriptor.getPackage(it) }
116
+ }
117
+
118
+ fun collectDescriptorsFromScope (scope : LexicalScope , nameFilter : (Name ) -> Boolean , collectFormParentScopes : Boolean ): Sequence <DeclarationDescriptor > {
105
119
val implicitReceivers = scope.getImplicitReceiversHierarchy().map { it.value }
106
120
107
121
fun isApplicable (descriptor : DeclarationDescriptor ): Boolean {
@@ -110,15 +124,49 @@ class KDocNameCompletionSession(
110
124
if (extensionReceiver != null ) {
111
125
val substituted = descriptor.substituteExtensionIfCallable(implicitReceivers, bindingContext, DataFlowInfo .EMPTY ,
112
126
CallType .DEFAULT , moduleDescriptor)
113
- return ! substituted.isEmpty ()
127
+ return substituted.isNotEmpty ()
114
128
}
115
129
}
116
130
return true
117
131
}
118
132
119
- scope.collectDescriptorsFiltered(nameFilter = descriptorNameFilter.toNameFilter()).filter(::isApplicable).forEach {
133
+ @Suppress(" IfThenToElvis" )
134
+ return (
135
+ if (collectFormParentScopes)
136
+ scope.collectDescriptorsFiltered(nameFilter = nameFilter).asSequence()
137
+ else if (scope is LexicalScope .Empty )
138
+ scope.parent.getContributedDescriptors(nameFilter = nameFilter).asSequence()
139
+ else
140
+ (scope.getContributedDescriptors(nameFilter = nameFilter).asSequence()
141
+ + scope.parent.collectDescriptorsFiltered(nameFilter = nameFilter).asSequence()
142
+ .filter { it.isExtension || it.isExtensionProperty })
143
+ ).filter(::isApplicable)
144
+ }
145
+
146
+
147
+ fun collectDescriptorsForLinkCompletion (declarationDescriptor : DeclarationDescriptor , kDocLink : KDocLink ): Sequence <DeclarationDescriptor > {
148
+ val qualifiedLink = kDocLink.getLinkText().split(' .' ).dropLast(1 )
149
+ val nameFilter = descriptorNameFilter.toNameFilter()
150
+ if (qualifiedLink.isNotEmpty()) {
151
+ val parentDescriptors = resolveKDocLink(bindingContext, resolutionFacade, declarationDescriptor, null , qualifiedLink)
152
+ val childDescriptorsOfPartialLink = parentDescriptors.asSequence().flatMap {
153
+ val scope = getKDocLinkResolutionScope(resolutionFacade, it)
154
+ collectDescriptorsFromScope(scope, nameFilter, false )
155
+ }
156
+
157
+ return (collectPackageViewDescriptors(qualifiedLink, nameFilter) + childDescriptorsOfPartialLink)
158
+ }
159
+ else {
160
+ val scope = getKDocLinkResolutionScope(resolutionFacade, declarationDescriptor)
161
+ return (collectDescriptorsFromScope(scope, nameFilter, true )
162
+ + collectPackageViewDescriptors(qualifiedLink, nameFilter))
163
+ }
164
+ }
165
+
166
+ private fun addLinkCompletions (declarationDescriptor : DeclarationDescriptor , kDocLink : KDocLink ) {
167
+ collectDescriptorsForLinkCompletion(declarationDescriptor, kDocLink).forEach {
120
168
val element = basicLookupElementFactory.createLookupElement(it, parametersAndTypeGrayed = true )
121
- collector.addElement(object : LookupElementDecorator <LookupElement >(element) {
169
+ collector.addElement(object : LookupElementDecorator <LookupElement >(element) {
122
170
override fun handleInsert (context : InsertionContext ? ) {
123
171
// insert only plain name here, no qualifier/parentheses/etc.
124
172
}
@@ -127,7 +175,7 @@ class KDocNameCompletionSession(
127
175
}
128
176
}
129
177
130
- object KDocTagCompletionProvider: CompletionProvider<CompletionParameters>() {
178
+ object KDocTagCompletionProvider : CompletionProvider<CompletionParameters>() {
131
179
override fun addCompletions (parameters : CompletionParameters , context : ProcessingContext , result : CompletionResultSet ) {
132
180
// findIdentifierPrefix() requires identifier part characters to be a superset of identifier start characters
133
181
val prefix = CompletionUtil .findIdentifierPrefix(
@@ -148,7 +196,7 @@ object KDocTagCompletionProvider: CompletionProvider<CompletionParameters>() {
148
196
}
149
197
}
150
198
151
- private fun KDocKnownTag.isApplicable (declaration : KtDeclaration ) = when (this ) {
199
+ private fun KDocKnownTag.isApplicable (declaration : KtDeclaration ) = when (this ) {
152
200
KDocKnownTag .CONSTRUCTOR , KDocKnownTag .PROPERTY -> declaration is KtClassOrObject
153
201
KDocKnownTag .RETURN -> declaration is KtNamedFunction
154
202
KDocKnownTag .RECEIVER -> declaration is KtNamedFunction && declaration.receiverTypeReference != null
0 commit comments