Spring Support: Implement Spring @Autowired inspection

#KT-12278 Fixed
 #KT-12147 Fixed
 #KT-12366 Fixed
 #KT-12122 Fixed
This commit is contained in:
Alexey Sedunov
2016-05-17 18:19:46 +03:00
parent 36f3d30250
commit 85d07e5f6d
31 changed files with 820 additions and 129 deletions
+4
View File
@@ -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>()
@@ -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
View File
@@ -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.
@@ -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()
}
}
}
@@ -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>&lt;html&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;Could not autowire. There is more than one bean of 'AbstractBarBean' type.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;table&gt;&lt;tr&gt;&lt;td valign='top'&gt;Beans:&lt;/td&gt;&lt;td&gt;abstractBarBean&amp;nbsp;&amp;nbsp; (invalidAutowiredByType.kt)&lt;br&gt;barBean1&amp;nbsp;&amp;nbsp; (invalidAutowiredByType.kt)&lt;br&gt;barBean2&amp;nbsp;&amp;nbsp; (invalidAutowiredByType.kt)&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/html&gt;</description>
</problem>
</problems>
@@ -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
}
@@ -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
}
@@ -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) }
} }
@@ -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)
}
}
@@ -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);
} }
@@ -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()))
}
}
@@ -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>() {