Support toRegex() standard function

#KT-8088 Fixed
This commit is contained in:
Nikolay Krasko
2016-04-19 22:37:15 +03:00
parent 6bea3923f5
commit d69d1f2c53
4 changed files with 73 additions and 16 deletions
@@ -5,5 +5,8 @@
<place><![CDATA[
psiParameter().ofMethod(0, psiMethod().withName("Regex").definedInClass("kotlin.text.Regex"))
]]></place>
<place><![CDATA[
receiver().ofMethod(psiMethod().withName("toRegex").withReceiver("kotlin.String").definedInPackage("kotlin.text"))
]]></place>
</injection>
</component>
@@ -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<BaseInjection>): InjectionInfo? {
for (injection in injections) {
if (injection.acceptsPsiElement(ktParameter)) {
if (injection.acceptsPsiElement(element)) {
return InjectionInfo(injection.injectedLanguageId, injection.prefix, injection.suffix)
}
}
@@ -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<KtParameter, KtParameterPattern>(Kt
}
}
@Suppress("unused")
class KotlinReceiverPattern : PsiElementPattern<KtTypeReference, KotlinReceiverPattern>(KtTypeReference::class.java) {
fun ofMethod(pattern: ElementPattern<Any>): KotlinReceiverPattern {
return with(object : PatternConditionPlus<KtTypeReference, KtFunction>("KtReceiverPattern-ofMethod", pattern) {
override fun processValues(typeReference: KtTypeReference, context: ProcessingContext?, processor: PairProcessor<KtFunction, ProcessingContext>): 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)
}
})
}
}
@@ -41,6 +41,27 @@ class KotlinStdlibInjectionTest : AbstractInjectionTest() {
RegExpLanguage.INSTANCE.id
)
fun testToRegex0() = testInjection(
"""
|val test = "hi<caret>".toRegex()
""",
RegExpLanguage.INSTANCE.id
)
fun testToRegex1() = testInjection(
"""
|val test = "hi<caret>".toRegex(RegexOption.CANON_EQ)
""",
RegExpLanguage.INSTANCE.id
)
fun testToRegex2() = testInjection(
"""
|val test = "hi<caret>".toRegex(setOf(RegexOption.LITERAL))
""",
RegExpLanguage.INSTANCE.id
)
private fun testInjection(text: String, languageId: String) {
testInjectionPresent(text, languageId, false)
}