Remove 172 bunchset
This commit is contained in:
@@ -1,77 +0,0 @@
|
||||
<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>
|
||||
@@ -1,57 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-512
@@ -1,512 +0,0 @@
|
||||
/*
|
||||
* 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.generate
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder
|
||||
import com.intellij.codeInsight.template.Expression
|
||||
import com.intellij.codeInsight.template.ExpressionContext
|
||||
import com.intellij.codeInsight.template.TemplateBuilderImpl
|
||||
import com.intellij.codeInsight.template.TextResult
|
||||
import com.intellij.codeInspection.SmartHashMap
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.runWriteAction
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PropertyUtil
|
||||
import com.intellij.psi.util.PsiTypesUtil
|
||||
import com.intellij.spring.CommonSpringModel
|
||||
import com.intellij.spring.model.CommonSpringBean
|
||||
import com.intellij.spring.model.SpringBeanPointer
|
||||
import com.intellij.spring.model.SpringModelSearchParameters
|
||||
import com.intellij.spring.model.actions.generate.GenerateSpringBeanDependenciesUtil
|
||||
import com.intellij.spring.model.actions.generate.GenerateSpringBeanDependenciesUtil.*
|
||||
import com.intellij.spring.model.actions.generate.SpringBeanClassMember
|
||||
import com.intellij.spring.model.highlighting.SpringConstructorArgResolveUtil
|
||||
import com.intellij.spring.model.utils.SpringBeanCoreUtils
|
||||
import com.intellij.spring.model.utils.SpringBeanUtils
|
||||
import com.intellij.spring.model.utils.SpringModelSearchers
|
||||
import com.intellij.spring.model.utils.SpringModelUtils
|
||||
import com.intellij.spring.model.xml.DomSpringBean
|
||||
import com.intellij.spring.model.xml.beans.Beans
|
||||
import com.intellij.spring.model.xml.beans.SpringBean
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import com.intellij.util.xml.DomElement
|
||||
import com.intellij.util.xml.DomUtil
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.forcedModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaOrKotlinMemberDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.getParameterDescriptor
|
||||
import org.jetbrains.kotlin.idea.completion.BasicLookupElementFactory
|
||||
import org.jetbrains.kotlin.idea.completion.InsertHandlerProvider
|
||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.core.getOrCreateCompanionObject
|
||||
import org.jetbrains.kotlin.idea.editor.BatchTemplateRunner
|
||||
import org.jetbrains.kotlin.idea.spring.beanClass
|
||||
import org.jetbrains.kotlin.idea.spring.effectiveBeanClasses
|
||||
import org.jetbrains.kotlin.idea.util.CallType
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.load.java.propertyNameBySetMethodName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.TypeReconstructionUtil
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
import java.util.*
|
||||
|
||||
// TODO: GenerateSpringBeanDependenciesUtil.ensureFileWritable() is not accessible here
|
||||
private fun DomElement.ensureFileWritable() = ensureFileWritable(DomUtil.getFile(this).virtualFile, manager.project)
|
||||
|
||||
// TODO: GenerateSpringBeanDependenciesUtil.getReferenceName() is not accessible here
|
||||
private fun getReferencedName(currentBean: SpringBean, bean: SpringBeanPointer<CommonSpringBean>): String? {
|
||||
val model = SpringModelUtils.getInstance().getSpringModel(currentBean)
|
||||
return SpringBeanCoreUtils.getReferencedName(bean, model.allCommonBeans)
|
||||
}
|
||||
|
||||
// TODO: GenerateSpringBeanDependenciesUtil.getExistedSetter() is not accessible here
|
||||
private fun getExistedSetter(currentBeanClass: PsiClass, setterPsiClass: PsiClass): PsiMethod? {
|
||||
val psiClassType = JavaPsiFacade.getInstance(setterPsiClass.project).elementFactory.createType(setterPsiClass)
|
||||
return currentBeanClass.allMethods.firstOrNull {
|
||||
PropertyUtil.isSimplePropertySetter(it) && it.parameterList.parameters.first().type.isAssignableFrom(psiClassType)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: GenerateSpringBeanDependenciesUtil.findConstructor() is not accessible here
|
||||
private fun findConstructor(constructors: Array<PsiMethod>, psiParameterTypes: List<PsiType>): PsiMethod? {
|
||||
return constructors.firstOrNull {
|
||||
val parameters = it.parameterList.parameters
|
||||
if (it.parameterList.parametersCount != psiParameterTypes.size) return@firstOrNull false
|
||||
(psiParameterTypes zip parameters).all { it.first.isAssignableFrom(it.second.type) }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: GenerateSpringBeanDependenciesUtil.findExistedConstructor() is not accessible here
|
||||
private fun findExistedConstructor(
|
||||
currentBean: SpringBean,
|
||||
currentBeanClass: PsiClass,
|
||||
candidateParameterClasses: Array<out PsiClass>
|
||||
): PsiMethod? {
|
||||
val constructors = SpringConstructorArgResolveUtil.findMatchingMethods(currentBean)
|
||||
for (candidateBeanClass in candidateParameterClasses) {
|
||||
for (constructor in constructors) {
|
||||
val psiParameterTypes = SmartList<PsiType>().apply {
|
||||
constructor.parameterList.parameters.mapTo(this) { it.type }
|
||||
add(PsiTypesUtil.getClassType(candidateBeanClass))
|
||||
}
|
||||
findConstructor(currentBeanClass.constructors, psiParameterTypes)?.let { return it }
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
// TODO: GenerateSpringBeanDependenciesUtil.createSpringBean() is not accessible here
|
||||
private fun createSpringBean(parentBeans: Beans, psiClass: PsiClass): SpringBean? {
|
||||
if (!((parentBeans as DomElement)).ensureFileWritable()) return null
|
||||
|
||||
return parentBeans.addBean().apply {
|
||||
clazz.stringValue = psiClass.qualifiedName
|
||||
id.stringValue = SpringBeanCoreUtils.suggestBeanNames(this).firstOrNull() ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun SpringBean.getFactoryFunctionName(factoryBeanClass: KtClass): String {
|
||||
factoryMethod.stringValue?.let { if (!it.isBlank()) return it }
|
||||
|
||||
val existingNames = factoryBeanClass.declarations.mapNotNull { if (it is KtFunction || it is KtClassOrObject) it.name else null }
|
||||
return KotlinNameSuggester.suggestNameByName("create${beanClass()!!.name}") { it !in existingNames }
|
||||
}
|
||||
|
||||
internal val PsiClass.defaultTypeText: String
|
||||
get() {
|
||||
val qName = qualifiedName ?: return "Any"
|
||||
val typeParameters = typeParameters
|
||||
if (typeParameters.isEmpty()) return qName
|
||||
return TypeReconstructionUtil.getTypeNameAndStarProjectionsString(qName, typeParameters.size)
|
||||
}
|
||||
|
||||
private fun createSettable(
|
||||
candidateBean: SpringBeanPointer<CommonSpringBean>,
|
||||
currentBeanClass: KtLightClass,
|
||||
candidateBeanClasses: Array<out PsiClass>,
|
||||
injectionKind: SpringDependencyInjectionKind
|
||||
): KtNamedDeclaration {
|
||||
val project = currentBeanClass.project
|
||||
val psiFactory = KtPsiFactory(project)
|
||||
val beanName = candidateBean.name
|
||||
try {
|
||||
val candidateClass = candidateBeanClasses.first()
|
||||
val propertyName = if (beanName != null && beanName.isIdentifier()) beanName else candidateClass.name!!
|
||||
|
||||
val prototype: KtNamedDeclaration = when (injectionKind) {
|
||||
SpringDependencyInjectionKind.SETTER -> {
|
||||
psiFactory.createFunction("fun set${propertyName.capitalize()}(${propertyName.decapitalize()}: ${candidateClass.defaultTypeText}) { }")
|
||||
}
|
||||
|
||||
SpringDependencyInjectionKind.LATEINIT_PROPERTY -> {
|
||||
psiFactory.createProperty("lateinit var ${propertyName.decapitalize()}: ${candidateClass.defaultTypeText}")
|
||||
}
|
||||
|
||||
else -> error("Unexpected injection kind: $injectionKind")
|
||||
}
|
||||
return currentBeanClass.kotlinOrigin!!.addDeclaration(prototype).apply { ShortenReferences.DEFAULT.process(this) }
|
||||
}
|
||||
catch (e: IncorrectOperationException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun getSuggestedNames(
|
||||
beanPointer: SpringBeanPointer<CommonSpringBean>,
|
||||
declaration: KtCallableDeclaration,
|
||||
excludedInValidator: List<KtDeclaration> = listOf(declaration),
|
||||
existingNames: Collection<String> = emptyList(),
|
||||
getType: CallableDescriptor.() -> KotlinType?
|
||||
): Collection<String> {
|
||||
val names = LinkedHashSet<String>()
|
||||
|
||||
val newDeclarationNameValidator =
|
||||
NewDeclarationNameValidator(declaration.parent, null, NewDeclarationNameValidator.Target.VARIABLES, excludedInValidator)
|
||||
fun validate(name: String) = name !in existingNames && newDeclarationNameValidator(name)
|
||||
|
||||
SpringBeanUtils.getInstance()
|
||||
.findBeanNames(beanPointer.springBean)
|
||||
.asSequence()
|
||||
.filter { it.isIdentifier() }
|
||||
.mapTo(names) { KotlinNameSuggester.suggestNameByName(it, ::validate) }
|
||||
|
||||
(declaration.resolveToDescriptor() as CallableDescriptor).getType()?.let {
|
||||
names += KotlinNameSuggester.suggestNamesByType(it, ::validate)
|
||||
}
|
||||
|
||||
return names
|
||||
}
|
||||
|
||||
internal fun TemplateBuilderImpl.appendVariableTemplate(
|
||||
variable: KtCallableDeclaration,
|
||||
candidateBeanClasses: Array<out PsiClass>,
|
||||
computeSuggestions: (() -> Collection<String>)?
|
||||
) {
|
||||
if (computeSuggestions != null) {
|
||||
val suggestedNames = computeSuggestions()
|
||||
val defaultName = variable.name ?: ""
|
||||
val nameExpression = object : Expression() {
|
||||
override fun calculateResult(context: ExpressionContext) = TextResult(defaultName)
|
||||
|
||||
override fun calculateQuickResult(context: ExpressionContext) = calculateResult(context)
|
||||
|
||||
override fun calculateLookupItems(context: ExpressionContext): Array<LookupElement>? {
|
||||
PsiDocumentManager.getInstance(context.project).commitAllDocuments()
|
||||
return suggestedNames.map { LookupElementBuilder.create(it) }.toTypedArray()
|
||||
|
||||
}
|
||||
}
|
||||
replaceElement(variable.nameIdentifier, "names", nameExpression, true)
|
||||
}
|
||||
|
||||
val superTypeVariants = getSuperTypeVariants(candidateBeanClasses)
|
||||
if (superTypeVariants.size > 1) {
|
||||
val lookupFactory = BasicLookupElementFactory(variable.project, InsertHandlerProvider(CallType.TYPE) { emptyList() })
|
||||
val typeReferenceExpression = object : Expression() {
|
||||
override fun calculateResult(context: ExpressionContext) = TextResult(candidateBeanClasses.first().qualifiedName ?: "")
|
||||
|
||||
override fun calculateQuickResult(context: ExpressionContext) = calculateResult(context)
|
||||
|
||||
override fun calculateLookupItems(context: ExpressionContext): Array<LookupElement>? {
|
||||
return superTypeVariants
|
||||
.mapTo(LinkedHashSet()) { lookupFactory.createLookupElementForJavaClass(it, qualifyNestedClasses = true) }
|
||||
.toTypedArray()
|
||||
}
|
||||
}
|
||||
replaceElement(variable.typeReference, "type", typeReferenceExpression, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun BatchTemplateRunner.addCreateFunctionTemplate(
|
||||
function: KtFunction,
|
||||
candidateBeanClasses: Map<Int, Array<out PsiClass>>,
|
||||
dependency: SpringBeanPointer<CommonSpringBean>
|
||||
) {
|
||||
val parameterList = function.valueParameterList!!
|
||||
val builder = TemplateBuilderImpl(parameterList)
|
||||
addTemplateFactory(parameterList) {
|
||||
for ((paramIndex, candidateBeanClassesForParam) in candidateBeanClasses) {
|
||||
builder.appendVariableTemplate(function.valueParameters[paramIndex], candidateBeanClassesForParam) {
|
||||
getSuggestedNames(dependency, function, listOf(function.valueParameters[paramIndex], function)) {
|
||||
valueParameters[paramIndex].type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder.buildInlineTemplate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun BatchTemplateRunner.addCreatePropertyTemplate(property: KtProperty, candidateBeanClasses: Array<out PsiClass>) {
|
||||
val builder = TemplateBuilderImpl(property)
|
||||
addTemplateFactory(property) {
|
||||
builder.appendVariableTemplate(property, candidateBeanClasses, null)
|
||||
builder.buildInlineTemplate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun BatchTemplateRunner.addCreateFunctionTemplate(
|
||||
function: KtFunction,
|
||||
paramIndex: Int,
|
||||
candidateBeanClasses: Array<out PsiClass>,
|
||||
dependency: SpringBeanPointer<CommonSpringBean>
|
||||
) {
|
||||
addCreateFunctionTemplate(function, mapOf(paramIndex to candidateBeanClasses), dependency)
|
||||
}
|
||||
|
||||
private fun getOrCreateSetter(
|
||||
candidateBean: SpringBeanPointer<CommonSpringBean>,
|
||||
currentBeanClass: KtLightClass,
|
||||
candidateBeanClasses: Array<out PsiClass>,
|
||||
templatesHolder: BatchTemplateRunner,
|
||||
injectionKind: SpringDependencyInjectionKind
|
||||
): PsiNamedElement? {
|
||||
for (candidateBeanClass in candidateBeanClasses) {
|
||||
getExistedSetter(currentBeanClass, candidateBeanClass)?.let { return it }
|
||||
}
|
||||
|
||||
if (!ensureFileWritable(currentBeanClass)) return null
|
||||
val settable = createSettable(candidateBean, currentBeanClass, candidateBeanClasses, injectionKind)
|
||||
when (settable) {
|
||||
is KtNamedFunction -> templatesHolder.addCreateFunctionTemplate(settable, 0, candidateBeanClasses, candidateBean)
|
||||
is KtProperty -> templatesHolder.addCreatePropertyTemplate(settable, candidateBeanClasses)
|
||||
}
|
||||
|
||||
return settable
|
||||
}
|
||||
|
||||
private fun createSetterDependency(
|
||||
currentBean: SpringBean,
|
||||
dependency: SpringBeanPointer<CommonSpringBean>,
|
||||
injectionKind: SpringDependencyInjectionKind
|
||||
): BatchTemplateRunner? {
|
||||
val templatesHolder = BatchTemplateRunner(currentBean.manager.project)
|
||||
val currentBeanClass = currentBean.beanClass() as? KtLightClass ?: return null
|
||||
val candidateBeanClasses = dependency.effectiveBeanClasses().ifEmpty { return null }
|
||||
val setter = getOrCreateSetter(dependency, currentBeanClass, candidateBeanClasses, templatesHolder, injectionKind) ?: return null
|
||||
currentBean.addProperty().apply {
|
||||
name.ensureXmlElementExists()
|
||||
name.stringValue = when (setter) {
|
||||
is PsiMethod, is KtFunction -> propertyNameBySetMethodName(Name.identifier(setter.name!!), false)!!.asString()
|
||||
else -> setter.name
|
||||
}
|
||||
refAttr.setStringValue(getReferencedName(currentBean, dependency))
|
||||
}
|
||||
return templatesHolder
|
||||
}
|
||||
|
||||
private fun addConstructorParameter(
|
||||
currentBeanClass: KtLightClass,
|
||||
candidateBeanClass: PsiClass,
|
||||
constructor: KtFunction
|
||||
) {
|
||||
val psiFactory = KtPsiFactory(currentBeanClass)
|
||||
|
||||
val validator = NewDeclarationNameValidator(constructor, null, NewDeclarationNameValidator.Target.VARIABLES)
|
||||
val resolutionFacade = currentBeanClass.kotlinOrigin!!.getResolutionFacade()
|
||||
val defaultType = (candidateBeanClass.getJavaOrKotlinMemberDescriptor(resolutionFacade) as ClassDescriptor).defaultType
|
||||
val name = KotlinNameSuggester.suggestNamesByType(defaultType, validator).first()
|
||||
|
||||
val parameter = psiFactory.createParameter("$name: ${candidateBeanClass.defaultTypeText}")
|
||||
constructor.getValueParameterList()!!.addParameter(parameter).apply { ShortenReferences.DEFAULT.process(this) }
|
||||
}
|
||||
|
||||
private fun findProperConstructorAndAddParameter(
|
||||
currentBean: SpringBean,
|
||||
dependency: SpringBeanPointer<CommonSpringBean>,
|
||||
currentBeanClass: KtLightClass,
|
||||
candidateBeanClass: PsiClass,
|
||||
holder: BatchTemplateRunner
|
||||
): PsiMethod? {
|
||||
val lightConstructor = currentBean.resolvedConstructorArgs.resolvedMethod as? KtLightMethod ?: return null
|
||||
val constructorOrigin = lightConstructor.kotlinOrigin
|
||||
val properConstructor = when (constructorOrigin) {
|
||||
is KtFunction -> constructorOrigin
|
||||
is KtClass -> constructorOrigin.createPrimaryConstructorIfAbsent()
|
||||
else -> return null
|
||||
}
|
||||
addConstructorParameter(currentBeanClass, candidateBeanClass, properConstructor)
|
||||
holder.addCreateFunctionTemplate(properConstructor, properConstructor.getValueParameters().lastIndex, arrayOf(candidateBeanClass), dependency)
|
||||
return lightConstructor
|
||||
}
|
||||
|
||||
private fun createConstructorWithTemplate(
|
||||
currentBean: SpringBean,
|
||||
dependency: SpringBeanPointer<CommonSpringBean>,
|
||||
templatesHolder: BatchTemplateRunner
|
||||
) {
|
||||
val beanClass = currentBean.beanClass() as? KtLightClass ?: return
|
||||
val ktBeanClass = beanClass.kotlinOrigin as? KtClass ?: return
|
||||
|
||||
try {
|
||||
val psiFactory = KtPsiFactory(beanClass)
|
||||
val factoryFunction = when {
|
||||
currentBean.factoryBean.exists() -> {
|
||||
// TODO: Support non-Kotlin factory beans
|
||||
val factoryClass = currentBean.factoryBean.value?.beanClass as? KtLightClass ?: return
|
||||
val ktFactoryClass = factoryClass.kotlinOrigin as? KtClass ?: return
|
||||
val funName = currentBean.getFactoryFunctionName(ktFactoryClass)
|
||||
val funText = "fun $funName(): ${beanClass.defaultTypeText} {\n return null \n}"
|
||||
ktFactoryClass.addDeclaration(psiFactory.createFunction(funText))
|
||||
}
|
||||
currentBean.factoryMethod.exists() -> {
|
||||
val funName = currentBean.getFactoryFunctionName(ktBeanClass)
|
||||
val funText = "@JvmStatic fun $funName(): ${beanClass.defaultTypeText} {\n return null \n}"
|
||||
ktBeanClass.getOrCreateCompanionObject().addDeclaration(psiFactory.createFunction(funText))
|
||||
}
|
||||
else -> {
|
||||
if (ktBeanClass.hasPrimaryConstructor() || ktBeanClass.getSecondaryConstructors().isNotEmpty()) {
|
||||
ktBeanClass.addDeclaration(psiFactory.createSecondaryConstructor("constructor()"))
|
||||
}
|
||||
else {
|
||||
ktBeanClass.createPrimaryConstructorIfAbsent()
|
||||
}
|
||||
}
|
||||
} as KtFunction
|
||||
|
||||
ShortenReferences.DEFAULT.process(factoryFunction)
|
||||
|
||||
val dummyMethod = JavaPsiFacade.getElementFactory(beanClass.project).createMethod("foo", PsiType.VOID)
|
||||
dummyMethod.containingFile.forcedModuleInfo = ktBeanClass.getModuleInfo()
|
||||
SpringConstructorArgResolveUtil.suggestParamsForConstructorArgs(currentBean).forEach { dummyMethod.parameterList.add(it) }
|
||||
|
||||
val parameterList = factoryFunction.valueParameterList!!
|
||||
val indexOffset = parameterList.parameters.size
|
||||
val candidateClassMap = SmartHashMap<Int, Array<PsiClass>>()
|
||||
val resolutionFacade = ktBeanClass.getResolutionFacade()
|
||||
for ((i, psiParam) in dummyMethod.parameterList.parameters.withIndex()) {
|
||||
val descriptor = psiParam.getParameterDescriptor(resolutionFacade)!!
|
||||
val ktParameter = psiFactory.createParameter(
|
||||
"${psiParam.name}: ${IdeDescriptorRenderers.SOURCE_CODE_NOT_NULL_TYPE_APPROXIMATION.renderType(descriptor.type)}"
|
||||
)
|
||||
parameterList.addParameter(ktParameter)
|
||||
(psiParam.type as? PsiClassType)?.resolve()?.let { candidateClassMap[i + indexOffset] = arrayOf(it) }
|
||||
}
|
||||
|
||||
templatesHolder.addCreateFunctionTemplate(factoryFunction, candidateClassMap, dependency)
|
||||
}
|
||||
catch (e: IncorrectOperationException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createConstructorDependency(
|
||||
currentBean: SpringBean,
|
||||
dependency: SpringBeanPointer<CommonSpringBean>
|
||||
): BatchTemplateRunner? {
|
||||
val templatesHolder = BatchTemplateRunner(currentBean.manager.project)
|
||||
val currentBeanClass = currentBean.beanClass() as? KtLightClass ?: return null
|
||||
val candidateBeanClasses = dependency.effectiveBeanClasses().ifEmpty { return null }
|
||||
var existedConstructor = findExistedConstructor(currentBean, currentBeanClass, candidateBeanClasses)
|
||||
if (existedConstructor == null) {
|
||||
if (!ensureFileWritable(currentBeanClass)) return null
|
||||
existedConstructor = findProperConstructorAndAddParameter(currentBean, dependency, currentBeanClass, candidateBeanClasses.first(), templatesHolder)
|
||||
}
|
||||
|
||||
val newConstructorArg = currentBean.addConstructorArg()
|
||||
newConstructorArg.refAttr.stringValue = getReferencedName(currentBean, dependency)
|
||||
if (existedConstructor == null && SpringConstructorArgResolveUtil.findMatchingMethods(currentBean).isEmpty()) {
|
||||
createConstructorWithTemplate(currentBean, dependency, templatesHolder)
|
||||
}
|
||||
|
||||
return templatesHolder
|
||||
}
|
||||
|
||||
private fun generateDependency(
|
||||
springBean: SpringBean,
|
||||
dependency: SpringBeanPointer<CommonSpringBean>,
|
||||
injectionKind: SpringDependencyInjectionKind
|
||||
): BatchTemplateRunner? {
|
||||
return runWriteAction {
|
||||
if (injectionKind.isSetter) {
|
||||
createSetterDependency(springBean, dependency, injectionKind)
|
||||
}
|
||||
else {
|
||||
createConstructorDependency(springBean, dependency)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class SpringDependencyInjectionKind(val isSetter: Boolean) {
|
||||
CONSTRUCTOR(false),
|
||||
SETTER(true),
|
||||
LATEINIT_PROPERTY(true)
|
||||
}
|
||||
|
||||
@set:TestOnly
|
||||
var Project.beanFilter: (SpringBeanPointer<CommonSpringBean>) -> Boolean
|
||||
by NotNullableUserDataProperty(Key.create("BEAN_CHOOSER")) { true }
|
||||
|
||||
@NotNull
|
||||
private fun chooseDependentBeans(
|
||||
candidates: Set<SpringBeanClassMember>,
|
||||
project: Project,
|
||||
isSetterDependency: Boolean
|
||||
): List<SpringBeanPointer<CommonSpringBean>> {
|
||||
return if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
candidates.map { it.springBean }.filter(project.beanFilter)
|
||||
}
|
||||
else {
|
||||
GenerateSpringBeanDependenciesUtil.chooseDependentBeans(candidates, project, isSetterDependency)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateDependenciesFor(
|
||||
springModel: CommonSpringModel,
|
||||
klass: KtLightClass,
|
||||
injectionKind: SpringDependencyInjectionKind
|
||||
): List<BatchTemplateRunner> {
|
||||
val project = klass.project
|
||||
val isSetter = injectionKind.isSetter
|
||||
|
||||
SpringModelSearchers
|
||||
.findBeans(springModel, SpringModelSearchParameters.byClass(klass))
|
||||
.asSequence()
|
||||
.map { it.springBean }
|
||||
.filterIsInstance<SpringBean>()
|
||||
.firstOrNull { acceptBean(it, false) }
|
||||
?.let { springBean ->
|
||||
if (!springBean.ensureFileWritable()) return emptyList()
|
||||
if (springBean.beanClass() == null) return emptyList()
|
||||
val dependencies = chooseDependentBeans(getCandidates(springBean, isSetter), project, isSetter)
|
||||
return dependencies.mapNotNull { generateDependency(springBean, it, injectionKind) }
|
||||
}
|
||||
|
||||
val dependencies = chooseDependentBeans(getCandidates(springModel, klass, isSetter), project, isSetter)
|
||||
val beanXml = dependencies.singleOrNull()?.springBean as? DomSpringBean ?: return emptyList()
|
||||
val beansXml = beanXml.getParentOfType(Beans::class.java, false) ?: return emptyList()
|
||||
val newBean = createSpringBean(beansXml, klass) ?: return emptyList()
|
||||
|
||||
return dependencies.mapNotNull { generateDependency(newBean, it, injectionKind) }
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
package org.jetbrains.kotlin.idea.spring.inspections
|
||||
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.spring.model.highlighting.jam.SpringComponentScanInspection
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
|
||||
import org.jetbrains.kotlin.idea.inspections.registerWithElementsUnwrapped
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtVisitorVoid
|
||||
|
||||
class KotlinSpringComponentScanInspection : AbstractKotlinInspection() {
|
||||
private val javaInspection by lazy {
|
||||
object : SpringComponentScanInspection() {
|
||||
// make base method visible
|
||||
override public fun checkClass(aClass: PsiClass, holder: ProblemsHolder, module: Module) = super.checkClass(aClass, holder, module)
|
||||
}
|
||||
}
|
||||
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||
return object: KtVisitorVoid() {
|
||||
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(classOrObject) ?: return
|
||||
val lightClass = classOrObject.toLightClass() ?: return
|
||||
val tmpHolder = ProblemsHolder(holder.manager, classOrObject.containingFile, isOnTheFly)
|
||||
javaInspection.checkClass(lightClass, tmpHolder, module)
|
||||
tmpHolder.resultsArray.registerWithElementsUnwrapped(holder, isOnTheFly)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* 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.inspections
|
||||
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.spring.model.highlighting.SpringJavaAutowiredMembersInspection
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
|
||||
import org.jetbrains.kotlin.idea.inspections.registerWithElementsUnwrapped
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtVisitorVoid
|
||||
|
||||
class SpringKotlinAutowiredMembersInspection : AbstractKotlinInspection() {
|
||||
private val javaInspection by lazy { SpringJavaAutowiredMembersInspection() }
|
||||
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||
return object: KtVisitorVoid() {
|
||||
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
|
||||
val lightClass = classOrObject.toLightClass() ?: return
|
||||
javaInspection.checkClass(lightClass, holder.manager, isOnTheFly)?.registerWithElementsUnwrapped(holder, isOnTheFly)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-182
@@ -1,182 +0,0 @@
|
||||
package org.jetbrains.kotlin.idea.spring.inspections
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil
|
||||
import com.intellij.codeInsight.FileModificationService
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.template.*
|
||||
import com.intellij.codeInspection.LocalQuickFix
|
||||
import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PropertyUtil
|
||||
import com.intellij.spring.CommonSpringModel
|
||||
import com.intellij.spring.SpringBundle
|
||||
import com.intellij.spring.model.SpringBeanPointer
|
||||
import com.intellij.spring.model.converters.SpringConverterUtil
|
||||
import com.intellij.spring.model.highlighting.SpringAutowireUtil
|
||||
import com.intellij.spring.model.highlighting.SpringJavaAutowiringInspection
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.asJava.toLightElements
|
||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
|
||||
import org.jetbrains.kotlin.idea.inspections.registerWithElementsUnwrapped
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
|
||||
class SpringKotlinAutowiringInspection : AbstractKotlinInspection() {
|
||||
// Based on SpringJavaAutowiringInspection.AddSpringBeanQualifierFix
|
||||
class AddQualifierFix(
|
||||
modifierListOwner: KtModifierListOwner,
|
||||
private val beanPointers: Collection<SpringBeanPointer<*>>,
|
||||
private val annotationFqName: String
|
||||
) : LocalQuickFix {
|
||||
private val elementPointer = modifierListOwner.createSmartPointer()
|
||||
|
||||
override fun getName() = SpringBundle.message("SpringAutowiringInspection.add.qualifier.fix")
|
||||
|
||||
override fun getFamilyName() = name
|
||||
|
||||
private fun getQualifierNamesSuggestNamesExpression(expression: KtStringTemplateExpression): Expression {
|
||||
return object : Expression() {
|
||||
override fun calculateResult(context: ExpressionContext): Result? {
|
||||
PsiDocumentManager.getInstance(context.project).commitAllDocuments()
|
||||
return TextResult(expression.plainContent)
|
||||
}
|
||||
|
||||
override fun calculateQuickResult(context: ExpressionContext) = this.calculateResult(context)
|
||||
|
||||
override fun calculateLookupItems(context: ExpressionContext): Array<LookupElement>? {
|
||||
PsiDocumentManager.getInstance(context.project).commitAllDocuments()
|
||||
return beanPointers.sortedBy { it.name ?: "" }.mapNotNull { SpringConverterUtil.createCompletionVariant(it) }.toTypedArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createQualifierNameTemplate(expression: KtStringTemplateExpression): Template {
|
||||
val builder = TemplateBuilderImpl(expression.containingFile)
|
||||
builder.replaceRange(
|
||||
expression.getContentRange().shiftRight(expression.startOffset),
|
||||
getQualifierNamesSuggestNamesExpression(expression)
|
||||
)
|
||||
return builder.buildInlineTemplate()
|
||||
}
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
val modifierListOwner = elementPointer.element ?: return
|
||||
if (!FileModificationService.getInstance().preparePsiElementForWrite(modifierListOwner)) return
|
||||
if (beanPointers.isEmpty()) return
|
||||
|
||||
val defaultBeanName = with(beanPointers.first().name) { if (isNullOrBlank()) "Unknown" else this }
|
||||
val entry = KtPsiFactory(project).createAnnotationEntry("@$annotationFqName(\"$defaultBeanName\")")
|
||||
val addedEntry = modifierListOwner.addAnnotationEntry(entry)
|
||||
|
||||
ShortenReferences.DEFAULT.process(addedEntry)
|
||||
|
||||
val stringTemplate = addedEntry.valueArguments.first().getArgumentExpression() as? KtStringTemplateExpression ?: return
|
||||
val virtualFile = modifierListOwner.containingFile.virtualFile!!
|
||||
val editor = FileEditorManager.getInstance(project).openTextEditor(OpenFileDescriptor(project, virtualFile, 0), false)!!
|
||||
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
|
||||
TemplateManager.getInstance(project).startTemplate(editor, createQualifierNameTemplate(stringTemplate))
|
||||
}
|
||||
}
|
||||
|
||||
private val javaInspection by lazy { SpringJavaAutowiringInspection() }
|
||||
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object : KtVisitorVoid() {
|
||||
// TODO: SpringJavaAutowiringInspection.checkAutowiredMethod() is not accessible here
|
||||
private fun checkAutowiredMethod(psiMethod: PsiMethod, holder: ProblemsHolder, springModel: CommonSpringModel, required: Boolean) {
|
||||
val resourceAnnotation = SpringAutowireUtil.getResourceAnnotation(psiMethod)
|
||||
when {
|
||||
resourceAnnotation != null -> {
|
||||
val propertyType = PropertyUtil.getPropertyType(psiMethod) ?: return
|
||||
SpringJavaAutowiringInspection.checkAutowiredPsiMember(psiMethod, propertyType, holder, springModel, required)
|
||||
}
|
||||
psiMethod.parameterList.parametersCount == 0 &&
|
||||
SpringAutowireUtil.isAutowiredByAnnotation(psiMethod) -> {
|
||||
val nameIdentifier = psiMethod.nameIdentifier ?: return
|
||||
val message = SpringBundle.message("bean.autowiring.by.type.no.parameter.for.autowired.method",
|
||||
if (psiMethod.isConstructor) "constructor" else "method")
|
||||
holder.registerProblem(nameIdentifier, message)
|
||||
}
|
||||
else -> {
|
||||
for (parameter in psiMethod.parameterList.parameters) {
|
||||
if (AnnotationUtil.isAnnotated(parameter, "org.springframework.beans.factory.annotation.Value", true)) continue
|
||||
SpringJavaAutowiringInspection.checkAutowiredPsiMember(parameter, parameter.type, holder, springModel, required)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Array<ProblemDescriptor>.registerAdjustedProblems() {
|
||||
registerWithElementsUnwrapped(holder, isOnTheFly) { qf, element ->
|
||||
// Can't access AddSpringBeanQualifierFix class directly
|
||||
|
||||
val klass = qf.javaClass
|
||||
if (!klass.name.endsWith("AddSpringBeanQualifierFix")) return@registerWithElementsUnwrapped qf
|
||||
|
||||
try {
|
||||
val fields = klass.declaredFields
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val beanPointers = fields[1].apply { isAccessible = true }.get(qf) as Collection<SpringBeanPointer<*>>
|
||||
val annotationFqName = fields[2].apply { isAccessible = true }.get(qf) as String
|
||||
val modifierListOwner = element.getNonStrictParentOfType<KtModifierListOwner>()
|
||||
?: return@registerWithElementsUnwrapped qf
|
||||
AddQualifierFix(modifierListOwner, beanPointers, annotationFqName)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
return@registerWithElementsUnwrapped null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : PsiMember> T.processLightMember(
|
||||
action: T.(holder: ProblemsHolder, model: CommonSpringModel, required: Boolean) -> Unit
|
||||
) {
|
||||
val model = SpringAutowireUtil.getProcessingSpringModel(containingClass) ?: return
|
||||
val required = SpringAutowireUtil.isRequired(this)
|
||||
val tmpHolder = ProblemsHolder(holder.manager, containingFile, isOnTheFly)
|
||||
action(this, tmpHolder, model, required)
|
||||
tmpHolder.resultsArray.registerAdjustedProblems()
|
||||
}
|
||||
|
||||
private fun PsiMethod.processLightMethod() {
|
||||
if (!SpringAutowireUtil.isInjectionPoint(this)) return
|
||||
processLightMember { holder, model, required -> checkAutowiredMethod(this, holder, model, required) }
|
||||
}
|
||||
|
||||
private fun PsiField.processLightField() {
|
||||
if (!SpringAutowireUtil.isAutowiredByAnnotation(this)) return
|
||||
processLightMember { holder, model, required ->
|
||||
SpringJavaAutowiringInspection.checkAutowiredPsiMember(this, type, holder, model, required)
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiClass.processLightClass() {
|
||||
javaInspection.checkClass(this, holder.manager, isOnTheFly)?.registerAdjustedProblems()
|
||||
}
|
||||
|
||||
override fun visitNamedFunction(function: KtNamedFunction) {
|
||||
function.toLightMethods().firstOrNull()?.processLightMethod()
|
||||
}
|
||||
|
||||
override fun visitProperty(property: KtProperty) {
|
||||
if (property.name != null) // It is here because `lightElement.name` returns `<no name provided>` instead of `null` suddenly
|
||||
for (lightElement in property.toLightElements()) {
|
||||
when (lightElement) {
|
||||
is KtLightMethod -> lightElement.processLightMethod()
|
||||
is KtLightField -> lightElement.processLightField()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
|
||||
classOrObject.toLightClass()?.processLightClass()
|
||||
}
|
||||
}
|
||||
}
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* 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.lineMarking
|
||||
|
||||
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler
|
||||
import com.intellij.codeInsight.daemon.LineMarkerInfo
|
||||
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo
|
||||
import com.intellij.navigation.GotoRelatedItem
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer
|
||||
import com.intellij.openapi.util.NotNullLazyValue
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.intellij.spring.gutter.SpringClassAnnotator
|
||||
import com.intellij.util.Function
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.asJava.toLightElements
|
||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||
import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation
|
||||
import javax.swing.Icon
|
||||
|
||||
class KotlinSpringClassAnnotator : SpringClassAnnotator() {
|
||||
override fun getElementToProcess(psiElement: PsiElement): PsiElement? {
|
||||
if (psiElement is KtLightIdentifier) return psiElement.parent
|
||||
psiElement.getParentOfTypeAndBranch<KtClass> { nameIdentifier }?.let { return it.toLightClass() }
|
||||
psiElement.getParentOfTypeAndBranch<KtNamedFunction> { nameIdentifier }?.let { function ->
|
||||
val containingClassOrObject = function.containingClassOrObject
|
||||
val classForLightMethod = if (containingClassOrObject is KtObjectDeclaration
|
||||
&& containingClassOrObject.isCompanion()
|
||||
&& function.resolveToDescriptor().hasJvmStaticAnnotation()) {
|
||||
containingClassOrObject.containingClassOrObject
|
||||
}
|
||||
else {
|
||||
containingClassOrObject
|
||||
}
|
||||
return classForLightMethod?.toLightClass()?.methods?.firstOrNull { (it as? KtLightMethod)?.kotlinOrigin == function }
|
||||
}
|
||||
psiElement.getParentOfTypeAndBranch<KtConstructor<*>> { getConstructorKeyword() ?: getValueParameterList() }?.let {
|
||||
return it.toLightMethods().firstOrNull()
|
||||
}
|
||||
psiElement.getParentOfTypeAndBranch<KtProperty> { nameIdentifier }?.let { return it }
|
||||
psiElement.getParentOfTypeAndBranch<KtParameter> { nameIdentifier }?.let { if (it.valOrVarKeyword != null) return it }
|
||||
psiElement.getParentOfTypeAndBranch<KtAnnotationEntry> {
|
||||
(typeReference?.typeElement as? KtUserType)?.referenceExpression?.getReferencedNameElement()
|
||||
}?.let { return it.toLightAnnotation() }
|
||||
return null
|
||||
}
|
||||
|
||||
private fun doCollectMarkers(psiElement: PsiElement, result: MutableCollection<in RelatedItemLineMarkerInfo<PsiElement>>) {
|
||||
if (psiElement is KtProperty || psiElement is KtParameter) {
|
||||
for (it in (psiElement as KtDeclaration).toLightElements()) {
|
||||
val nameIdentifier = (it as? PsiNameIdentifierOwner)?.nameIdentifier ?: continue
|
||||
super.collectNavigationMarkers(nameIdentifier, result)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Workaround for SpringClassAnnotator
|
||||
(getElementToProcess(psiElement) as? KtLightAnnotationForSourceEntry)?.let { return super.collectNavigationMarkers(it, result) }
|
||||
|
||||
super.collectNavigationMarkers(psiElement, result)
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Weak references to light elements may be reclaimed by GC after original file is modified causing line markers to misbehave
|
||||
// This workaround allows reuse of SpringClassAnnotator logic and avoids binding of line markers to light elements
|
||||
|
||||
private val toolTipProviderField by lazy { LineMarkerInfo::class.java.getDeclaredField("myTooltipProvider").apply { isAccessible = true } }
|
||||
private val iconField by lazy { LineMarkerInfo::class.java.getDeclaredField("myIcon").apply { isAccessible = true } }
|
||||
private val iconAlignmentField by lazy { LineMarkerInfo::class.java.getDeclaredField("myIconAlignment").apply { isAccessible = true } }
|
||||
private val targetsField by lazy { RelatedItemLineMarkerInfo::class.java.getDeclaredField("myTargets").apply { isAccessible = true } }
|
||||
|
||||
override fun collectNavigationMarkers(psiElement: PsiElement, result: MutableCollection<in RelatedItemLineMarkerInfo<PsiElement>>) {
|
||||
val newItems = SmartList<RelatedItemLineMarkerInfo<PsiElement>>()
|
||||
|
||||
doCollectMarkers(psiElement, newItems)
|
||||
|
||||
newItems.mapNotNullTo(result) { item ->
|
||||
val itemElement = item.element
|
||||
val elementToAnnotate = when (itemElement) {
|
||||
is KtLightIdentifier -> itemElement.origin
|
||||
is KtLightElement<*, *> -> itemElement.kotlinOrigin
|
||||
else -> return@mapNotNullTo item
|
||||
}
|
||||
if (elementToAnnotate == null) return@mapNotNullTo null
|
||||
if (alreadyMarked(result, elementToAnnotate, item.navigationHandler)) return@mapNotNullTo null
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
RelatedItemLineMarkerInfo<PsiElement>(
|
||||
elementToAnnotate,
|
||||
elementToAnnotate.textRange,
|
||||
iconField.get(item) as Icon?,
|
||||
item.updatePass,
|
||||
toolTipProviderField.get(item) as Function<PsiElement, String>,
|
||||
item.navigationHandler,
|
||||
iconAlignmentField.get(item) as GutterIconRenderer.Alignment,
|
||||
targetsField.get(item) as NotNullLazyValue<Collection<GotoRelatedItem>>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun alreadyMarked(result: MutableCollection<in RelatedItemLineMarkerInfo<PsiElement>>,
|
||||
elementToAnnotate: PsiElement,
|
||||
navigationHandler: GutterIconNavigationHandler<*>?) =
|
||||
result.any {
|
||||
when (it) {
|
||||
is RelatedItemLineMarkerInfo<*> -> {
|
||||
it.element == elementToAnnotate && it.navigationHandler == navigationHandler
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
-157
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* 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
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* 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.highlighting.SpringAutowireUtil
|
||||
import com.intellij.spring.model.jam.qualifiers.SpringJamQualifier
|
||||
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()
|
||||
}
|
||||
}
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.spring.inspections.KotlinSpringFacetCodeInspection
|
||||
// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
// "Add qualifier" "true"
|
||||
// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension
|
||||
// CONFIGURE_SPRING_FILE_SET
|
||||
// WITH_RUNTIME
|
||||
// DISABLE-ERRORS
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.beans.factory.annotation.Qualifier
|
||||
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
open class InvalidAutowiredByTypeQualifiers
|
||||
|
||||
abstract class BaseBarBean
|
||||
@Component
|
||||
open class BarBean1 : BaseBarBean()
|
||||
@Component
|
||||
open class BarBean2 : BaseBarBean()
|
||||
|
||||
@Component
|
||||
open class MultipleAutowiredCandidates() {
|
||||
@Autowired
|
||||
lateinit var <caret>bean: BaseBarBean
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
// "Add qualifier" "true"
|
||||
// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension
|
||||
// CONFIGURE_SPRING_FILE_SET
|
||||
// WITH_RUNTIME
|
||||
// DISABLE-ERRORS
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.beans.factory.annotation.Qualifier
|
||||
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
open class InvalidAutowiredByTypeQualifiers
|
||||
|
||||
abstract class BaseBarBean
|
||||
@Component
|
||||
open class BarBean1 : BaseBarBean()
|
||||
@Component
|
||||
open class BarBean2 : BaseBarBean()
|
||||
|
||||
@Component
|
||||
open class MultipleAutowiredCandidates() {
|
||||
@Qualifier("barBean1")
|
||||
@Autowired
|
||||
lateinit var bean: BaseBarBean
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
// ACTION_CLASS: org.jetbrains.kotlin.idea.spring.generate.GenerateKotlinAutowiredDependencyAction
|
||||
// CHOOSE_BEAN: barBean, application
|
||||
package a
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.beans.factory.annotation.Qualifier
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
|
||||
@Component
|
||||
open class FooBean {
|
||||
@Qualifier("application")
|
||||
@Autowired
|
||||
lateinit var application: Application
|
||||
@Autowired
|
||||
lateinit var barBean<caret>: BarBean
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
open class BarBean
|
||||
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
open class Application
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
// 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
@@ -1,11 +0,0 @@
|
||||
// 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
@@ -1,11 +0,0 @@
|
||||
// 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
@@ -1,11 +0,0 @@
|
||||
// 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
@@ -1,12 +0,0 @@
|
||||
// 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 {
|
||||
|
||||
}
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* 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.tests
|
||||
|
||||
import com.intellij.facet.impl.FacetUtil
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.spring.facet.SpringFacet
|
||||
import com.intellij.spring.facet.SpringFileSet
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
||||
import org.jetbrains.kotlin.idea.test.TestFixtureExtension
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import java.io.File
|
||||
|
||||
@Suppress("unused")
|
||||
class SpringTestFixtureExtension() : TestFixtureExtension {
|
||||
private var module: Module? = null
|
||||
|
||||
override fun setUp(module: Module) {
|
||||
this.module = module
|
||||
|
||||
val springClasspath = System.getProperty("spring.classpath")
|
||||
?: throw RuntimeException("Unable to get a valid classpath from 'spring.classpath' property, please set it accordingly");
|
||||
|
||||
ConfigLibraryUtil.addLibrary(module, "spring", null, springClasspath.split(File.pathSeparator).toTypedArray())
|
||||
|
||||
FacetUtil.addFacet(module, SpringFacet.getSpringFacetType())
|
||||
}
|
||||
|
||||
fun configureFileSet(fixture: CodeInsightTestFixture, configFiles: Collection<String>): SpringFileSet {
|
||||
return configureFileSet(fixture, "default", module!!, configFiles)
|
||||
}
|
||||
|
||||
fun configureFileSet(fixture: CodeInsightTestFixture, id: String, module: Module, configFiles: Collection<String>): SpringFileSet {
|
||||
return module.getSpringFacetWithAssertion().addFileSet(id, id).apply {
|
||||
configFiles.forEach { addFile(fixture.copyFileToProject(it)) }
|
||||
}
|
||||
}
|
||||
|
||||
fun Module.getSpringFacetWithAssertion() = SpringFacet.getInstance(this) ?: error("No Spring facet in ${this}")
|
||||
|
||||
override fun tearDown() {
|
||||
try {
|
||||
// clear existing SpringFacet configuration before running next test
|
||||
module?.let { module ->
|
||||
SpringFacet.getInstance(module)?.let { facet ->
|
||||
facet.removeFileSets()
|
||||
FacetUtil.deleteFacet(facet)
|
||||
}
|
||||
ConfigLibraryUtil.removeLibrary(module, "spring")
|
||||
}
|
||||
}
|
||||
finally {
|
||||
module = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun SpringTestFixtureExtension.loadConfigByMainFilePath(testPath: String, fixture: JavaCodeInsightTestFixture) {
|
||||
val mainFileName = PathUtil.getFileName(testPath)
|
||||
val baseName = FileUtil.getNameWithoutExtension(mainFileName)
|
||||
val configFileName = if (baseName.endsWith("Xml")) "$baseName-config.xml" else mainFileName
|
||||
configureFileSet(fixture, listOf(PathUtil.toSystemIndependentName("${PathUtil.getParentPath(testPath)}/$configFileName")))
|
||||
}
|
||||
|
||||
fun configureSpringFileSetByDirective(module: Module, directives: String, psiFiles: Collection<PsiFile>) {
|
||||
if (!InTextDirectivesUtils.isDirectiveDefined(directives, "// CONFIGURE_SPRING_FILE_SET")) return
|
||||
val fileSet = SpringFacet.getInstance(module)!!.addFileSet("default", "default")!!
|
||||
psiFiles.forEach { fileSet.addFile(it.virtualFile) }
|
||||
}
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* 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.tests.gutter
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import com.intellij.codeInsight.daemon.LineMarkerProviders
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import icons.SpringApiIcons
|
||||
import junit.framework.Assert
|
||||
import junit.framework.AssertionFailedError
|
||||
import org.jetbrains.kotlin.compatibility.projectDisposableEx
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
||||
import org.jetbrains.kotlin.idea.spring.lineMarking.KotlinSpringClassAnnotator
|
||||
import org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension
|
||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import org.jetbrains.kotlin.idea.test.TestFixtureExtension
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractSpringClassAnnotatorTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
override fun getProjectDescriptor() = LightCodeInsightFixtureTestCase.JAVA_LATEST
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
TestFixtureExtension.loadFixture<SpringTestFixtureExtension>(myModule)
|
||||
Assert.assertTrue("Kotlin-ultimate service was not found, make sure that <!-- ULTIMATE-PLUGIN-PLACEHOLDER --> " +
|
||||
"is replaced in `plugin.xml` with data from `ultimate-plugin.xml`",
|
||||
LineMarkerProviders.INSTANCE.allForLanguage(KotlinLanguage.INSTANCE).any { it is KotlinSpringClassAnnotator }
|
||||
)
|
||||
}
|
||||
|
||||
protected fun doTest(path: String) {
|
||||
val configFilePath = "${KotlinTestUtils.getHomeDirectory()}/$path"
|
||||
val configFile = File(configFilePath)
|
||||
val testRoot = configFile.parentFile
|
||||
|
||||
val config = JsonParser().parse(FileUtil.loadFile(configFile, true)) as JsonObject
|
||||
|
||||
PluginTestCaseBase.addJdk(myFixture.projectDisposableEx, PluginTestCaseBase::mockJdk)
|
||||
|
||||
val withRuntime = config["withRuntime"]?.asBoolean ?: false
|
||||
if (withRuntime) {
|
||||
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(myModule, PluginTestCaseBase.mockJdk())
|
||||
}
|
||||
|
||||
try {
|
||||
val springConfigFiles = (config["springConfig"] as JsonArray).map { it.asString }
|
||||
myFixture.testDataPath = testRoot.absolutePath
|
||||
for (file in testRoot.listFiles()) {
|
||||
val name = file.name
|
||||
if (file.isDirectory) myFixture.copyDirectoryToProject(name, name) else myFixture.configureByFile(name)
|
||||
}
|
||||
TestFixtureExtension.getFixture<SpringTestFixtureExtension>()!!.configureFileSet(myFixture, springConfigFiles)
|
||||
|
||||
val fileName = config.getString("file")
|
||||
val iconName = config.getString("icon")
|
||||
val icon = SpringApiIcons::class.java.getField(iconName)[null]
|
||||
|
||||
val gutterMark = myFixture.findGutter(fileName)!!.let {
|
||||
if (it.icon == icon) it
|
||||
else myFixture.findGuttersAtCaret().let { gutters ->
|
||||
gutters.firstOrNull() { it.icon == icon }
|
||||
?: throw AssertionFailedError("no $icon in gutters: ${gutters.map { it.icon }}")
|
||||
}
|
||||
}
|
||||
|
||||
val tooltip = config.getString("tooltip")
|
||||
Assert.assertEquals(tooltip, gutterMark.tooltipText)
|
||||
|
||||
val naming = config.getString("naming")
|
||||
val targets = (config["targets"] as JsonArray).map { it.asString }
|
||||
when (naming) {
|
||||
"bean" -> checkBeanGutterTargets(gutterMark, targets)
|
||||
"property" -> checkBeanPropertyTargets(gutterMark, targets)
|
||||
"generic" -> checkPsiElementGutterTargets(gutterMark, targets)
|
||||
else -> error("Unexpected naming: $naming")
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (withRuntime) {
|
||||
ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(myModule, PluginTestCaseBase.mockJdk())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
TestFixtureExtension.unloadFixture<SpringTestFixtureExtension>()
|
||||
super.tearDown()
|
||||
}
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package org.jetbrains.kotlin.idea.spring.tests.inspections
|
||||
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.idea.codeInsight.AbstractInspectionTest
|
||||
import org.jetbrains.kotlin.idea.spring.tests.configureSpringFileSetByDirective
|
||||
|
||||
abstract class AbstractSpringInspectionTest : AbstractInspectionTest() {
|
||||
|
||||
override val forceUsePackageFolder: Boolean = true
|
||||
|
||||
override fun configExtra(psiFiles: List<PsiFile>, options: String) {
|
||||
configureSpringFileSetByDirective(myFixture.module, options, psiFiles)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user