KotlinLanguageInjector understands patterns-injections into Java annotations

This commit is contained in:
Nicolay Mitropolsky
2017-08-18 10:02:51 +03:00
committed by Nikolay Krasko
parent 743dc80b4d
commit 1435911437
2 changed files with 75 additions and 0 deletions
@@ -35,6 +35,7 @@ import org.intellij.plugins.intelliLang.inject.TemporaryPlacesRegistry
import org.intellij.plugins.intelliLang.inject.config.BaseInjection
import org.intellij.plugins.intelliLang.inject.java.JavaLanguageInjectionSupport
import org.intellij.plugins.intelliLang.util.AnnotationUtilEx
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.references.KtReference
@@ -44,7 +45,9 @@ import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.source.getPsi
import java.util.*
import kotlin.collections.ArrayList
@@ -153,6 +156,7 @@ class KotlinLanguageInjector(
private fun findInjectionInfo(place: KtElement, originalHost: Boolean = true): InjectionInfo? {
return injectWithExplicitCodeInstruction(place)
?: injectWithCall(place)
?: injectInAnnotationCall(place)
?: injectWithReceiver(place)
?: injectWithVariableUsage(place, originalHost)
?: injectWithAnnotationEntry(place)
@@ -262,6 +266,16 @@ class KotlinLanguageInjector(
return null
}
private fun injectInAnnotationCall(host: KtElement): InjectionInfo? {
val argument = host.parent as? KtValueArgument ?: return null
val annotationEntry = argument.parent.parent as? KtAnnotationEntry ?: return null
val callDescriptor = annotationEntry.getResolvedCall(annotationEntry.analyze())?.candidateDescriptor
val psiClass = (callDescriptor as? DeclarationDescriptorWithSource)?.source?.getPsi() as? PsiClass ?: return null
val argumentName = argument.getArgumentName()?.asName?.identifier ?: "value"
val method = psiClass.findMethodsByName(argumentName, false).singleOrNull() ?: return null
return findInjection(method, Configuration.getInstance().getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID))
}
private fun injectionForJavaMethod(argument: KtValueArgument, javaMethod: PsiMethod): InjectionInfo? {
val argumentIndex = (argument.parent as KtValueArgumentList).arguments.indexOf(argument)
val psiParameter = javaMethod.parameterList.parameters.getOrNull(argumentIndex) ?: return null
@@ -488,4 +488,65 @@ class KotlinInjectionTest : AbstractInjectionTest() {
Configuration.getInstance().replaceInjections(listOf(), listOf(customInjection), true)
}
}
fun testInjectionInJavaAnnotation() {
val customInjection = BaseInjection("java")
customInjection.injectedLanguageId = HTMLLanguage.INSTANCE.id
val elementPattern = customInjection.compiler.createElementPattern(
"""psiMethod().withName("value").withParameters().definedInClass("InHtml")""",
"SuppressWarnings temp rule")
customInjection.setInjectionPlaces(InjectionPlace(elementPattern, true))
try {
Configuration.getInstance().replaceInjections(listOf(customInjection), listOf(), true)
doInjectionPresentTest(
"""
@InHtml("<htm<caret>l></html>")
fun foo() {
}
""", """
@interface InHtml {
String value();
}
""".trimIndent(),
HTMLLanguage.INSTANCE.id,
unInjectShouldBePresent = false
)
}
finally {
Configuration.getInstance().replaceInjections(listOf(), listOf(customInjection), true)
}
}
fun testInjectionInJavaAnnotationWithNamedParam() {
val customInjection = BaseInjection("java")
customInjection.injectedLanguageId = HTMLLanguage.INSTANCE.id
val elementPattern = customInjection.compiler.createElementPattern(
"""psiMethod().withName("html").withParameters().definedInClass("InHtml")""",
"SuppressWarnings temp rule")
customInjection.setInjectionPlaces(InjectionPlace(elementPattern, true))
try {
Configuration.getInstance().replaceInjections(listOf(customInjection), listOf(), true)
doInjectionPresentTest(
"""
@InHtml(html = "<htm<caret>l></html>")
fun foo() {
}
""", """
@interface InHtml {
String html();
}
""".trimIndent(),
HTMLLanguage.INSTANCE.id,
unInjectShouldBePresent = false
)
}
finally {
Configuration.getInstance().replaceInjections(listOf(), listOf(customInjection), true)
}
}
}