172: [Spring] Revert "Spring: removing needless EP-s because they ported to UAST in platform"
This reverts commit 9355f79c6b06fdcd365f23b40e93ea841b372b27.
This commit is contained in:
@@ -0,0 +1,77 @@
|
|||||||
|
<idea-plugin>
|
||||||
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
|
<psi.referenceContributor
|
||||||
|
language="kotlin"
|
||||||
|
implementation="org.jetbrains.kotlin.idea.spring.references.KotlinSpringReferenceContributor"
|
||||||
|
order="before kotlinFilePathReferenceContributor" />
|
||||||
|
<psi.referenceContributor
|
||||||
|
language="kotlin"
|
||||||
|
implementation="org.jetbrains.kotlin.idea.jam.KotlinJamReferenceContributor"
|
||||||
|
order="before kotlinFilePathReferenceContributor" />
|
||||||
|
|
||||||
|
<multiHostInjector implementation="org.jetbrains.kotlin.idea.spring.el.KotlinSpringELInjector"/>
|
||||||
|
|
||||||
|
<codeInsight.lineMarkerProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.spring.lineMarking.KotlinSpringClassAnnotator"/>
|
||||||
|
<codeInsight.lineMarkerProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.spring.lineMarking.KotlinSpringModelDependenciesLineMarkerProvider"/>
|
||||||
|
|
||||||
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.spring.inspections.KotlinFinalClassOrFunSpringInspection"
|
||||||
|
displayName="Final Kotlin class or function with Spring annotation"
|
||||||
|
groupBundle="resources.messages.SpringBundle"
|
||||||
|
groupKey="inspection.group.code"
|
||||||
|
groupPath="Spring,Spring Core"
|
||||||
|
enabledByDefault="false"
|
||||||
|
level="WARNING"/>
|
||||||
|
<localInspection language="kotlin"
|
||||||
|
displayName="Spring Facet Code Configuration (Kotlin)"
|
||||||
|
groupBundle="resources.messages.SpringBundle"
|
||||||
|
groupKey="inspection.group.setup"
|
||||||
|
groupPath="Spring,Spring Core"
|
||||||
|
enabledByDefault="true"
|
||||||
|
level="WARNING"
|
||||||
|
implementationClass="org.jetbrains.kotlin.idea.spring.inspections.KotlinSpringFacetCodeInspection"/>
|
||||||
|
<localInspection language="kotlin"
|
||||||
|
displayName="Autowired members defined in invalid Spring bean (Kotlin)"
|
||||||
|
groupBundle="resources.messages.SpringBundle"
|
||||||
|
groupKey="inspection.group.code"
|
||||||
|
groupPath="Spring,Spring Core"
|
||||||
|
enabledByDefault="true"
|
||||||
|
level="WARNING"
|
||||||
|
implementationClass="org.jetbrains.kotlin.idea.spring.inspections.SpringKotlinAutowiredMembersInspection"/>
|
||||||
|
<localInspection language="kotlin"
|
||||||
|
displayName="Autowiring for Bean Class (Kotlin)"
|
||||||
|
groupBundle="resources.messages.SpringBundle"
|
||||||
|
groupKey="inspection.group.code"
|
||||||
|
groupPath="Spring,Spring Core"
|
||||||
|
enabledByDefault="true"
|
||||||
|
level="ERROR"
|
||||||
|
implementationClass="org.jetbrains.kotlin.idea.spring.inspections.SpringKotlinAutowiringInspection"/>
|
||||||
|
<localInspection language="kotlin"
|
||||||
|
displayName="@ComponentScan setup (Kotlin)"
|
||||||
|
groupBundle="resources.messages.SpringBundle"
|
||||||
|
groupKey="inspection.group.code"
|
||||||
|
groupPath="Spring,Spring Core"
|
||||||
|
enabledByDefault="true"
|
||||||
|
level="ERROR"
|
||||||
|
implementationClass="org.jetbrains.kotlin.idea.spring.inspections.KotlinSpringComponentScanInspection"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<actions>
|
||||||
|
<action id="Kotlin.Spring.Beans.Generate.Setter.Dependency.Action"
|
||||||
|
class="org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanXmlDependencyAction$Setter">
|
||||||
|
<add-to-group anchor="last" group-id="GenerateGroup"/>
|
||||||
|
</action>
|
||||||
|
<action id="Kotlin.Spring.Beans.Generate.Constructor.Dependency.Action"
|
||||||
|
class="org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanXmlDependencyAction$Constructor">
|
||||||
|
<add-to-group anchor="last" group-id="GenerateGroup"/>
|
||||||
|
</action>
|
||||||
|
<action id="Kotlin.Spring.Beans.Generate.Lateinit.Property.Dependency.Action"
|
||||||
|
class="org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinSpringBeanXmlDependencyAction$LateinitProperty">
|
||||||
|
<add-to-group anchor="last" group-id="GenerateGroup"/>
|
||||||
|
</action>
|
||||||
|
|
||||||
|
<action id="Kotlin.Spring.Beans.Generate.Autowired.Dependency.Action"
|
||||||
|
class="org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinAutowiredDependencyAction">
|
||||||
|
<add-to-group anchor="last" group-id="GenerateGroup"/>
|
||||||
|
</action>
|
||||||
|
</actions>
|
||||||
|
</idea-plugin>
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package org.jetbrains.kotlin.idea.jam
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.completion.CompletionUtil
|
||||||
|
import com.intellij.jam.JamService
|
||||||
|
import com.intellij.jam.JamStringAttributeElement
|
||||||
|
import com.intellij.jam.reflect.JamStringAttributeMeta
|
||||||
|
import com.intellij.psi.PsiElementRef
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
import com.intellij.psi.PsiReferenceRegistrar
|
||||||
|
import com.intellij.util.SmartList
|
||||||
|
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
||||||
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
|
import org.jetbrains.kotlin.idea.references.AbstractKotlinReferenceContributor
|
||||||
|
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||||
|
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isPlain
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
|
|
||||||
|
// Based on the JamReferenceContributor
|
||||||
|
class KotlinJamReferenceContributor : AbstractKotlinReferenceContributor() {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||||
|
registrar.registerMultiProvider<KtStringTemplateExpression> { expression ->
|
||||||
|
if (!expression.isPlain()) return@registerMultiProvider PsiReference.EMPTY_ARRAY
|
||||||
|
val argument = expression
|
||||||
|
.parents
|
||||||
|
.filterIsInstance<KtValueArgument>()
|
||||||
|
.firstOrNull() { it.parent?.parent is KtAnnotationEntry } ?: return@registerMultiProvider PsiReference.EMPTY_ARRAY
|
||||||
|
val annotationEntry = argument.parent.parent as KtAnnotationEntry
|
||||||
|
val lightAnnotation = (CompletionUtil.getOriginalOrSelf(annotationEntry)).toLightAnnotation()
|
||||||
|
?: return@registerMultiProvider PsiReference.EMPTY_ARRAY
|
||||||
|
|
||||||
|
val service = JamService.getJamService(expression.project)
|
||||||
|
val annotationMeta = service.getMeta(lightAnnotation)
|
||||||
|
?: return@registerMultiProvider PsiReference.EMPTY_ARRAY
|
||||||
|
val attributeName = argument.getArgumentName()?.asName?.asString()
|
||||||
|
val attribute = annotationMeta.findAttribute(attributeName) as? JamStringAttributeMeta<Any, Any>
|
||||||
|
?: return@registerMultiProvider PsiReference.EMPTY_ARRAY
|
||||||
|
val jam = attribute.getJam(PsiElementRef.real(lightAnnotation))
|
||||||
|
val converter = attribute.converter
|
||||||
|
when (jam) {
|
||||||
|
is JamStringAttributeElement<*> -> converter.createReferences(jam as JamStringAttributeElement<Any>)
|
||||||
|
is List<*> -> {
|
||||||
|
val list = SmartList<PsiReference>()
|
||||||
|
for (item in jam) {
|
||||||
|
val jamElement = item as? JamStringAttributeElement<Any> ?: continue
|
||||||
|
if (jamElement.psiElement?.unwrapped != expression) continue
|
||||||
|
list += converter.createReferences(jamElement)
|
||||||
|
}
|
||||||
|
list.toTypedArray()
|
||||||
|
}
|
||||||
|
else -> PsiReference.EMPTY_ARRAY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+157
@@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.spring.references
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
import com.intellij.psi.PsiReferenceBase
|
||||||
|
import com.intellij.psi.PsiReferenceRegistrar
|
||||||
|
import com.intellij.spring.constants.SpringAnnotationsConstants
|
||||||
|
import com.intellij.spring.constants.SpringConstants
|
||||||
|
import com.intellij.spring.model.utils.resources.SpringResourcesBuilder
|
||||||
|
import com.intellij.spring.model.utils.resources.SpringResourcesUtil
|
||||||
|
import com.intellij.spring.references.SpringBeanNamesReferenceProvider
|
||||||
|
import com.intellij.spring.references.SpringBeanReference
|
||||||
|
import org.jetbrains.kotlin.asJava.toLightClass
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||||
|
import org.jetbrains.kotlin.idea.references.AbstractKotlinReferenceContributor
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getContentRange
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isPlain
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.plainContent
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeAsSequence
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
|
|
||||||
|
// TODO: Use Kotlin patterns
|
||||||
|
class KotlinSpringReferenceContributor : AbstractKotlinReferenceContributor() {
|
||||||
|
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||||
|
registrar.registerProvider<KtStringTemplateExpression> {
|
||||||
|
if (!it.isPlain()) return@registerProvider null
|
||||||
|
|
||||||
|
val callExpression = (it.parent as? KtValueArgument)?.getStrictParentOfType<KtCallExpression>() ?: return@registerProvider null
|
||||||
|
val context = callExpression.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val resolvedCall = callExpression.getResolvedCall(context) ?: return@registerProvider null
|
||||||
|
val callable = resolvedCall.resultingDescriptor as? CallableMemberDescriptor ?: return@registerProvider null
|
||||||
|
if (!callable.overriddenTreeAsSequence(true).any {
|
||||||
|
it.containingDeclaration.importableFqName?.asString() == SpringConstants.BEAN_FACTORY_CLASS
|
||||||
|
}) return@registerProvider null
|
||||||
|
if (callable.name.asString() !in SpringBeanNamesReferenceProvider.METHODS) return@registerProvider null
|
||||||
|
|
||||||
|
SpringBeanReference(it, it.getContentRange())
|
||||||
|
}
|
||||||
|
|
||||||
|
registrar.registerProvider<KtStringTemplateExpression>(PsiReferenceRegistrar.HIGHER_PRIORITY) {
|
||||||
|
if (!it.isPlain()) return@registerProvider null
|
||||||
|
|
||||||
|
val argument = it.parent as? KtValueArgument ?: return@registerProvider null
|
||||||
|
val argumentName = argument.getArgumentName() ?: return@registerProvider null
|
||||||
|
if (argumentName.asName.asString() != "name") return@registerProvider null
|
||||||
|
|
||||||
|
val entry = argument.getStrictParentOfType<KtAnnotationEntry>() ?: return@registerProvider null
|
||||||
|
val context = entry.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val resolvedCall = entry.getResolvedCall(context) ?: return@registerProvider null
|
||||||
|
val annotation = (resolvedCall.resultingDescriptor as? ConstructorDescriptor)?.containingDeclaration ?: return@registerProvider null
|
||||||
|
if (annotation.importableFqName?.asString() != SpringAnnotationsConstants.JAVAX_RESOURCE) return@registerProvider null
|
||||||
|
|
||||||
|
val contentRange = it.getContentRange()
|
||||||
|
var startOffset = contentRange.startOffset
|
||||||
|
val isFactoryBeanRef: Boolean
|
||||||
|
if (it.plainContent.startsWith("&")) {
|
||||||
|
startOffset++
|
||||||
|
isFactoryBeanRef = true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
isFactoryBeanRef = false
|
||||||
|
}
|
||||||
|
|
||||||
|
val callable = (it.getStrictParentOfType<KtAnnotationEntry>()?.parent as? KtModifierList)?.parent as? KtCallableDeclaration
|
||||||
|
val callableType = (callable?.resolveToDescriptor() as? CallableDescriptor)?.returnType
|
||||||
|
val requiredSuperClass = callableType?.constructor?.declarationDescriptor?.source?.getPsi() as? KtClass
|
||||||
|
|
||||||
|
SpringBeanReference(it, TextRange(startOffset, contentRange.endOffset), requiredSuperClass?.toLightClass(), isFactoryBeanRef)
|
||||||
|
}
|
||||||
|
|
||||||
|
registrar.registerProvider<KtStringTemplateExpression>(PsiReferenceRegistrar.HIGHER_PRIORITY) {
|
||||||
|
if (!it.isPlain()) return@registerProvider null
|
||||||
|
|
||||||
|
val argument = it.parent as? KtValueArgument ?: return@registerProvider null
|
||||||
|
val argumentName = argument.getArgumentName()
|
||||||
|
if (argumentName != null && argumentName.asName.asString() != "value") return@registerProvider null
|
||||||
|
|
||||||
|
val entry = argument.getStrictParentOfType<KtAnnotationEntry>() ?: return@registerProvider null
|
||||||
|
val context = entry.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val resolvedCall = entry.getResolvedCall(context) ?: return@registerProvider null
|
||||||
|
val annotation = (resolvedCall.resultingDescriptor as? ConstructorDescriptor)?.containingDeclaration ?: return@registerProvider null
|
||||||
|
if (annotation.importableFqName?.asString() != SpringAnnotationsConstants.SCOPE) return@registerProvider null
|
||||||
|
|
||||||
|
KtSpringBeanScopeReference(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
registrar.registerMultiProvider<KtStringTemplateExpression> {
|
||||||
|
if (!it.isPlain()) return@registerMultiProvider PsiReference.EMPTY_ARRAY
|
||||||
|
|
||||||
|
val callExpression = (it.parent as? KtValueArgument)?.getStrictParentOfType<KtCallExpression>()
|
||||||
|
?: return@registerMultiProvider PsiReference.EMPTY_ARRAY
|
||||||
|
val context = callExpression.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val resolvedCall = callExpression.getResolvedCall(context) ?: return@registerMultiProvider PsiReference.EMPTY_ARRAY
|
||||||
|
val classDescriptor = (resolvedCall.resultingDescriptor as? ConstructorDescriptor)?.containingDeclaration
|
||||||
|
?: return@registerMultiProvider PsiReference.EMPTY_ARRAY
|
||||||
|
val qName = classDescriptor.importableFqName?.asString()
|
||||||
|
if (qName != SpringConstants.CLASS_PATH_XML_APP_CONTEXT && qName != SpringConstants.CLASS_PATH_RESOURCE) {
|
||||||
|
return@registerMultiProvider PsiReference.EMPTY_ARRAY
|
||||||
|
}
|
||||||
|
|
||||||
|
val content = it.plainContent
|
||||||
|
val resourcesBuilder = SpringResourcesBuilder.create(it, content).fromRoot(content.startsWith("/")).soft(false)
|
||||||
|
SpringResourcesUtil.getInstance().getClassPathReferences(resourcesBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
registrar.registerProvider<KtStringTemplateExpression>(PsiReferenceRegistrar.HIGHER_PRIORITY) {
|
||||||
|
if (!it.isPlain()) return@registerProvider null
|
||||||
|
|
||||||
|
val argument = it.parent as? KtValueArgument ?: return@registerProvider null
|
||||||
|
val argumentName = argument.getArgumentName()
|
||||||
|
if (argumentName != null && argumentName.asName.asString() != "value") return@registerProvider null
|
||||||
|
|
||||||
|
val entry = argument.getStrictParentOfType<KtAnnotationEntry>() ?: return@registerProvider null
|
||||||
|
val bindingContext = entry.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val resolvedCall = entry.getResolvedCall(bindingContext) ?: return@registerProvider null
|
||||||
|
val annotation = (resolvedCall.resultingDescriptor as? ConstructorDescriptor)?.containingDeclaration
|
||||||
|
?: return@registerProvider null
|
||||||
|
if (annotation.importableFqName?.asString() != SpringAnnotationsConstants.QUALIFIER) return@registerProvider null
|
||||||
|
|
||||||
|
val annotated = entry.getStrictParentOfType<KtModifierListOwner>() ?: return@registerProvider null
|
||||||
|
if (annotated is KtClassOrObject) {
|
||||||
|
object : PsiReferenceBase<KtStringTemplateExpression>(it) {
|
||||||
|
override fun resolve() = entry
|
||||||
|
override fun getVariants(): Array<Any> = arrayOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
KtSpringQualifierReference(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.spring.references
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||||
|
import com.intellij.ide.TypePresentationService
|
||||||
|
import com.intellij.psi.ElementManipulators
|
||||||
|
import com.intellij.psi.PsiReferenceBase
|
||||||
|
import com.intellij.spring.model.scope.SpringBeanScope
|
||||||
|
import com.intellij.spring.model.scope.SpringBeanScopeManager
|
||||||
|
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.plainContent
|
||||||
|
|
||||||
|
class KtSpringBeanScopeReference(
|
||||||
|
element: KtStringTemplateExpression
|
||||||
|
) : PsiReferenceBase<KtStringTemplateExpression>(element, ElementManipulators.getManipulator(element).getRangeInElement(element)) {
|
||||||
|
private fun getScopes(): Sequence<SpringBeanScope> {
|
||||||
|
return SpringBeanScope.getDefaultScopes().asSequence() + SpringBeanScopeManager.getInstance().getCustomBeanScopes(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLookupElement(scope: String): LookupElementBuilder {
|
||||||
|
return LookupElementBuilder
|
||||||
|
.create(scope)
|
||||||
|
.withIcon(TypePresentationService.getService().getTypeIcon(SpringBeanScope::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resolve() = if (element.plainContent in getScopes().map { it.value }) element else null
|
||||||
|
|
||||||
|
override fun getVariants() = getScopes().map { getLookupElement(it.value) }.toList().toTypedArray()
|
||||||
|
}
|
||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.spring.references
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
|
import com.intellij.psi.*
|
||||||
|
import com.intellij.spring.model.DefaultSpringBeanQualifier
|
||||||
|
import com.intellij.spring.model.converters.SpringConverterUtil
|
||||||
|
import com.intellij.spring.model.jam.qualifiers.SpringJamQualifier
|
||||||
|
import com.intellij.spring.model.utils.SpringAutowireUtil
|
||||||
|
import com.intellij.spring.model.utils.SpringModelSearchers
|
||||||
|
import com.intellij.spring.references.SpringQualifierReference
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||||
|
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
||||||
|
import org.jetbrains.kotlin.asJava.toLightElements
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||||
|
import org.jetbrains.kotlin.idea.search.allScope
|
||||||
|
import org.jetbrains.kotlin.idea.spring.springModel
|
||||||
|
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
|
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.plainContent
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
// Based on com.intellij.spring.references.SpringQualifierReference
|
||||||
|
// It inherits from SpringQualifierReference to allow reuse of existing Java inspections which explicitly check for SpringQualifierReference
|
||||||
|
class KtSpringQualifierReference(element: KtStringTemplateExpression) : SpringQualifierReference(StringTemplatePsiLiteralWrapper(element)) {
|
||||||
|
class StringTemplatePsiLiteralWrapper(
|
||||||
|
val element: KtStringTemplateExpression
|
||||||
|
) : PsiElement by element, PsiLiteralExpression, KtLightElement<KtStringTemplateExpression, KtStringTemplateExpression>, PsiCompiledElement {
|
||||||
|
|
||||||
|
override fun getValue() = element.plainContent
|
||||||
|
override fun getType() = PsiType.getJavaLangString(element.manager, element.project.allScope())
|
||||||
|
|
||||||
|
override val clsDelegate: KtStringTemplateExpression
|
||||||
|
get() = element
|
||||||
|
override val kotlinOrigin: KtStringTemplateExpression
|
||||||
|
get() = element
|
||||||
|
|
||||||
|
override fun getMirror() = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAnnotationFqName(): String? {
|
||||||
|
val annotationEntry = element.getStrictParentOfType<KtAnnotationEntry>() ?: return null
|
||||||
|
val context = annotationEntry.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val annotationType = context[BindingContext.TYPE, annotationEntry.typeReference] ?: return null
|
||||||
|
return annotationType.constructor.declarationDescriptor?.importableFqName?.asString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun multiResolve(incompleteCode: Boolean): Array<out ResolveResult> {
|
||||||
|
val annotationEntry = element.getStrictParentOfType<KtAnnotationEntry>() ?: return ResolveResult.EMPTY_ARRAY
|
||||||
|
val lightAnnotation = annotationEntry.toLightAnnotation() ?: return ResolveResult.EMPTY_ARRAY
|
||||||
|
val springModel = element.springModel ?: return ResolveResult.EMPTY_ARRAY
|
||||||
|
|
||||||
|
val results = ArrayList<ResolveResult>()
|
||||||
|
val jamQualifier = SpringJamQualifier(lightAnnotation, null)
|
||||||
|
|
||||||
|
val qualifiedBeans = springModel.findQualifiedBeans(jamQualifier)
|
||||||
|
qualifiedBeans.mapTo(results) { PsiElementResolveResult(it.springBean.springQualifier!!.identifyingPsiElement) }
|
||||||
|
|
||||||
|
val qualifierValue = jamQualifier.qualifierValue
|
||||||
|
if (qualifierValue != null) {
|
||||||
|
val beanPointer = SpringModelSearchers.findBean(springModel, qualifierValue)
|
||||||
|
val psiElement = if (beanPointer != null && beanPointer.isValid) beanPointer.psiElement else null
|
||||||
|
if (psiElement != null) results += PsiElementResolveResult(psiElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't get light elements for property in the synthetic completion KtFile, so look for original one instead
|
||||||
|
private fun getOriginalProperty(): KtProperty? {
|
||||||
|
val currentProperty = element.getStrictParentOfType<KtProperty>() ?: return null
|
||||||
|
val originalFile = element.containingFile.originalFile as? KtFile ?: return null
|
||||||
|
return originalFile.findElementAt(currentProperty.startOffset)?.getNonStrictParentOfType<KtProperty>()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getVariants(): Array<out Any> {
|
||||||
|
val annotationFqName = getAnnotationFqName() ?: return LookupElement.EMPTY_ARRAY
|
||||||
|
val springModel = element.springModel ?: return LookupElement.EMPTY_ARRAY
|
||||||
|
val property = getOriginalProperty() ?: return LookupElement.EMPTY_ARRAY
|
||||||
|
val lightElement = property.toLightElements().firstOrNull {
|
||||||
|
it is PsiField || (it is PsiMethod && !it.name.startsWith("set"))
|
||||||
|
}
|
||||||
|
val expectedPsiType = when (lightElement) {
|
||||||
|
is PsiMethod -> lightElement.returnType
|
||||||
|
is PsiField -> lightElement.type
|
||||||
|
else -> null
|
||||||
|
} ?: return LookupElement.EMPTY_ARRAY
|
||||||
|
return SpringAutowireUtil
|
||||||
|
.autowireByType(springModel, expectedPsiType)
|
||||||
|
.mapNotNull {
|
||||||
|
val qualifier = it.springBean.springQualifier
|
||||||
|
val value = qualifier?.qualifierValue
|
||||||
|
when {
|
||||||
|
qualifier == null ->
|
||||||
|
SpringConverterUtil.createCompletionVariant(it)
|
||||||
|
value != null && (qualifier is DefaultSpringBeanQualifier || qualifier.qualifierType?.qualifiedName == annotationFqName) ->
|
||||||
|
SpringConverterUtil.createCompletionVariant(it, value)
|
||||||
|
else ->
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.toTypedArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// ELEMENT: java
|
||||||
|
// CHAR: \n
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan(basePackages = arrayOf("ja<caret>va"))
|
||||||
|
open class App {
|
||||||
|
|
||||||
|
}
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// ELEMENT: java
|
||||||
|
// CHAR: \n
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan(basePackages = arrayOf("javava"))
|
||||||
|
open class App {
|
||||||
|
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// ELEMENT: java
|
||||||
|
// CHAR: \t
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan(basePackages = arrayOf("ja<caret>va"))
|
||||||
|
open class App {
|
||||||
|
|
||||||
|
}
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// ELEMENT: java
|
||||||
|
// CHAR: \t
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan(basePackages = arrayOf("java"))
|
||||||
|
open class App {
|
||||||
|
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// NUMBER: 2
|
||||||
|
// EXIST: { lookupString:"java" }
|
||||||
|
// EXIST: { lookupString:"javax" }
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan(basePackages = arrayOf("ja<caret>va"))
|
||||||
|
open class App {
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user