Make parameter injection work for Java methods

This commit is contained in:
Nikolay Krasko
2016-04-22 21:15:14 +03:00
parent 3e35c60406
commit 64c46a33c4
10 changed files with 143 additions and 16 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ New features:
- [KT-2428](https://youtrack.jetbrains.com/issue/KT-11574) Support basic use-cases of language injection for expressions marked with @Language annotation
- [KT-11472](https://youtrack.jetbrains.com/issue/KT-11472) Add comment or @Language annotation after "Inject language or reference" intention automatically
- Apply injection for the literals in property initializer through property usages
- Enable injection in Kotlin by annotation function or method parameter with @Language annotation
- Enable injection from Java or Kotlin function declaration by annotating parameter with @Language annotation
- [KT-11807](https://youtrack.jetbrains.com/issue/KT-11807) Use function body template when generating overriding functions with default body
Issues fixed:
@@ -28,6 +28,7 @@ import org.intellij.plugins.intelliLang.Configuration
import org.intellij.plugins.intelliLang.inject.InjectorUtils
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.idea.util.findAnnotation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
@@ -136,7 +137,21 @@ class KotlinLanguageInjector : LanguageInjector {
val argumentIndex = (argument.parent as KtValueArgumentList).arguments.indexOf(argument)
val psiParameter = javaMethod.parameterList.parameters.getOrNull(argumentIndex) ?: return null
return findInjection(psiParameter, Configuration.getInstance().getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID))
val injectionInfo = findInjection(psiParameter, Configuration.getInstance().getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID))
if (injectionInfo != null) {
return injectionInfo
}
val annotations = AnnotationUtilEx.getAnnotationFrom(
psiParameter,
Configuration.getProjectInstance(psiParameter.project).advancedConfiguration.languageAnnotationPair,
true)
if (annotations.size > 0) {
return processAnnotationInjectionInner(annotations)
}
return null
}
private fun injectionForKotlinCall(argument: KtValueArgument, ktFunction: KtFunction): InjectionInfo? {
@@ -168,4 +183,12 @@ class KotlinLanguageInjector : LanguageInjector {
}
private class InjectionInfo(val languageId: String?, val prefix: String?, val suffix: String?)
private fun processAnnotationInjectionInner(annotations: Array<PsiAnnotation>): InjectionInfo? {
val id = AnnotationUtilEx.calcAnnotationValue(annotations, "value")
val prefix = AnnotationUtilEx.calcAnnotationValue(annotations, "prefix")
val suffix = AnnotationUtilEx.calcAnnotationValue(annotations, "suffix")
return InjectionInfo(id, prefix, suffix)
}
}
@@ -0,0 +1,6 @@
import org.intellij.lang.annotations.Language;
public class Test {
public Test(@Language("HTML") String str) {
}
}
@@ -0,0 +1,3 @@
fun bar() {
Test("<caret>some")
}
@@ -0,0 +1,5 @@
import org.intellij.lang.annotations.Language;
public class Test {
public static void foo(@Language("HTML") String str) {}
}
@@ -0,0 +1,3 @@
import some.Test
fun bar() { Test.foo("<caret>some") }
@@ -39,15 +39,19 @@ abstract class AbstractInjectionTest : KotlinLightCodeInsightFixtureTestCase() {
}
}
protected fun assertInjectionPresent(text: String, languageId: String? = null, unInjectShouldBePresent: Boolean = true) {
protected fun doInjectionPresentTest(text: String, languageId: String? = null, unInjectShouldBePresent: Boolean = true) {
myFixture.configureByText("${getTestName(true)}.kt", text.trimIndent())
assertInjectionPresent(languageId, unInjectShouldBePresent)
}
protected fun assertInjectionPresent(languageId: String?, unInjectShouldBePresent: Boolean) {
TestCase.assertFalse("Injection action is available. There's probably no injection at caret place",
InjectLanguageAction().isAvailable(project, myFixture.editor, myFixture.file))
if (languageId != null) {
val injectedFile = (editor as? EditorWindow)?.injectedFile
KotlinLightCodeInsightFixtureTestCaseBase.assertEquals("Wrong injection language", languageId, injectedFile?.language?.id)
assertEquals("Wrong injection language", languageId, injectedFile?.language?.id)
}
if (unInjectShouldBePresent) {
@@ -44,7 +44,7 @@ class KotlinInjectionTest : AbstractInjectionTest() {
TestCase.assertNull(myFixture.getReferenceAtCaretPosition())
}
fun testInjectionOnJavaPredefinedMethodWithAnnotation() = assertInjectionPresent(
fun testInjectionOnJavaPredefinedMethodWithAnnotation() = doInjectionPresentTest(
"""
val test1 = java.util.regex.Pattern.compile("<caret>pattern")
""",
@@ -63,7 +63,7 @@ class KotlinInjectionTest : AbstractInjectionTest() {
try {
Configuration.getInstance().replaceInjections(listOf(customInjection), listOf(), true)
assertInjectionPresent(
doInjectionPresentTest(
"""
val stringBuilder = StringBuilder().replace(0, 0, "<caret><html></html>")
""",
@@ -76,20 +76,20 @@ class KotlinInjectionTest : AbstractInjectionTest() {
}
}
fun testInjectionWithCommentOnProperty() = assertInjectionPresent(
fun testInjectionWithCommentOnProperty() = doInjectionPresentTest(
"""
//language=file-reference
val test = "<caret>simple"
""")
fun testInjectionWithUsageOnReceiverWithRuntime() = assertInjectionPresent(
fun testInjectionWithUsageOnReceiverWithRuntime() = doInjectionPresentTest(
"""
val test = "<caret>some"
fun foo() = test.toRegex()
""",
languageId = RegExpLanguage.INSTANCE.id, unInjectShouldBePresent = false)
fun testInjectionWithUsageInParameterWithRuntime() = assertInjectionPresent(
fun testInjectionWithUsageInParameterWithRuntime() = doInjectionPresentTest(
"""
val test = "<caret>some"
fun foo() = Regex(test)
@@ -103,7 +103,7 @@ class KotlinInjectionTest : AbstractInjectionTest() {
fun foo() = Regex(test)
""")
fun testInjectionWithMultipleCommentsOnFun() = assertInjectionPresent(
fun testInjectionWithMultipleCommentsOnFun() = doInjectionPresentTest(
"""
// Some comment
// Other comment
@@ -111,7 +111,7 @@ class KotlinInjectionTest : AbstractInjectionTest() {
fun test() = "<caret>simple"
""")
fun testInjectionWithAnnotationOnPropertyWithAnnotation() = assertInjectionPresent(
fun testInjectionWithAnnotationOnPropertyWithAnnotation() = doInjectionPresentTest(
"""
@org.intellij.lang.annotations.Language("file-reference")
val test = "<caret>simple"
@@ -300,7 +300,7 @@ class KotlinInjectionTest : AbstractInjectionTest() {
"""
)
fun testInjectionWithUsageInFunctionWithMarkedParameterWithAnnotation() = assertInjectionPresent(
fun testInjectionWithUsageInFunctionWithMarkedParameterWithAnnotation() = doInjectionPresentTest(
"""
import org.intellij.lang.annotations.Language
@@ -312,7 +312,7 @@ class KotlinInjectionTest : AbstractInjectionTest() {
""",
languageId = HTMLLanguage.INSTANCE.id, unInjectShouldBePresent = false)
fun testInjectionOfCustomParameterWithAnnotation() = assertInjectionPresent(
fun testInjectionOfCustomParameterWithAnnotation() = doInjectionPresentTest(
"""
import org.intellij.lang.annotations.Language
@@ -322,7 +322,7 @@ class KotlinInjectionTest : AbstractInjectionTest() {
""",
languageId = HTMLLanguage.INSTANCE.id, unInjectShouldBePresent = false)
fun testInjectionOfCustomParameterInConstructorWithAnnotation() = assertInjectionPresent(
fun testInjectionOfCustomParameterInConstructorWithAnnotation() = doInjectionPresentTest(
"""
import org.intellij.lang.annotations.Language
@@ -332,7 +332,7 @@ class KotlinInjectionTest : AbstractInjectionTest() {
""",
languageId = HTMLLanguage.INSTANCE.id, unInjectShouldBePresent = false)
fun testInjectionOfCustomParameterDefaultCallWithAnnotation() = assertInjectionPresent(
fun testInjectionOfCustomParameterDefaultCallWithAnnotation() = doInjectionPresentTest(
"""
import org.intellij.lang.annotations.Language
@@ -341,4 +341,42 @@ class KotlinInjectionTest : AbstractInjectionTest() {
fun other() { foo(s = "<caret>some") }
""",
languageId = HTMLLanguage.INSTANCE.id, unInjectShouldBePresent = false)
// fun testInjectionOfCustomParameterJavaWithAnnotation() = dotInjectionPresentTest(
// """
// import some.Test
//
// fun bar() { Test.foo("<caret>some") }
// """,
// javaCode =
// """
// package some;
//
// import org.intellij.lang.annotations.Language;
//
// public class Test {
// public static void foo(@Language("HTML") String str) {}
// }
// """,
// languageId = HTMLLanguage.INSTANCE.id, unInjectShouldBePresent = false
// )
//
// fun testInjectionOfCustomParameterInJavaConstructorWithAnnotation() = dotInjectionPresentTest(
// """
// import some.Test
//
// fun bar() { Test("<caret>some") }
// """,
// javaCode =
// """
// package some;
//
// import org.intellij.lang.annotations.Language;
//
// public class Test {
// public Test(@Language("HTML") String str) {}
// }
// """,
// languageId = HTMLLanguage.INSTANCE.id, unInjectShouldBePresent = false
// )
}
@@ -0,0 +1,45 @@
/*
* 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.psi
import com.intellij.lang.html.HTMLLanguage
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
class KotlinMultiFileInjectionTest : AbstractInjectionTest() {
public override fun setUp() {
super.setUp()
myFixture.testDataPath = PluginTestCaseBase.getTestDataPathBase() + "/injection"
}
fun testInjectionOfCustomParameterInJavaConstructorWithAnnotation() = doMultiFileInjectionPresentTest(HTMLLanguage.INSTANCE.id, false)
fun testInjectionOfCustomParameterJavaWithAnnotation() = doMultiFileInjectionPresentTest(HTMLLanguage.INSTANCE.id, false)
override fun getTestDataPath(): String? {
return "idea/testData/injection/"
}
private fun doMultiFileInjectionPresentTest(languageId: String? = null, unInjectShouldBePresent: Boolean = true) {
val testName = getTestName(false)
myFixture.configureByFile("$testName.java")
myFixture.configureByFile("$testName.kt")
assertInjectionPresent(languageId, unInjectShouldBePresent)
}
}
@@ -63,7 +63,7 @@ class KotlinStdlibInjectionTest : AbstractInjectionTest() {
)
private fun assertInjectionPresent(text: String, languageId: String) {
assertInjectionPresent(text, languageId, false)
doInjectionPresentTest(text, languageId = languageId, unInjectShouldBePresent = false)
}
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE