Ad hoc solution to avoid resolution in language injection by receiver (KT-16995)

#KT-16995 Fixed
This commit is contained in:
Nikolay Krasko
2017-03-31 18:41:46 +03:00
parent f16736285a
commit eb4e6e6c1a
@@ -38,8 +38,13 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import java.util.* import java.util.*
import kotlin.collections.ArrayList
class KotlinLanguageInjector : LanguageInjector { class KotlinLanguageInjector : LanguageInjector {
companion object {
private val STRING_LITERALS_REGEXP = "\"([^\"]*)\"".toRegex()
}
val kotlinSupport: KotlinLanguageInjectionSupport? by lazy { val kotlinSupport: KotlinLanguageInjectionSupport? by lazy {
ArrayList(InjectorUtils.getActiveInjectionSupports()).filterIsInstance(KotlinLanguageInjectionSupport::class.java).firstOrNull() ArrayList(InjectorUtils.getActiveInjectionSupports()).filterIsInstance(KotlinLanguageInjectionSupport::class.java).firstOrNull()
} }
@@ -58,9 +63,9 @@ class KotlinLanguageInjector : LanguageInjector {
private fun findInjectionInfo(place: KtElement, originalHost: Boolean = true): InjectionInfo? { private fun findInjectionInfo(place: KtElement, originalHost: Boolean = true): InjectionInfo? {
return injectWithExplicitCodeInstruction(place) return injectWithExplicitCodeInstruction(place)
?: injectWithCall(place) ?: injectWithCall(place)
?: injectWithReceiver(place) ?: injectWithReceiver(place)
?: injectWithVariableUsage(place, originalHost) ?: injectWithVariableUsage(place, originalHost)
} }
private fun injectWithExplicitCodeInstruction(host: KtElement): InjectionInfo? { private fun injectWithExplicitCodeInstruction(host: KtElement): InjectionInfo? {
@@ -78,12 +83,21 @@ class KotlinLanguageInjector : LanguageInjector {
if (isAnalyzeOff(qualifiedExpression.project)) return null if (isAnalyzeOff(qualifiedExpression.project)) return null
val kotlinInjections = Configuration.getInstance().getInjections(KOTLIN_SUPPORT_ID)
val calleeName = callee.text
val possibleNames = collectPossibleNames(kotlinInjections)
if (calleeName !in possibleNames) {
return null
}
for (reference in callee.references) { for (reference in callee.references) {
ProgressManager.checkCanceled() ProgressManager.checkCanceled()
val resolvedTo = reference.resolve() val resolvedTo = reference.resolve()
if (resolvedTo is KtFunction) { if (resolvedTo is KtFunction) {
val injectionInfo = findInjection(resolvedTo.receiverTypeReference, Configuration.getInstance().getInjections(KOTLIN_SUPPORT_ID)) val injectionInfo = findInjection(resolvedTo.receiverTypeReference, kotlinInjections)
if (injectionInfo != null) { if (injectionInfo != null) {
return injectionInfo return injectionInfo
} }
@@ -93,6 +107,21 @@ class KotlinLanguageInjector : LanguageInjector {
return null return null
} }
private fun collectPossibleNames(injections: List<BaseInjection>): Set<String> {
val result = HashSet<String>()
for (injection in injections) {
val injectionPlaces = injection.injectionPlaces
for (place in injectionPlaces) {
val placeStr = place.toString()
val literals = STRING_LITERALS_REGEXP.findAll(placeStr).map { it.groupValues[1] }
result.addAll(literals)
}
}
return result
}
private fun injectWithVariableUsage(host: KtElement, originalHost: Boolean): InjectionInfo? { private fun injectWithVariableUsage(host: KtElement, originalHost: Boolean): InjectionInfo? {
// Given place is not original host of the injection so we stop to prevent stepping through indirect references // Given place is not original host of the injection so we stop to prevent stepping through indirect references
if (!originalHost) return null if (!originalHost) return null