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-12175](https://youtrack.jetbrains.com/issue/KT-12175) Don't enforce empty line after one-line constructor
|
||||
- Added "Decompile" button to Kotlin bytecode toolwindow
|
||||
- [KT-12278](https://youtrack.jetbrains.com/issue/KT-12278) Implement Spring @Autowired inspection
|
||||
|
||||
Issues fixed:
|
||||
|
||||
@@ -53,6 +54,9 @@ Issues 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-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
|
||||
|
||||
|
||||
@@ -72,9 +72,10 @@ class KtLightAnnotation(
|
||||
}
|
||||
|
||||
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 getNavigationElement() = originalExpression
|
||||
override fun getTextRange() = originalExpression?.textRange ?: TextRange.EMPTY_RANGE
|
||||
}
|
||||
|
||||
inner class LightArrayInitializerValue(private val delegate: PsiArrayInitializerMemberValue) : PsiArrayInitializerMemberValue by delegate {
|
||||
|
||||
@@ -52,6 +52,8 @@ sealed class KtLightFieldImpl(
|
||||
|
||||
override fun getContainingClass() = containingClass
|
||||
|
||||
override fun getContainingFile() = containingClass.containingFile
|
||||
|
||||
override fun getType() = clsDelegate.type
|
||||
|
||||
override fun getTypeElement() = clsDelegate.typeElement
|
||||
|
||||
@@ -17,19 +17,32 @@
|
||||
package org.jetbrains.kotlin.asJava
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiCompiledElement
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.intellij.psi.impl.light.LightIdentifier
|
||||
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(
|
||||
private val lightOwner: PsiNameIdentifierOwner,
|
||||
private val ktDeclaration: KtNamedDeclaration?
|
||||
) : LightIdentifier(lightOwner.manager, ktDeclaration?.name ?: "") {
|
||||
) : LightIdentifier(lightOwner.manager, ktDeclaration?.name ?: ""), PsiCompiledElement {
|
||||
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 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
|
||||
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?
|
||||
get() = unwrapped?.getNonStrictParentOfType<PsiNamedElement>()
|
||||
|
||||
+11
-9
@@ -63,16 +63,18 @@ private fun toSeverity(highlightDisplayLevel: HighlightDisplayLevel): Severity
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun Array<ProblemDescriptor>.registerWithElementsUnwrapped(holder: ProblemsHolder, isOnTheFly: Boolean) {
|
||||
forEach {
|
||||
fun Array<ProblemDescriptor>.registerWithElementsUnwrapped(
|
||||
holder: ProblemsHolder,
|
||||
isOnTheFly: Boolean,
|
||||
quickFixSubstitutor: ((LocalQuickFix, PsiElement) -> LocalQuickFix?)? = null) {
|
||||
forEach { problem ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val descriptor = holder.manager.createProblemDescriptor(
|
||||
it.psiElement.unwrapped ?: it.psiElement,
|
||||
it.descriptionTemplate,
|
||||
isOnTheFly,
|
||||
it.fixes as? Array<LocalQuickFix> ?: LocalQuickFix.EMPTY_ARRAY,
|
||||
it.highlightType
|
||||
)
|
||||
val originalFixes = problem.fixes as? Array<LocalQuickFix> ?: LocalQuickFix.EMPTY_ARRAY
|
||||
val newElement = problem.psiElement.unwrapped ?: return@forEach
|
||||
val newFixes = quickFixSubstitutor?.let { subst ->
|
||||
originalFixes.mapNotNull { subst(it, newElement) }.toTypedArray()
|
||||
} ?: originalFixes
|
||||
val descriptor = holder.manager.createProblemDescriptor(newElement, problem.descriptionTemplate, isOnTheFly, newFixes, problem.highlightType)
|
||||
holder.registerProblem(descriptor)
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import com.intellij.codeInspection.ex.InspectionManagerEx
|
||||
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.testFramework.IdeaTestUtil
|
||||
import com.intellij.testFramework.InspectionTestUtil
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
@@ -51,6 +52,10 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase()
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
protected open fun configExtra(psiFiles: List<PsiFile>, options: String) {
|
||||
|
||||
}
|
||||
|
||||
protected fun doTest(path: String) {
|
||||
val optionsFile = File(path)
|
||||
val options = FileUtil.loadFile(optionsFile, true)
|
||||
@@ -110,6 +115,8 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase()
|
||||
|
||||
fixtureClasses.forEach { TestFixtureExtension.loadFixture(it, myFixture.module) }
|
||||
|
||||
configExtra(psiFiles, options)
|
||||
|
||||
val scope = AnalysisScope(project, psiFiles.map { it.virtualFile!! })
|
||||
scope.invalidate()
|
||||
|
||||
|
||||
@@ -124,6 +124,10 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
|
||||
}), LocalInspectionTool.class);
|
||||
}
|
||||
|
||||
protected void configExtra(String options) {
|
||||
|
||||
}
|
||||
|
||||
private void doKotlinQuickFixTest(final String testName, final QuickFixTestCase quickFixTestCase) {
|
||||
String relativePath = notNull(quickFixTestCase.getBasePath(), "") + "/" + StringsKt.decapitalize(testName);
|
||||
final String testFullPath = quickFixTestCase.getTestDataPath().replace(File.separatorChar, '/') + relativePath;
|
||||
@@ -150,6 +154,8 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
|
||||
|
||||
checkForUnexpectedActions();
|
||||
|
||||
configExtra(fileText);
|
||||
|
||||
applyAction(contents, quickFixTestCase, testName, testFullPath);
|
||||
|
||||
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"
|
||||
level="WARNING"
|
||||
implementationClass="org.jetbrains.kotlin.idea.spring.inspections.SpringKotlinAutowiredMembersInspection"/>
|
||||
<localInspection language="kotlin"
|
||||
displayName="Autowiring for Bean Class (Kotlin)"
|
||||
groupBundle="resources.messages.SpringBundle"
|
||||
groupKey="inspection.group.code"
|
||||
groupPath="Spring,Spring Core"
|
||||
enabledByDefault="true"
|
||||
level="ERROR"
|
||||
implementationClass="org.jetbrains.kotlin.idea.spring.inspections.SpringKotlinAutowiringInspection"/>
|
||||
</extensions>
|
||||
|
||||
<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.jam.qualifiers.SpringJamQualifier
|
||||
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.toLightElements
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.search.allScope
|
||||
import org.jetbrains.kotlin.idea.spring.springModel
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.plainContent
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import java.util.*
|
||||
|
||||
// Based on com.intellij.spring.references.SpringQualifierReference
|
||||
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? {
|
||||
val annotationEntry = element.getStrictParentOfType<KtAnnotationEntry>() ?: return null
|
||||
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.openapi.module.Module
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.spring.facet.SpringFacet
|
||||
import com.intellij.spring.facet.SpringFileSet
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||
@@ -26,6 +27,7 @@ import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
||||
import org.jetbrains.kotlin.idea.test.TestFixtureExtension
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.tests.ULTIMATE_TEST_ROOT
|
||||
import java.util.*
|
||||
|
||||
@@ -89,4 +91,10 @@ fun SpringTestFixtureExtension.loadConfigByMainFilePath(testPath: String, fixtur
|
||||
val baseName = FileUtil.getNameWithoutExtension(mainFileName)
|
||||
val configFileName = if (baseName.endsWith("Xml")) "$baseName-config.xml" else mainFileName
|
||||
configureFileSet(fixture, listOf(PathUtil.toSystemIndependentName("${PathUtil.getParentPath(testPath)}/$configFileName")))
|
||||
}
|
||||
|
||||
fun configureSpringFileSetByDirective(module: Module, directives: String, psiFiles: Collection<PsiFile>) {
|
||||
if (!InTextDirectivesUtils.isDirectiveDefined(directives, "// CONFIGURE_SPRING_FILE_SET")) return
|
||||
val fileSet = SpringFacet.getInstance(module)!!.addFileSet("default", "default")!!
|
||||
psiFiles.forEach { fileSet.addFile(it.virtualFile) }
|
||||
}
|
||||
+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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.codeInsight;
|
||||
package org.jetbrains.kotlin.idea.spring.tests.inspections;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
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 */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("ultimate/testData/inspections")
|
||||
@TestMetadata("ultimate/testData/inspections/spring")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class UltimateInspectionTestGenerated extends AbstractInspectionTest {
|
||||
public void testAllFilesPresentInInspections() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("ultimate/testData/inspections"), Pattern.compile("^(inspections\\.test)$"));
|
||||
public class SpringInspectionTestGenerated extends AbstractSpringInspectionTest {
|
||||
public void testAllFilesPresentInSpring() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("ultimate/testData/inspections/spring"), Pattern.compile("^(inspections\\.test)$"));
|
||||
}
|
||||
|
||||
@TestMetadata("spring/autowiredMembersInInvalidClass/inspectionData/inspections.test")
|
||||
public void testSpring_autowiredMembersInInvalidClass_inspectionData_Inspections_test() throws Exception {
|
||||
@TestMetadata("autowiredMembersInInvalidClass/inspectionData/inspections.test")
|
||||
public void testAutowiredMembersInInvalidClass_inspectionData_Inspections_test() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/inspections/spring/autowiredMembersInInvalidClass/inspectionData/inspections.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("spring/finalSpringAnnotatedDeclaration/inspectionData/inspections.test")
|
||||
public void testSpring_finalSpringAnnotatedDeclaration_inspectionData_Inspections_test() throws Exception {
|
||||
@TestMetadata("autowiring/inspectionData/inspections.test")
|
||||
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");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("spring/unconfiguredFacet/inspectionData/inspections.test")
|
||||
public void testSpring_unconfiguredFacet_inspectionData_Inspections_test() throws Exception {
|
||||
@TestMetadata("unconfiguredFacet/inspectionData/inspections.test")
|
||||
public void testUnconfiguredFacet_inspectionData_Inspections_test() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("ultimate/testData/inspections/spring/unconfiguredFacet/inspectionData/inspections.test");
|
||||
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
|
||||
|
||||
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.generate.AbstractGenerateSpringDependencyActionTest
|
||||
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.AbstractSpringReferenceCompletionTest
|
||||
import org.jetbrains.kotlin.idea.spring.tests.references.AbstractSpringReferenceNavigationTest
|
||||
@@ -31,12 +31,12 @@ fun main(args: Array<String>) {
|
||||
System.setProperty("java.awt.headless", "true")
|
||||
|
||||
testGroup("ultimate/tests", "ultimate/testData") {
|
||||
testClass<AbstractInspectionTest>("UltimateInspectionTestGenerated") {
|
||||
model("inspections", pattern = "^(inspections\\.test)$", singleClass = true)
|
||||
testClass<AbstractSpringInspectionTest> {
|
||||
model("inspections/spring", pattern = "^(inspections\\.test)$", singleClass = true)
|
||||
}
|
||||
|
||||
testClass<AbstractQuickFixTest>("UltimateQuickFixTestGenerated") {
|
||||
model("quickFixes", pattern = "^([\\w\\-_]+)\\.kt$", filenameStartsLowerCase = true)
|
||||
testClass<AbstractSpringQuickFixTest> {
|
||||
model("quickFixes/spring", pattern = "^([\\w\\-_]+)\\.kt$", filenameStartsLowerCase = true)
|
||||
}
|
||||
|
||||
testClass<AbstractSpringClassAnnotatorTest>() {
|
||||
|
||||
Reference in New Issue
Block a user