Annotations: support injections in string arrays (KT-35222)
This commit is contained in:
@@ -257,11 +257,11 @@ class KotlinLanguageInjector(
|
|||||||
}.firstOrNull()
|
}.firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun injectWithCall(host: KtElement): InjectionInfo? {
|
private tailrec fun injectWithCall(host: KtElement): InjectionInfo? {
|
||||||
val ktHost: KtElement = host
|
val argument = getArgument(host) ?: return null
|
||||||
val argument = ktHost.parent as? KtValueArgument ?: return null
|
val callExpression = PsiTreeUtil.getParentOfType(argument, KtCallElement::class.java) ?: return null
|
||||||
|
|
||||||
val callExpression = PsiTreeUtil.getParentOfType(ktHost, KtCallElement::class.java) ?: return null
|
if (getCallableShortName(callExpression) == "arrayOf") return injectWithCall(callExpression)
|
||||||
val callee = getNameReference(callExpression.calleeExpression) ?: return null
|
val callee = getNameReference(callExpression.calleeExpression) ?: return null
|
||||||
|
|
||||||
if (isAnalyzeOff()) return null
|
if (isAnalyzeOff()) return null
|
||||||
@@ -292,10 +292,21 @@ class KotlinLanguageInjector(
|
|||||||
return callee as? KtNameReferenceExpression
|
return callee as? KtNameReferenceExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun injectInAnnotationCall(host: KtElement): InjectionInfo? {
|
private fun getArgument(host: KtElement): KtValueArgument? = when (val parent = host.parent) {
|
||||||
val argument = host.parent as? KtValueArgument ?: return null
|
is KtValueArgument -> parent
|
||||||
|
is KtCollectionLiteralExpression, is KtCallElement -> parent.parent as? KtValueArgument
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
private tailrec fun injectInAnnotationCall(host: KtElement): InjectionInfo? {
|
||||||
|
val argument = getArgument(host) ?: return null
|
||||||
val annotationEntry = argument.parent.parent as? KtCallElement ?: return null
|
val annotationEntry = argument.parent.parent as? KtCallElement ?: return null
|
||||||
if (!fastCheckInjectionsExists(annotationEntry)) return null
|
|
||||||
|
val callableShortName = getCallableShortName(annotationEntry) ?: return null
|
||||||
|
if (callableShortName == "arrayOf") return injectInAnnotationCall(annotationEntry)
|
||||||
|
|
||||||
|
if (!fastCheckInjectionsExists(callableShortName)) return null
|
||||||
|
|
||||||
val calleeExpression = annotationEntry.calleeExpression ?: return null
|
val calleeExpression = annotationEntry.calleeExpression ?: return null
|
||||||
val callee = getNameReference(calleeExpression)?.mainReference?.let { reference ->
|
val callee = getNameReference(calleeExpression)?.mainReference?.let { reference ->
|
||||||
allowResolveInDispatchThread { reference.resolve() }
|
allowResolveInDispatchThread { reference.resolve() }
|
||||||
@@ -400,10 +411,11 @@ class KotlinLanguageInjector(
|
|||||||
|
|
||||||
private val injectableTargetClassShortNames = CachedValuesManager.getManager(project).createCachedValue(::createCachedValue, false)
|
private val injectableTargetClassShortNames = CachedValuesManager.getManager(project).createCachedValue(::createCachedValue, false)
|
||||||
|
|
||||||
private fun fastCheckInjectionsExists(annotationEntry: KtCallElement): Boolean {
|
private fun fastCheckInjectionsExists(annotationShortName: String) = annotationShortName in injectableTargetClassShortNames.value
|
||||||
val referencedName = getNameReference(annotationEntry.calleeExpression)?.getReferencedName() ?: return false
|
|
||||||
val annotationShortName = annotationEntry.containingKtFile.aliasImportMap()[referencedName].singleOrNull() ?: referencedName
|
private fun getCallableShortName(annotationEntry: KtCallElement): String? {
|
||||||
return annotationShortName in injectableTargetClassShortNames.value
|
val referencedName = getNameReference(annotationEntry.calleeExpression)?.getReferencedName() ?: return null
|
||||||
|
return annotationEntry.containingKtFile.aliasImportMap()[referencedName].singleOrNull() ?: referencedName
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun retrieveJavaPlaceTargetClassesFQNs(place: InjectionPlace): Collection<String> {
|
private fun retrieveJavaPlaceTargetClassesFQNs(place: InjectionPlace): Collection<String> {
|
||||||
|
|||||||
@@ -508,14 +508,44 @@ class KotlinInjectionTest : AbstractInjectionTest() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testKotlinAnnotationsPatternNamedArrayLiteral() {
|
||||||
|
doAnnotationInjectionTest(
|
||||||
|
patternLanguage = "kotlin",
|
||||||
|
injectedLanguage = RegExpLanguage.INSTANCE.id,
|
||||||
|
pattern = """kotlinParameter().ofFunction(0, kotlinFunction().withName("Matches").definedInClass("Matches"))""",
|
||||||
|
kotlinCode = """
|
||||||
|
annotation class Matches(val pattern: Array<String>)
|
||||||
|
|
||||||
|
@Matches(pattern = ["[A-Z]<caret>[a-z]+"])
|
||||||
|
val name = "John"
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testKotlinAnnotationsPatternNamedArray() {
|
||||||
|
doAnnotationInjectionTest(
|
||||||
|
patternLanguage = "kotlin",
|
||||||
|
injectedLanguage = RegExpLanguage.INSTANCE.id,
|
||||||
|
pattern = """kotlinParameter().ofFunction(0, kotlinFunction().withName("Matches").definedInClass("Matches"))""",
|
||||||
|
kotlinCode = """
|
||||||
|
annotation class Matches(val pattern: Array<String>)
|
||||||
|
|
||||||
|
@Matches(pattern = arrayOf("[A-Z]<caret>[a-z]+"))
|
||||||
|
val name = "John"
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun testInjectionInJavaAnnotation() {
|
fun testInjectionInJavaAnnotation() {
|
||||||
|
|
||||||
myFixture.addClass("""
|
myFixture.addClass(
|
||||||
|
"""
|
||||||
@interface InHtml {
|
@interface InHtml {
|
||||||
String value();
|
String value();
|
||||||
}
|
}
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
doAnnotationInjectionTest(
|
doAnnotationInjectionTest(
|
||||||
injectedLanguage = HTMLLanguage.INSTANCE.id,
|
injectedLanguage = HTMLLanguage.INSTANCE.id,
|
||||||
@@ -550,6 +580,46 @@ class KotlinInjectionTest : AbstractInjectionTest() {
|
|||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testInjectionInJavaAnnotationWithNamedParamArray() {
|
||||||
|
myFixture.addClass("""
|
||||||
|
package myinjection;
|
||||||
|
|
||||||
|
@interface InHtml {
|
||||||
|
String[] htmls();
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
doAnnotationInjectionTest(
|
||||||
|
injectedLanguage = HTMLLanguage.INSTANCE.id,
|
||||||
|
pattern = """psiMethod().withName("htmls").withParameters().definedInClass("myinjection.InHtml")""",
|
||||||
|
kotlinCode = """
|
||||||
|
import myinjection.InHtml
|
||||||
|
|
||||||
|
@InHtml(htmls = arrayOf("<br/>", "<htm<caret>l></html>"))
|
||||||
|
fun foo() {
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testInjectionInJavaAnnotationWithNamedParamLiterals() {
|
||||||
|
myFixture.addClass("""
|
||||||
|
package myinjection;
|
||||||
|
|
||||||
|
@interface InHtml {
|
||||||
|
String[] htmls();
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
doAnnotationInjectionTest(
|
||||||
|
injectedLanguage = HTMLLanguage.INSTANCE.id,
|
||||||
|
pattern = """psiMethod().withName("htmls").withParameters().definedInClass("myinjection.InHtml")""",
|
||||||
|
kotlinCode = """
|
||||||
|
import myinjection.InHtml
|
||||||
|
|
||||||
|
@InHtml(htmls = ["<br/>", "<htm<caret>l></html>"])
|
||||||
|
fun foo() {
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
fun testInjectionInJavaNestedAnnotation() {
|
fun testInjectionInJavaNestedAnnotation() {
|
||||||
myFixture.addClass(
|
myFixture.addClass(
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user