Spring Support: Implement Spring @Autowired inspection
#KT-12278 Fixed #KT-12147 Fixed #KT-12366 Fixed #KT-12122 Fixed
This commit is contained in:
@@ -26,6 +26,7 @@ New features:
|
|||||||
- [KT-12092](https://youtrack.jetbrains.com/issue/KT-12092) Implement bean references in @Qualifier annotations
|
- [KT-12092](https://youtrack.jetbrains.com/issue/KT-12092) Implement bean references in @Qualifier annotations
|
||||||
- [KT-12175](https://youtrack.jetbrains.com/issue/KT-12175) Don't enforce empty line after one-line constructor
|
- [KT-12175](https://youtrack.jetbrains.com/issue/KT-12175) Don't enforce empty line after one-line constructor
|
||||||
- Added "Decompile" button to Kotlin bytecode toolwindow
|
- Added "Decompile" button to Kotlin bytecode toolwindow
|
||||||
|
- [KT-12278](https://youtrack.jetbrains.com/issue/KT-12278) Implement Spring @Autowired inspection
|
||||||
|
|
||||||
Issues fixed:
|
Issues fixed:
|
||||||
|
|
||||||
@@ -53,6 +54,9 @@ Issues fixed:
|
|||||||
- [KT-12067](https://youtrack.jetbrains.com/issue/KT-12067) Deadlock in Kotlin debugger is fixed
|
- [KT-12067](https://youtrack.jetbrains.com/issue/KT-12067) Deadlock in Kotlin debugger is fixed
|
||||||
- [KT-12070](https://youtrack.jetbrains.com/issue/KT-12070) Add empty line in error message of Maven and Gradle configuration
|
- [KT-12070](https://youtrack.jetbrains.com/issue/KT-12070) Add empty line in error message of Maven and Gradle configuration
|
||||||
- [KT-12091](https://youtrack.jetbrains.com/issue/KT-12091) Fixed unstable behavior of Spring line markers
|
- [KT-12091](https://youtrack.jetbrains.com/issue/KT-12091) Fixed unstable behavior of Spring line markers
|
||||||
|
- [KT-12147](https://youtrack.jetbrains.com/issue/KT-12147) Fixed exception on analyzing object declaration with @Component annotation
|
||||||
|
- [KT-12366](https://youtrack.jetbrains.com/issue/KT-12366) Fixed exception on analyzing class declaration upon annotation typing
|
||||||
|
- [KT-12122](https://youtrack.jetbrains.com/issue/KT-12122) Fixed line marker popup on functions with @Qualifier-annotated parameters
|
||||||
|
|
||||||
#### Debugger
|
#### Debugger
|
||||||
|
|
||||||
|
|||||||
@@ -72,9 +72,10 @@ class KtLightAnnotation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getReference() = references.singleOrNull()
|
override fun getReference() = references.singleOrNull()
|
||||||
override fun getReferences() = ReferenceProvidersRegistry.getReferencesFromProviders(delegate, PsiReferenceService.Hints.NO_HINTS)
|
override fun getReferences() = originalExpression?.references ?: PsiReference.EMPTY_ARRAY
|
||||||
override fun getLanguage() = KotlinLanguage.INSTANCE
|
override fun getLanguage() = KotlinLanguage.INSTANCE
|
||||||
override fun getNavigationElement() = originalExpression
|
override fun getNavigationElement() = originalExpression
|
||||||
|
override fun getTextRange() = originalExpression?.textRange ?: TextRange.EMPTY_RANGE
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class LightArrayInitializerValue(private val delegate: PsiArrayInitializerMemberValue) : PsiArrayInitializerMemberValue by delegate {
|
inner class LightArrayInitializerValue(private val delegate: PsiArrayInitializerMemberValue) : PsiArrayInitializerMemberValue by delegate {
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ sealed class KtLightFieldImpl(
|
|||||||
|
|
||||||
override fun getContainingClass() = containingClass
|
override fun getContainingClass() = containingClass
|
||||||
|
|
||||||
|
override fun getContainingFile() = containingClass.containingFile
|
||||||
|
|
||||||
override fun getType() = clsDelegate.type
|
override fun getType() = clsDelegate.type
|
||||||
|
|
||||||
override fun getTypeElement() = clsDelegate.typeElement
|
override fun getTypeElement() = clsDelegate.typeElement
|
||||||
|
|||||||
@@ -17,19 +17,32 @@
|
|||||||
package org.jetbrains.kotlin.asJava
|
package org.jetbrains.kotlin.asJava
|
||||||
|
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.psi.PsiCompiledElement
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiNameIdentifierOwner
|
import com.intellij.psi.PsiNameIdentifierOwner
|
||||||
import com.intellij.psi.impl.light.LightIdentifier
|
import com.intellij.psi.impl.light.LightIdentifier
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
|
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
|
||||||
|
import org.jetbrains.kotlin.psi.KtSecondaryConstructor
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||||
|
|
||||||
class KtLightIdentifier(
|
class KtLightIdentifier(
|
||||||
private val lightOwner: PsiNameIdentifierOwner,
|
private val lightOwner: PsiNameIdentifierOwner,
|
||||||
private val ktDeclaration: KtNamedDeclaration?
|
private val ktDeclaration: KtNamedDeclaration?
|
||||||
) : LightIdentifier(lightOwner.manager, ktDeclaration?.name ?: "") {
|
) : LightIdentifier(lightOwner.manager, ktDeclaration?.name ?: ""), PsiCompiledElement {
|
||||||
val origin: PsiElement?
|
val origin: PsiElement?
|
||||||
get() = ktDeclaration?.nameIdentifier
|
get() = when (ktDeclaration) {
|
||||||
|
is KtSecondaryConstructor -> ktDeclaration.getConstructorKeyword()
|
||||||
|
is KtPrimaryConstructor -> ktDeclaration.getConstructorKeyword()
|
||||||
|
?: ktDeclaration.valueParameterList
|
||||||
|
?: ktDeclaration.containingClassOrObject?.nameIdentifier
|
||||||
|
else -> ktDeclaration?.nameIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMirror() = ((lightOwner as? KtLightElement<*, *>)?.clsDelegate as? PsiNameIdentifierOwner)?.nameIdentifier
|
||||||
|
|
||||||
override fun isPhysical() = true
|
override fun isPhysical() = true
|
||||||
override fun getParent() = lightOwner
|
override fun getParent() = lightOwner
|
||||||
override fun getTextRange() = ktDeclaration?.nameIdentifier?.textRange ?: TextRange.EMPTY_RANGE
|
override fun getContainingFile() = lightOwner.containingFile
|
||||||
|
override fun getTextRange() = origin?.textRange ?: TextRange.EMPTY_RANGE
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,12 @@ fun KtTypeParameter.toPsiTypeParameters(): List<PsiTypeParameter> {
|
|||||||
|
|
||||||
// Returns original declaration if given PsiElement is a Kotlin light element, and element itself otherwise
|
// Returns original declaration if given PsiElement is a Kotlin light element, and element itself otherwise
|
||||||
val PsiElement.unwrapped: PsiElement?
|
val PsiElement.unwrapped: PsiElement?
|
||||||
get() = if (this is KtLightElement<*, *>) kotlinOrigin else this
|
get() = when {
|
||||||
|
this is KtLightElement<*, *> -> kotlinOrigin
|
||||||
|
this is KtLightIdentifier -> origin
|
||||||
|
this is KtLightAnnotation.LightExpressionValue -> originalExpression
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
|
||||||
val PsiElement.namedUnwrappedElement: PsiNamedElement?
|
val PsiElement.namedUnwrappedElement: PsiNamedElement?
|
||||||
get() = unwrapped?.getNonStrictParentOfType<PsiNamedElement>()
|
get() = unwrapped?.getNonStrictParentOfType<PsiNamedElement>()
|
||||||
|
|||||||
+11
-9
@@ -63,16 +63,18 @@ private fun toSeverity(highlightDisplayLevel: HighlightDisplayLevel): Severity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun Array<ProblemDescriptor>.registerWithElementsUnwrapped(holder: ProblemsHolder, isOnTheFly: Boolean) {
|
fun Array<ProblemDescriptor>.registerWithElementsUnwrapped(
|
||||||
forEach {
|
holder: ProblemsHolder,
|
||||||
|
isOnTheFly: Boolean,
|
||||||
|
quickFixSubstitutor: ((LocalQuickFix, PsiElement) -> LocalQuickFix?)? = null) {
|
||||||
|
forEach { problem ->
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val descriptor = holder.manager.createProblemDescriptor(
|
val originalFixes = problem.fixes as? Array<LocalQuickFix> ?: LocalQuickFix.EMPTY_ARRAY
|
||||||
it.psiElement.unwrapped ?: it.psiElement,
|
val newElement = problem.psiElement.unwrapped ?: return@forEach
|
||||||
it.descriptionTemplate,
|
val newFixes = quickFixSubstitutor?.let { subst ->
|
||||||
isOnTheFly,
|
originalFixes.mapNotNull { subst(it, newElement) }.toTypedArray()
|
||||||
it.fixes as? Array<LocalQuickFix> ?: LocalQuickFix.EMPTY_ARRAY,
|
} ?: originalFixes
|
||||||
it.highlightType
|
val descriptor = holder.manager.createProblemDescriptor(newElement, problem.descriptionTemplate, isOnTheFly, newFixes, problem.highlightType)
|
||||||
)
|
|
||||||
holder.registerProblem(descriptor)
|
holder.registerProblem(descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,6 +24,7 @@ import com.intellij.codeInspection.ex.InspectionManagerEx
|
|||||||
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper
|
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper
|
||||||
import com.intellij.openapi.command.CommandProcessor
|
import com.intellij.openapi.command.CommandProcessor
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.testFramework.IdeaTestUtil
|
import com.intellij.testFramework.IdeaTestUtil
|
||||||
import com.intellij.testFramework.InspectionTestUtil
|
import com.intellij.testFramework.InspectionTestUtil
|
||||||
import com.intellij.testFramework.LightProjectDescriptor
|
import com.intellij.testFramework.LightProjectDescriptor
|
||||||
@@ -51,6 +52,10 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase()
|
|||||||
super.tearDown()
|
super.tearDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun configExtra(psiFiles: List<PsiFile>, options: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected fun doTest(path: String) {
|
protected fun doTest(path: String) {
|
||||||
val optionsFile = File(path)
|
val optionsFile = File(path)
|
||||||
val options = FileUtil.loadFile(optionsFile, true)
|
val options = FileUtil.loadFile(optionsFile, true)
|
||||||
@@ -110,6 +115,8 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase()
|
|||||||
|
|
||||||
fixtureClasses.forEach { TestFixtureExtension.loadFixture(it, myFixture.module) }
|
fixtureClasses.forEach { TestFixtureExtension.loadFixture(it, myFixture.module) }
|
||||||
|
|
||||||
|
configExtra(psiFiles, options)
|
||||||
|
|
||||||
val scope = AnalysisScope(project, psiFiles.map { it.virtualFile!! })
|
val scope = AnalysisScope(project, psiFiles.map { it.virtualFile!! })
|
||||||
scope.invalidate()
|
scope.invalidate()
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,10 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
|
|||||||
}), LocalInspectionTool.class);
|
}), LocalInspectionTool.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void configExtra(String options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void doKotlinQuickFixTest(final String testName, final QuickFixTestCase quickFixTestCase) {
|
private void doKotlinQuickFixTest(final String testName, final QuickFixTestCase quickFixTestCase) {
|
||||||
String relativePath = notNull(quickFixTestCase.getBasePath(), "") + "/" + StringsKt.decapitalize(testName);
|
String relativePath = notNull(quickFixTestCase.getBasePath(), "") + "/" + StringsKt.decapitalize(testName);
|
||||||
final String testFullPath = quickFixTestCase.getTestDataPath().replace(File.separatorChar, '/') + relativePath;
|
final String testFullPath = quickFixTestCase.getTestDataPath().replace(File.separatorChar, '/') + relativePath;
|
||||||
@@ -150,6 +154,8 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
|
|||||||
|
|
||||||
checkForUnexpectedActions();
|
checkForUnexpectedActions();
|
||||||
|
|
||||||
|
configExtra(fileText);
|
||||||
|
|
||||||
applyAction(contents, quickFixTestCase, testName, testFullPath);
|
applyAction(contents, quickFixTestCase, testName, testFullPath);
|
||||||
|
|
||||||
assertEmpty(expectedErrorMessage);
|
assertEmpty(expectedErrorMessage);
|
||||||
|
|||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
<component name="ProjectDictionaryState">
|
||||||
|
<dictionary name="Alexey.Sedunov">
|
||||||
|
<words>
|
||||||
|
<w>autowired</w>
|
||||||
|
<w>autowiring</w>
|
||||||
|
<w>springframework</w>
|
||||||
|
</words>
|
||||||
|
</dictionary>
|
||||||
|
</component>
|
||||||
@@ -30,6 +30,14 @@
|
|||||||
enabledByDefault="true"
|
enabledByDefault="true"
|
||||||
level="WARNING"
|
level="WARNING"
|
||||||
implementationClass="org.jetbrains.kotlin.idea.spring.inspections.SpringKotlinAutowiredMembersInspection"/>
|
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"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<actions>
|
<actions>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
Checks autowiring problems in a bean class.
|
||||||
+177
@@ -0,0 +1,177 @@
|
|||||||
|
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.*
|
||||||
|
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) {
|
||||||
|
for (lightElement in property.toLightElements()) {
|
||||||
|
when (lightElement) {
|
||||||
|
is KtLightMethod -> lightElement.processLightMethod()
|
||||||
|
is KtLightField -> lightElement.processLightField()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
|
||||||
|
classOrObject.toLightClass()?.processLightClass()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
-1
@@ -23,21 +23,44 @@ import com.intellij.spring.model.converters.SpringConverterUtil
|
|||||||
import com.intellij.spring.model.highlighting.SpringAutowireUtil
|
import com.intellij.spring.model.highlighting.SpringAutowireUtil
|
||||||
import com.intellij.spring.model.jam.qualifiers.SpringJamQualifier
|
import com.intellij.spring.model.jam.qualifiers.SpringJamQualifier
|
||||||
import com.intellij.spring.model.utils.SpringModelSearchers
|
import com.intellij.spring.model.utils.SpringModelSearchers
|
||||||
|
import com.intellij.spring.references.SpringQualifierReference
|
||||||
|
import com.intellij.util.IncorrectOperationException
|
||||||
|
import org.jetbrains.kotlin.asJava.KtLightElement
|
||||||
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
||||||
import org.jetbrains.kotlin.asJava.toLightElements
|
import org.jetbrains.kotlin.asJava.toLightElements
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
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.idea.spring.springModel
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
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.psi.psiUtil.startOffset
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
// Based on com.intellij.spring.references.SpringQualifierReference
|
// Based on com.intellij.spring.references.SpringQualifierReference
|
||||||
class KtSpringQualifierReference(element: KtStringTemplateExpression) : PsiReferenceBase.Poly<KtStringTemplateExpression>(element, false) {
|
// 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 getName() = null
|
||||||
|
override fun setName(newName: String) = throw IncorrectOperationException()
|
||||||
|
|
||||||
|
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? {
|
private fun getAnnotationFqName(): String? {
|
||||||
val annotationEntry = element.getStrictParentOfType<KtAnnotationEntry>() ?: return null
|
val annotationEntry = element.getStrictParentOfType<KtAnnotationEntry>() ?: return null
|
||||||
val context = annotationEntry.analyze(BodyResolveMode.PARTIAL)
|
val context = annotationEntry.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan
|
||||||
|
open class AmbiguousConstructors
|
||||||
|
|
||||||
|
// Not reported if there is only one constructor
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class SingleConstructor1(n: Int)
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class SingleConstructor2 {
|
||||||
|
constructor(n: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not reported if no-arg constructor is present
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class NoArgConstructor1() {
|
||||||
|
constructor(n: Int): this()
|
||||||
|
constructor(s: String): this()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class NoArgConstructor2 {
|
||||||
|
constructor()
|
||||||
|
constructor(n: Int)
|
||||||
|
constructor(s: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not reported if @Autowired constructor is present
|
||||||
|
@Component
|
||||||
|
open class AutowiredConstructor1 {
|
||||||
|
@Autowired constructor(n: Int)
|
||||||
|
constructor(s: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class AutowiredConstructor2 @Autowired constructor(n: Int) {
|
||||||
|
constructor(s: String): this(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reported
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class AmbigiousConstructor1 {
|
||||||
|
constructor(n: Int)
|
||||||
|
constructor(s: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class AmbigiousConstructor2(n: Int) {
|
||||||
|
constructor(s: String): this(0)
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<problems>
|
||||||
|
<problem>
|
||||||
|
<file>ambiguousConstructors.kt</file>
|
||||||
|
<line>52</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/ambiguousConstructors.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Class doesn't contain matching constructor for autowiring</description>
|
||||||
|
</problem>
|
||||||
|
<problem>
|
||||||
|
<file>ambiguousConstructors.kt</file>
|
||||||
|
<line>58</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/ambiguousConstructors.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Class doesn't contain matching constructor for autowiring</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>multipleAutowiredConstructors.kt</file>
|
||||||
|
<line>30</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/multipleAutowiredConstructors.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Only one constructor can have @Autowired annotation</description>
|
||||||
|
</problem>
|
||||||
|
<problem>
|
||||||
|
<file>multipleAutowiredConstructors.kt</file>
|
||||||
|
<line>31</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/multipleAutowiredConstructors.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Only one constructor can have @Autowired annotation</description>
|
||||||
|
</problem>
|
||||||
|
<problem>
|
||||||
|
<file>multipleAutowiredConstructors.kt</file>
|
||||||
|
<line>35</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/multipleAutowiredConstructors.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Only one constructor can have @Autowired annotation</description>
|
||||||
|
</problem>
|
||||||
|
<problem>
|
||||||
|
<file>multipleAutowiredConstructors.kt</file>
|
||||||
|
<line>36</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/multipleAutowiredConstructors.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Only one constructor can have @Autowired annotation</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>parameterlessFunction.kt</file>
|
||||||
|
<line>15</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/parameterlessFunction.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Autowired method without parameters</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>invalidAutowiredResource.kt</file>
|
||||||
|
<line>24</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/mismatchedType.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Could not autowire. Bean should be of 'invalidAutowiredResource.BarBean' type</description>
|
||||||
|
</problem>
|
||||||
|
<problem>
|
||||||
|
<file>invalidAutowiredResource.kt</file>
|
||||||
|
<line>31</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/invalidAutowiredResource.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Cannot resolve bean 'fooBeannn'</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>invalidAutowiredQualifier.kt</file>
|
||||||
|
<line>23</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/invalidAutowiredQualifier.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Could not autowire. Qualified bean must be of 'BarBean' type.</description>
|
||||||
|
</problem>
|
||||||
|
<problem>
|
||||||
|
<file>invalidAutowiredQualifier.kt</file>
|
||||||
|
<line>30</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/invalidAutowiredQualifier.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Cannot find bean with qualifier 'fooBeannn'</description>
|
||||||
|
</problem>
|
||||||
|
<problem>
|
||||||
|
<file>invalidAutowiredQualifier.kt</file>
|
||||||
|
<line>37</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/invalidAutowiredQualifier.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Cannot find bean qualified with @Qualifier</description>
|
||||||
|
</problem>
|
||||||
|
|
||||||
|
<problem>
|
||||||
|
<file>invalidAutowiredByType.kt</file>
|
||||||
|
<line>23</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/invalidAutowiredByType.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description>Could not autowire. No beans of 'String' type found.</description>
|
||||||
|
</problem>
|
||||||
|
<problem>
|
||||||
|
<file>invalidAutowiredByType.kt</file>
|
||||||
|
<line>29</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/invalidAutowiredByType.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Autowiring for Bean Class (Kotlin)</problem_class>
|
||||||
|
<description><html><table><tr><td>Could not autowire. There is more than one bean of 'AbstractBarBean' type.</td></tr><tr><td><table><tr><td valign='top'>Beans:</td><td>abstractBarBean&nbsp;&nbsp; (invalidAutowiredByType.kt)<br>barBean1&nbsp;&nbsp; (invalidAutowiredByType.kt)<br>barBean2&nbsp;&nbsp; (invalidAutowiredByType.kt)<br></td></tr></table></td></tr></table></html></description>
|
||||||
|
</problem>
|
||||||
|
</problems>
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.spring.inspections.SpringKotlinAutowiringInspection
|
||||||
|
// FIXTURE_CLASS: org.jetbrains.kotlin.idea.spring.tests.SpringTestFixtureExtension
|
||||||
|
// CONFIGURE_SPRING_FILE_SET
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
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 AbstractBarBean
|
||||||
|
@Component
|
||||||
|
open class BarBean1 : AbstractBarBean()
|
||||||
|
@Component
|
||||||
|
open class BarBean2 : AbstractBarBean()
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class NoAutowiredCandidates() {
|
||||||
|
@Autowired
|
||||||
|
lateinit var bean: String
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class MultipleAutowiredCandidates() {
|
||||||
|
@Autowired
|
||||||
|
lateinit var bean: AbstractBarBean
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
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 MismatchedTypes
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class FooBean
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class BarBean
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class MismatchedType() {
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("fooBean")
|
||||||
|
lateinit var bean1: BarBean
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class UnresolvedBeanRef() {
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("fooBeannn")
|
||||||
|
lateinit var bean1: FooBean
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class NamelessQualifier() {
|
||||||
|
@Autowired
|
||||||
|
@Qualifier
|
||||||
|
lateinit var bean1: FooBean
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// FULL_JDK
|
||||||
|
|
||||||
|
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 javax.annotation.Resource
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan
|
||||||
|
open class MismatchedTypes
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class FooBean
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class BarBean
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class MismatchedType() {
|
||||||
|
@Autowired
|
||||||
|
@Resource(name = "fooBean")
|
||||||
|
lateinit var bean1: BarBean
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class UnresolvedBeanRef() {
|
||||||
|
@Autowired
|
||||||
|
@Resource(name = "fooBeannn")
|
||||||
|
lateinit var bean1: FooBean
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan
|
||||||
|
open class MultipleAutowiredConstructors
|
||||||
|
|
||||||
|
// Not reported if required == false
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class NonRequiredAutowired1 {
|
||||||
|
@Autowired(required = false) constructor(n: Int)
|
||||||
|
@Autowired constructor(s: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class NonRequiredAutowired2 @Autowired(required = false) constructor(n: Int) {
|
||||||
|
@Autowired constructor(s: String): this(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reported
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class BothAutowired1 {
|
||||||
|
@Autowired constructor(n: Int)
|
||||||
|
@Autowired constructor(s: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class BothAutowired2 @Autowired constructor(n: Int) {
|
||||||
|
@Autowired constructor(s: String): this(0)
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan
|
||||||
|
open class ParameterlessFunctions
|
||||||
|
|
||||||
|
@Component
|
||||||
|
open class ParameterlessFunction {
|
||||||
|
@Autowired fun foo() = 1
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
org.jetbrains.kotlin.idea.spring.inspections.SpringKotlinAutowiringInspection
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// "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
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
// "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
|
||||||
|
}
|
||||||
@@ -1,97 +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.quickfix;
|
|
||||||
|
|
||||||
import com.intellij.testFramework.TestDataPath;
|
|
||||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
|
||||||
import org.jetbrains.kotlin.test.TestMetadata;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
@TestMetadata("ultimate/testData/quickFixes")
|
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
|
||||||
public class UltimateQuickFixTestGenerated extends AbstractQuickFixTest {
|
|
||||||
public void testAllFilesPresentInQuickFixes() throws Exception {
|
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("ultimate/testData/quickFixes"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("ultimate/testData/quickFixes/spring")
|
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
|
||||||
public static class Spring extends AbstractQuickFixTest {
|
|
||||||
public void testAllFilesPresentInSpring() throws Exception {
|
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("ultimate/testData/quickFixes/spring"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration")
|
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
|
||||||
public static class FinalSpringAnnotatedDeclaration extends AbstractQuickFixTest {
|
|
||||||
public void testAllFilesPresentInFinalSpringAnnotatedDeclaration() throws Exception {
|
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("classWithComponentRuntime.kt")
|
|
||||||
public void testClassWithComponentRuntime() throws Exception {
|
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/classWithComponentRuntime.kt");
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("classWithConfigurationRuntime.kt")
|
|
||||||
public void testClassWithConfigurationRuntime() throws Exception {
|
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/classWithConfigurationRuntime.kt");
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("classWithCustomConfigurationRuntime.kt")
|
|
||||||
public void testClassWithCustomConfigurationRuntime() throws Exception {
|
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/classWithCustomConfigurationRuntime.kt");
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("funWithBeanFinalClassRuntime.kt")
|
|
||||||
public void testFunWithBeanFinalClassRuntime() throws Exception {
|
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanFinalClassRuntime.kt");
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("funWithBeanOpenClassRuntime.kt")
|
|
||||||
public void testFunWithBeanOpenClassRuntime() throws Exception {
|
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanOpenClassRuntime.kt");
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("funWithCustomBeanFinalClassRuntime.kt")
|
|
||||||
public void testFunWithCustomBeanFinalClassRuntime() throws Exception {
|
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanFinalClassRuntime.kt");
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("funWithCustomBeanOpenClassRuntime.kt")
|
|
||||||
public void testFunWithCustomBeanOpenClassRuntime() throws Exception {
|
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanOpenClassRuntime.kt");
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.spring.tests
|
|||||||
import com.intellij.facet.impl.FacetUtil
|
import com.intellij.facet.impl.FacetUtil
|
||||||
import com.intellij.openapi.module.Module
|
import com.intellij.openapi.module.Module
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.spring.facet.SpringFacet
|
import com.intellij.spring.facet.SpringFacet
|
||||||
import com.intellij.spring.facet.SpringFileSet
|
import com.intellij.spring.facet.SpringFileSet
|
||||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||||
@@ -26,6 +27,7 @@ import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
|
|||||||
import com.intellij.util.PathUtil
|
import com.intellij.util.PathUtil
|
||||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
||||||
import org.jetbrains.kotlin.idea.test.TestFixtureExtension
|
import org.jetbrains.kotlin.idea.test.TestFixtureExtension
|
||||||
|
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||||
import org.jetbrains.kotlin.tests.ULTIMATE_TEST_ROOT
|
import org.jetbrains.kotlin.tests.ULTIMATE_TEST_ROOT
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -89,4 +91,10 @@ fun SpringTestFixtureExtension.loadConfigByMainFilePath(testPath: String, fixtur
|
|||||||
val baseName = FileUtil.getNameWithoutExtension(mainFileName)
|
val baseName = FileUtil.getNameWithoutExtension(mainFileName)
|
||||||
val configFileName = if (baseName.endsWith("Xml")) "$baseName-config.xml" else mainFileName
|
val configFileName = if (baseName.endsWith("Xml")) "$baseName-config.xml" else mainFileName
|
||||||
configureFileSet(fixture, listOf(PathUtil.toSystemIndependentName("${PathUtil.getParentPath(testPath)}/$configFileName")))
|
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) }
|
||||||
}
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
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 fun configExtra(psiFiles: List<PsiFile>, options: String) {
|
||||||
|
configureSpringFileSetByDirective(myFixture.module, options, psiFiles)
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
-11
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.codeInsight;
|
package org.jetbrains.kotlin.idea.spring.tests.inspections;
|
||||||
|
|
||||||
import com.intellij.testFramework.TestDataPath;
|
import com.intellij.testFramework.TestDataPath;
|
||||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||||
@@ -27,28 +27,34 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
@TestMetadata("ultimate/testData/inspections")
|
@TestMetadata("ultimate/testData/inspections/spring")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public class UltimateInspectionTestGenerated extends AbstractInspectionTest {
|
public class SpringInspectionTestGenerated extends AbstractSpringInspectionTest {
|
||||||
public void testAllFilesPresentInInspections() throws Exception {
|
public void testAllFilesPresentInSpring() throws Exception {
|
||||||
KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("ultimate/testData/inspections"), Pattern.compile("^(inspections\\.test)$"));
|
KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("ultimate/testData/inspections/spring"), Pattern.compile("^(inspections\\.test)$"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("spring/autowiredMembersInInvalidClass/inspectionData/inspections.test")
|
@TestMetadata("autowiredMembersInInvalidClass/inspectionData/inspections.test")
|
||||||
public void testSpring_autowiredMembersInInvalidClass_inspectionData_Inspections_test() throws Exception {
|
public void testAutowiredMembersInInvalidClass_inspectionData_Inspections_test() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/inspections/spring/autowiredMembersInInvalidClass/inspectionData/inspections.test");
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/inspections/spring/autowiredMembersInInvalidClass/inspectionData/inspections.test");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("spring/finalSpringAnnotatedDeclaration/inspectionData/inspections.test")
|
@TestMetadata("autowiring/inspectionData/inspections.test")
|
||||||
public void testSpring_finalSpringAnnotatedDeclaration_inspectionData_Inspections_test() throws Exception {
|
public void testAutowiring_inspectionData_Inspections_test() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/inspections/spring/autowiring/inspectionData/inspections.test");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("finalSpringAnnotatedDeclaration/inspectionData/inspections.test")
|
||||||
|
public void testFinalSpringAnnotatedDeclaration_inspectionData_Inspections_test() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/inspections/spring/finalSpringAnnotatedDeclaration/inspectionData/inspections.test");
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/inspections/spring/finalSpringAnnotatedDeclaration/inspectionData/inspections.test");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("spring/unconfiguredFacet/inspectionData/inspections.test")
|
@TestMetadata("unconfiguredFacet/inspectionData/inspections.test")
|
||||||
public void testSpring_unconfiguredFacet_inspectionData_Inspections_test() throws Exception {
|
public void testUnconfiguredFacet_inspectionData_Inspections_test() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/inspections/spring/unconfiguredFacet/inspectionData/inspections.test");
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/inspections/spring/unconfiguredFacet/inspectionData/inspections.test");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package org.jetbrains.kotlin.idea.spring.tests.quickfixes
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixTest
|
||||||
|
import org.jetbrains.kotlin.idea.spring.tests.configureSpringFileSetByDirective
|
||||||
|
|
||||||
|
abstract class AbstractSpringQuickFixTest : AbstractQuickFixTest() {
|
||||||
|
override fun configExtra(options: String) {
|
||||||
|
configureSpringFileSetByDirective(getModule(), options, listOf(getFile()))
|
||||||
|
}
|
||||||
|
}
|
||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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.quickfixes;
|
||||||
|
|
||||||
|
import com.intellij.testFramework.TestDataPath;
|
||||||
|
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||||
|
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||||
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
@TestMetadata("ultimate/testData/quickFixes/spring")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public class SpringQuickFixTestGenerated extends AbstractSpringQuickFixTest {
|
||||||
|
public void testAllFilesPresentInSpring() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("ultimate/testData/quickFixes/spring"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ultimate/testData/quickFixes/spring/addQualifierAnnotation")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class AddQualifierAnnotation extends AbstractSpringQuickFixTest {
|
||||||
|
public void testAllFilesPresentInAddQualifierAnnotation() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("ultimate/testData/quickFixes/spring/addQualifierAnnotation"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ambiguousBean.kt")
|
||||||
|
public void testAmbiguousBean() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/addQualifierAnnotation/ambiguousBean.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class FinalSpringAnnotatedDeclaration extends AbstractSpringQuickFixTest {
|
||||||
|
public void testAllFilesPresentInFinalSpringAnnotatedDeclaration() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classWithComponentRuntime.kt")
|
||||||
|
public void testClassWithComponentRuntime() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/classWithComponentRuntime.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classWithConfigurationRuntime.kt")
|
||||||
|
public void testClassWithConfigurationRuntime() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/classWithConfigurationRuntime.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classWithCustomConfigurationRuntime.kt")
|
||||||
|
public void testClassWithCustomConfigurationRuntime() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/classWithCustomConfigurationRuntime.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("funWithBeanFinalClassRuntime.kt")
|
||||||
|
public void testFunWithBeanFinalClassRuntime() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanFinalClassRuntime.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("funWithBeanOpenClassRuntime.kt")
|
||||||
|
public void testFunWithBeanOpenClassRuntime() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/funWithBeanOpenClassRuntime.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("funWithCustomBeanFinalClassRuntime.kt")
|
||||||
|
public void testFunWithCustomBeanFinalClassRuntime() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanFinalClassRuntime.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("funWithCustomBeanOpenClassRuntime.kt")
|
||||||
|
public void testFunWithCustomBeanOpenClassRuntime() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/quickFixes/spring/finalSpringAnnotatedDeclaration/funWithCustomBeanOpenClassRuntime.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,11 +17,11 @@
|
|||||||
package org.jetbrains.kotlin.tests
|
package org.jetbrains.kotlin.tests
|
||||||
|
|
||||||
import org.jetbrains.kotlin.generators.tests.testGroup
|
import org.jetbrains.kotlin.generators.tests.testGroup
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.AbstractInspectionTest
|
|
||||||
import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixTest
|
|
||||||
import org.jetbrains.kotlin.idea.spring.tests.findUsages.AbstractSpringFindUsagesTest
|
import org.jetbrains.kotlin.idea.spring.tests.findUsages.AbstractSpringFindUsagesTest
|
||||||
import org.jetbrains.kotlin.idea.spring.tests.generate.AbstractGenerateSpringDependencyActionTest
|
import org.jetbrains.kotlin.idea.spring.tests.generate.AbstractGenerateSpringDependencyActionTest
|
||||||
import org.jetbrains.kotlin.idea.spring.tests.gutter.AbstractSpringClassAnnotatorTest
|
import org.jetbrains.kotlin.idea.spring.tests.gutter.AbstractSpringClassAnnotatorTest
|
||||||
|
import org.jetbrains.kotlin.idea.spring.tests.inspections.AbstractSpringInspectionTest
|
||||||
|
import org.jetbrains.kotlin.idea.spring.tests.quickfixes.AbstractSpringQuickFixTest
|
||||||
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceCompletionHandlerTest
|
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceCompletionHandlerTest
|
||||||
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceCompletionTest
|
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceCompletionTest
|
||||||
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceNavigationTest
|
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceNavigationTest
|
||||||
@@ -31,12 +31,12 @@ fun main(args: Array<String>) {
|
|||||||
System.setProperty("java.awt.headless", "true")
|
System.setProperty("java.awt.headless", "true")
|
||||||
|
|
||||||
testGroup("ultimate/tests", "ultimate/testData") {
|
testGroup("ultimate/tests", "ultimate/testData") {
|
||||||
testClass<AbstractInspectionTest>("UltimateInspectionTestGenerated") {
|
testClass<AbstractSpringInspectionTest> {
|
||||||
model("inspections", pattern = "^(inspections\\.test)$", singleClass = true)
|
model("inspections/spring", pattern = "^(inspections\\.test)$", singleClass = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
testClass<AbstractQuickFixTest>("UltimateQuickFixTestGenerated") {
|
testClass<AbstractSpringQuickFixTest> {
|
||||||
model("quickFixes", pattern = "^([\\w\\-_]+)\\.kt$", filenameStartsLowerCase = true)
|
model("quickFixes/spring", pattern = "^([\\w\\-_]+)\\.kt$", filenameStartsLowerCase = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
testClass<AbstractSpringClassAnnotatorTest>() {
|
testClass<AbstractSpringClassAnnotatorTest>() {
|
||||||
|
|||||||
Reference in New Issue
Block a user