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.OrderRootType;
|
||||||
import com.intellij.openapi.roots.libraries.Library;
|
import com.intellij.openapi.roots.libraries.Library;
|
||||||
import com.intellij.openapi.util.io.FileUtilRt;
|
import com.intellij.openapi.util.io.FileUtilRt;
|
||||||
|
import com.intellij.util.ArrayUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.test.MockLibraryUtil;
|
import org.jetbrains.kotlin.test.MockLibraryUtil;
|
||||||
import org.jetbrains.kotlin.utils.PathUtil;
|
import org.jetbrains.kotlin.utils.PathUtil;
|
||||||
@@ -36,22 +37,30 @@ public class JdkAndMockLibraryProjectDescriptor extends KotlinLightProjectDescri
|
|||||||
private final boolean withRuntime;
|
private final boolean withRuntime;
|
||||||
private final boolean isJsLibrary;
|
private final boolean isJsLibrary;
|
||||||
private final boolean allowKotlinPackage;
|
private final boolean allowKotlinPackage;
|
||||||
|
private final String[] classpath;
|
||||||
|
|
||||||
public JdkAndMockLibraryProjectDescriptor(String sourcesPath, boolean withSources) {
|
public JdkAndMockLibraryProjectDescriptor(String sourcesPath, boolean withSources) {
|
||||||
this(sourcesPath, withSources, false, false, false);
|
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.sourcesPath = sourcesPath;
|
||||||
this.withSources = withSources;
|
this.withSources = withSources;
|
||||||
this.withRuntime = withRuntime;
|
this.withRuntime = withRuntime;
|
||||||
this.isJsLibrary = isJsLibrary;
|
this.isJsLibrary = isJsLibrary;
|
||||||
this.allowKotlinPackage = allowKotlinPackage;
|
this.allowKotlinPackage = allowKotlinPackage;
|
||||||
|
this.classpath = classpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model) {
|
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);
|
String jarUrl = getJarUrl(libraryJar);
|
||||||
|
|
||||||
Library.ModifiableModel libraryModel = model.getModuleLibraryTable().getModifiableModel().createLibrary(LIBRARY_NAME).getModifiableModel();
|
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.config.BaseInjection
|
||||||
import org.intellij.plugins.intelliLang.inject.java.JavaLanguageInjectionSupport
|
import org.intellij.plugins.intelliLang.inject.java.JavaLanguageInjectionSupport
|
||||||
import org.intellij.plugins.intelliLang.util.AnnotationUtilEx
|
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.ProjectRootsUtil
|
||||||
import org.jetbrains.kotlin.idea.util.findAnnotation
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class KotlinLanguageInjector : LanguageInjector {
|
class KotlinLanguageInjector : LanguageInjector {
|
||||||
@@ -126,7 +130,7 @@ class KotlinLanguageInjector : LanguageInjector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (resolvedTo is KtFunction) {
|
else if (resolvedTo is KtFunction) {
|
||||||
val injectionForJavaMethod = injectionForKotlinCall(argument, resolvedTo)
|
val injectionForJavaMethod = injectionForKotlinCall(argument, resolvedTo, reference)
|
||||||
if (injectionForJavaMethod != null) {
|
if (injectionForJavaMethod != null) {
|
||||||
return injectionForJavaMethod
|
return injectionForJavaMethod
|
||||||
}
|
}
|
||||||
@@ -150,14 +154,14 @@ class KotlinLanguageInjector : LanguageInjector {
|
|||||||
Configuration.getProjectInstance(psiParameter.project).advancedConfiguration.languageAnnotationPair,
|
Configuration.getProjectInstance(psiParameter.project).advancedConfiguration.languageAnnotationPair,
|
||||||
true)
|
true)
|
||||||
|
|
||||||
if (annotations.size > 0) {
|
if (annotations.isNotEmpty()) {
|
||||||
return processAnnotationInjectionInner(annotations)
|
return processAnnotationInjectionInner(annotations)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
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 argumentIndex = (argument.parent as KtValueArgumentList).arguments.indexOf(argument)
|
||||||
val ktParameter = ktFunction.valueParameters.getOrNull(argumentIndex) ?: return null
|
val ktParameter = ktFunction.valueParameters.getOrNull(argumentIndex) ?: return null
|
||||||
|
|
||||||
@@ -166,8 +170,16 @@ class KotlinLanguageInjector : LanguageInjector {
|
|||||||
return patternInjection
|
return patternInjection
|
||||||
}
|
}
|
||||||
|
|
||||||
val injectAnnotation = ktParameter.findAnnotation(FqName(AnnotationUtil.LANGUAGE)) ?: return null
|
// Found psi element after resolve can be obtained from compiled declaration but annotations parameters are lost there.
|
||||||
val languageId = extractLanguageFromInjectAnnotation(injectAnnotation) ?: return null
|
// 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)
|
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);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("AnnotationWithValue.kt")
|
||||||
|
public void testAnnotationWithValue() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/stubs/AnnotationWithValue.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("AnnotationsOnPrimaryCtr.kt")
|
@TestMetadata("AnnotationsOnPrimaryCtr.kt")
|
||||||
public void testAnnotationsOnPrimaryCtr() throws Exception {
|
public void testAnnotationsOnPrimaryCtr() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/stubs/AnnotationsOnPrimaryCtr.kt");
|
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