From d69d1f2c53038dce97334c42de8d4261d7ebfc4d Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Tue, 19 Apr 2016 22:37:15 +0300 Subject: [PATCH] Support toRegex() standard function #KT-8088 Fixed --- idea/resources/injection/kotlinInjections.xml | 3 ++ .../idea/injection/KotlinLanguageInjector.kt | 46 ++++++++++++------- .../kotlin/idea/patterns/KotlinPatterns.kt | 19 ++++++++ .../kotlin/psi/KotlinStdlibInjectionTest.kt | 21 +++++++++ 4 files changed, 73 insertions(+), 16 deletions(-) diff --git a/idea/resources/injection/kotlinInjections.xml b/idea/resources/injection/kotlinInjections.xml index 001d86b8f01..8e4751151dc 100644 --- a/idea/resources/injection/kotlinInjections.xml +++ b/idea/resources/injection/kotlinInjections.xml @@ -5,5 +5,8 @@ + diff --git a/idea/src/org/jetbrains/kotlin/idea/injection/KotlinLanguageInjector.kt b/idea/src/org/jetbrains/kotlin/idea/injection/KotlinLanguageInjector.kt index fc09b491195..b8f4a2c46f3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/injection/KotlinLanguageInjector.kt +++ b/idea/src/org/jetbrains/kotlin/idea/injection/KotlinLanguageInjector.kt @@ -18,13 +18,11 @@ package org.jetbrains.kotlin.idea.injection import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.util.TextRange -import com.intellij.psi.InjectedLanguagePlaces -import com.intellij.psi.LanguageInjector -import com.intellij.psi.PsiLanguageInjectionHost -import com.intellij.psi.PsiMethod +import com.intellij.psi.* import com.intellij.psi.util.PsiTreeUtil 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.jetbrains.kotlin.psi.* import java.util.* @@ -41,6 +39,7 @@ class KotlinLanguageInjector : LanguageInjector { val injectionInfo = injectWithExplicitCodeInstruction(ktHost) ?: injectWithCall(ktHost) + ?: injectWithReceiver(ktHost) ?: return val language = InjectorUtils.getLanguageByString(injectionInfo.languageId) ?: return @@ -53,6 +52,28 @@ class KotlinLanguageInjector : LanguageInjector { return InjectionInfo(languageId, null, null) } + private fun injectWithReceiver(host: KtElement): InjectionInfo? { + val qualifiedExpression = host.parent as? KtDotQualifiedExpression ?: return null + if (qualifiedExpression.receiverExpression != host) return null + + val callExpression = qualifiedExpression.selectorExpression as? KtCallExpression ?: return null + val callee = callExpression.calleeExpression ?: return null + + for (reference in callee.references) { + ProgressManager.checkCanceled() + + val resolvedTo = reference.resolve() + if (resolvedTo is KtFunction) { + val injectionInfo = findInjection(resolvedTo.receiverTypeReference, Configuration.getInstance().getInjections(KOTLIN_SUPPORT_ID)) + if (injectionInfo != null) { + return injectionInfo + } + } + } + + return null + } + private fun injectWithCall(host: KtElement): InjectionInfo? { val ktHost: KtElement = host val argument = ktHost.parent as? KtValueArgument ?: return null @@ -85,26 +106,19 @@ class KotlinLanguageInjector : LanguageInjector { val argumentIndex = (argument.parent as KtValueArgumentList).arguments.indexOf(argument) val psiParameter = javaMethod.parameterList.parameters.getOrNull(argumentIndex) ?: return null - val injections = Configuration.getInstance().getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID) - - for (injection in injections) { - if (injection.acceptsPsiElement(psiParameter)) { - // ?? if (!processXmlInjections(injection, owner, method, paramIndex)) { - return InjectionInfo(injection.injectedLanguageId, injection.prefix, injection.suffix) - } - } - - return null + return findInjection(psiParameter, Configuration.getInstance().getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID)) } private fun injectionForKotlinCall(argument: KtValueArgument, ktFunction: KtFunction): InjectionInfo? { val argumentIndex = (argument.parent as KtValueArgumentList).arguments.indexOf(argument) val ktParameter = ktFunction.valueParameters.getOrNull(argumentIndex) ?: return null - val injections = Configuration.getInstance().getInjections(KOTLIN_SUPPORT_ID) + return findInjection(ktParameter, Configuration.getInstance().getInjections(KOTLIN_SUPPORT_ID)) + } + private fun findInjection(element: PsiElement?, injections: List): InjectionInfo? { for (injection in injections) { - if (injection.acceptsPsiElement(ktParameter)) { + if (injection.acceptsPsiElement(element)) { return InjectionInfo(injection.injectedLanguageId, injection.prefix, injection.suffix) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/patterns/KotlinPatterns.kt b/idea/src/org/jetbrains/kotlin/idea/patterns/KotlinPatterns.kt index 7066ab97616..be788b3b699 100644 --- a/idea/src/org/jetbrains/kotlin/idea/patterns/KotlinPatterns.kt +++ b/idea/src/org/jetbrains/kotlin/idea/patterns/KotlinPatterns.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer object KotlinPatterns: StandardPatterns() { @JvmStatic fun psiParameter() = KtParameterPattern() @JvmStatic fun psiMethod() = KotlinFunctionPattern() + @JvmStatic fun receiver() = KotlinReceiverPattern() } // Methods in this class are used through reflection during pattern construction @@ -119,3 +120,21 @@ class KtParameterPattern : PsiElementPattern(Kt } } +@Suppress("unused") +class KotlinReceiverPattern : PsiElementPattern(KtTypeReference::class.java) { + fun ofMethod(pattern: ElementPattern): KotlinReceiverPattern { + return with(object : PatternConditionPlus("KtReceiverPattern-ofMethod", pattern) { + override fun processValues(typeReference: KtTypeReference, context: ProcessingContext?, processor: PairProcessor): Boolean { + return processor.process(typeReference.parent as? KtFunction, context) + } + + override fun accepts(typeReference: KtTypeReference, context: ProcessingContext?): Boolean { + val ktFunction = typeReference.parent as? KtFunction ?: return false + if (ktFunction.receiverTypeReference != typeReference) return false + + return super.accepts(typeReference, context) + } + }) + } +} + diff --git a/idea/tests/org/jetbrains/kotlin/psi/KotlinStdlibInjectionTest.kt b/idea/tests/org/jetbrains/kotlin/psi/KotlinStdlibInjectionTest.kt index d174f3e37eb..768ca90f4bf 100644 --- a/idea/tests/org/jetbrains/kotlin/psi/KotlinStdlibInjectionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/psi/KotlinStdlibInjectionTest.kt @@ -41,6 +41,27 @@ class KotlinStdlibInjectionTest : AbstractInjectionTest() { RegExpLanguage.INSTANCE.id ) + fun testToRegex0() = testInjection( + """ + |val test = "hi".toRegex() + """, + RegExpLanguage.INSTANCE.id + ) + + fun testToRegex1() = testInjection( + """ + |val test = "hi".toRegex(RegexOption.CANON_EQ) + """, + RegExpLanguage.INSTANCE.id + ) + + fun testToRegex2() = testInjection( + """ + |val test = "hi".toRegex(setOf(RegexOption.LITERAL)) + """, + RegExpLanguage.INSTANCE.id + ) + private fun testInjection(text: String, languageId: String) { testInjectionPresent(text, languageId, false) }