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)
}