Get annotation for injection from reference descriptor (KT-15548)
#KT-15548 Fixed
This commit is contained in:
+11
-2
@@ -22,6 +22,7 @@ import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.test.MockLibraryUtil;
|
||||
import org.jetbrains.kotlin.utils.PathUtil;
|
||||
@@ -36,22 +37,30 @@ public class JdkAndMockLibraryProjectDescriptor extends KotlinLightProjectDescri
|
||||
private final boolean withRuntime;
|
||||
private final boolean isJsLibrary;
|
||||
private final boolean allowKotlinPackage;
|
||||
private final String[] classpath;
|
||||
|
||||
public JdkAndMockLibraryProjectDescriptor(String sourcesPath, boolean withSources) {
|
||||
this(sourcesPath, withSources, false, false, false);
|
||||
}
|
||||
|
||||
public JdkAndMockLibraryProjectDescriptor(String sourcesPath, boolean withSources, boolean withRuntime, boolean isJsLibrary, boolean allowKotlinPackage) {
|
||||
public JdkAndMockLibraryProjectDescriptor(
|
||||
String sourcesPath, boolean withSources, boolean withRuntime, boolean isJsLibrary, boolean allowKotlinPackage) {
|
||||
this(sourcesPath, withSources, withRuntime, isJsLibrary, allowKotlinPackage, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
}
|
||||
|
||||
public JdkAndMockLibraryProjectDescriptor(
|
||||
String sourcesPath, boolean withSources, boolean withRuntime, boolean isJsLibrary, boolean allowKotlinPackage, String[] classpath) {
|
||||
this.sourcesPath = sourcesPath;
|
||||
this.withSources = withSources;
|
||||
this.withRuntime = withRuntime;
|
||||
this.isJsLibrary = isJsLibrary;
|
||||
this.allowKotlinPackage = allowKotlinPackage;
|
||||
this.classpath = classpath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model) {
|
||||
File libraryJar = MockLibraryUtil.compileLibraryToJar(sourcesPath, LIBRARY_NAME, withSources, isJsLibrary, allowKotlinPackage);
|
||||
File libraryJar = MockLibraryUtil.compileLibraryToJar(sourcesPath, LIBRARY_NAME, withSources, isJsLibrary, allowKotlinPackage, classpath);
|
||||
String jarUrl = getJarUrl(libraryJar);
|
||||
|
||||
Library.ModifiableModel libraryModel = model.getModuleLibraryTable().getModifiableModel().createLibrary(LIBRARY_NAME).getModifiableModel();
|
||||
|
||||
@@ -29,10 +29,14 @@ 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.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.references.KtReference
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.idea.util.findAnnotation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import java.util.*
|
||||
|
||||
class KotlinLanguageInjector : LanguageInjector {
|
||||
@@ -126,7 +130,7 @@ class KotlinLanguageInjector : LanguageInjector {
|
||||
}
|
||||
}
|
||||
else if (resolvedTo is KtFunction) {
|
||||
val injectionForJavaMethod = injectionForKotlinCall(argument, resolvedTo)
|
||||
val injectionForJavaMethod = injectionForKotlinCall(argument, resolvedTo, reference)
|
||||
if (injectionForJavaMethod != null) {
|
||||
return injectionForJavaMethod
|
||||
}
|
||||
@@ -150,14 +154,14 @@ class KotlinLanguageInjector : LanguageInjector {
|
||||
Configuration.getProjectInstance(psiParameter.project).advancedConfiguration.languageAnnotationPair,
|
||||
true)
|
||||
|
||||
if (annotations.size > 0) {
|
||||
if (annotations.isNotEmpty()) {
|
||||
return processAnnotationInjectionInner(annotations)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun injectionForKotlinCall(argument: KtValueArgument, ktFunction: KtFunction): InjectionInfo? {
|
||||
private fun injectionForKotlinCall(argument: KtValueArgument, ktFunction: KtFunction, reference: PsiReference): InjectionInfo? {
|
||||
val argumentIndex = (argument.parent as KtValueArgumentList).arguments.indexOf(argument)
|
||||
val ktParameter = ktFunction.valueParameters.getOrNull(argumentIndex) ?: return null
|
||||
|
||||
@@ -166,8 +170,16 @@ class KotlinLanguageInjector : LanguageInjector {
|
||||
return patternInjection
|
||||
}
|
||||
|
||||
val injectAnnotation = ktParameter.findAnnotation(FqName(AnnotationUtil.LANGUAGE)) ?: return null
|
||||
val languageId = extractLanguageFromInjectAnnotation(injectAnnotation) ?: return null
|
||||
// Found psi element after resolve can be obtained from compiled declaration but annotations parameters are lost there.
|
||||
// Search for original descriptor from reference.
|
||||
val ktReference = reference as? KtReference ?: return null
|
||||
val bindingContext = ktReference.element.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS)
|
||||
val functionDescriptor = ktReference.resolveToDescriptors(bindingContext).singleOrNull() as? FunctionDescriptor ?: return null
|
||||
|
||||
val parameterDescriptor = functionDescriptor.valueParameters.getOrNull(argumentIndex) ?: return null
|
||||
val injectAnnotation = parameterDescriptor.annotations.findAnnotation(FqName(AnnotationUtil.LANGUAGE)) ?: return null
|
||||
|
||||
val languageId = injectAnnotation.argumentValue("value") as? String ?: return null
|
||||
return InjectionInfo(languageId, null, null)
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package injection
|
||||
|
||||
import org.intellij.lang.annotations.Language
|
||||
|
||||
fun Int.html(@org.intellij.lang.annotations.Language("HTML") html: String) {}
|
||||
|
||||
fun Int.regexp(@Language("RegExp") html: String) {}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
PsiJetFileStubImpl[package=]
|
||||
PACKAGE_DIRECTIVE
|
||||
IMPORT_LIST
|
||||
CLASS[fqName=Test, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=Test, superNames=[]]
|
||||
MODIFIER_LIST[annotation]
|
||||
PRIMARY_CONSTRUCTOR
|
||||
VALUE_PARAMETER_LIST
|
||||
VALUE_PARAMETER[fqName=Test.value, hasDefaultValue=false, hasValOrVar=true, isMutable=false, name=value]
|
||||
TYPE_REFERENCE
|
||||
USER_TYPE
|
||||
REFERENCE_EXPRESSION[referencedName=String]
|
||||
VALUE_PARAMETER[fqName=Test.other, hasDefaultValue=false, hasValOrVar=true, isMutable=false, name=other]
|
||||
TYPE_REFERENCE
|
||||
USER_TYPE
|
||||
REFERENCE_EXPRESSION[referencedName=String]
|
||||
CLASS[fqName=Annotated, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=Annotated, superNames=[]]
|
||||
MODIFIER_LIST[]
|
||||
ANNOTATION_ENTRY[hasValueArguments=true, shortName=Test]
|
||||
CONSTRUCTOR_CALLEE
|
||||
TYPE_REFERENCE
|
||||
USER_TYPE
|
||||
REFERENCE_EXPRESSION[referencedName=Test]
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
annotation class Test(val value: String, val other: String)
|
||||
|
||||
@Test("", other = "") class Annotated
|
||||
@@ -60,6 +60,12 @@ public class StubBuilderTestGenerated extends AbstractStubBuilderTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("AnnotationWithValue.kt")
|
||||
public void testAnnotationWithValue() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/stubs/AnnotationWithValue.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("AnnotationsOnPrimaryCtr.kt")
|
||||
public void testAnnotationsOnPrimaryCtr() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/stubs/AnnotationsOnPrimaryCtr.kt");
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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 com.intellij.testFramework.LightProjectDescriptor
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.intellij.lang.regexp.RegExpLanguage
|
||||
import org.jetbrains.kotlin.idea.test.JdkAndMockLibraryProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
|
||||
class KotlinLibInjectionTest : AbstractInjectionTest() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
}
|
||||
|
||||
fun testFunInjection() = assertInjectionPresent(
|
||||
"""
|
||||
import injection.html
|
||||
fun test() {
|
||||
12.html("<caret><html></html>")
|
||||
}
|
||||
""",
|
||||
HTMLLanguage.INSTANCE.id
|
||||
)
|
||||
|
||||
fun testFunInjectionWithImportedAnnotation() = assertInjectionPresent(
|
||||
"""
|
||||
import injection.regexp
|
||||
fun test() {
|
||||
12.regexp("<caret>test")
|
||||
}
|
||||
""",
|
||||
RegExpLanguage.INSTANCE.id
|
||||
)
|
||||
|
||||
private fun assertInjectionPresent(@Language("kotlin") text: String, languageId: String) {
|
||||
doInjectionPresentTest(text, languageId = languageId, unInjectShouldBePresent = false)
|
||||
}
|
||||
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor {
|
||||
return JdkAndMockLibraryProjectDescriptor(
|
||||
PluginTestCaseBase.getTestDataPathBase() + "/injection/lib/", false, false, false, true,
|
||||
arrayOf(KotlinTestUtils.getHomeDirectory() + "/ideaSDK/lib/annotations.jar"))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user