PsiBasedClassResolver: use ImpreciseResolveResult instead of Boolean?

This commit is contained in:
Pavel V. Talanov
2017-04-24 17:30:35 +03:00
parent 8f4c969933
commit 901aa9c18b
4 changed files with 53 additions and 18 deletions
@@ -0,0 +1,29 @@
/*
* 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.asJava
enum class ImpreciseResolveResult {
MATCH,
NO_MATCH,
UNSURE;
inline fun ifSure(body: (Boolean) -> Unit) = when (this) {
MATCH -> body(true)
NO_MATCH -> body(false)
UNSURE -> Unit
}
}
@@ -21,6 +21,8 @@ import com.intellij.psi.PsiModifier
import com.intellij.psi.search.PsiShortNamesCache import com.intellij.psi.search.PsiShortNamesCache
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult.*
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.idea.caches.resolve.getNullableModuleInfo import org.jetbrains.kotlin.idea.caches.resolve.getNullableModuleInfo
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
@@ -123,22 +125,22 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
* @return true if it will definitely resolve to that class, false if it will definitely resolve to something else, * @return true if it will definitely resolve to that class, false if it will definitely resolve to something else,
* null if full resolve is required to answer that question. * null if full resolve is required to answer that question.
*/ */
fun canBeTargetReference(ref: KtSimpleNameExpression): Boolean? { fun canBeTargetReference(ref: KtSimpleNameExpression): ImpreciseResolveResult {
attempts.incrementAndGet() attempts.incrementAndGet()
// The names can be different if the target was imported via an import alias // The names can be different if the target was imported via an import alias
if (ref.getReferencedName() != targetShortName) { if (ref.getReferencedName() != targetShortName) {
return null return UNSURE
} }
// Names in expressions can conflict with local declarations and methods of implicit receivers, // Names in expressions can conflict with local declarations and methods of implicit receivers,
// so we can't find out what they refer to without a full resolve. // so we can't find out what they refer to without a full resolve.
val userType = ref.getStrictParentOfType<KtUserType>() ?: return null val userType = ref.getStrictParentOfType<KtUserType>() ?: return UNSURE
if (forceAmbiguityForNonAnnotations && userType.getParentOfTypeAndBranch<KtAnnotationEntry> { typeReference } == null) { if (forceAmbiguityForNonAnnotations && userType.getParentOfTypeAndBranch<KtAnnotationEntry> { typeReference } == null) {
return null return UNSURE
} }
if (forceAmbiguity) { if (forceAmbiguity) {
return null return UNSURE
} }
val qualifiedCheckResult = checkQualifiedReferenceToTarget(ref) val qualifiedCheckResult = checkQualifiedReferenceToTarget(ref)
@@ -156,23 +158,23 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
result = result.changeTo(Result.FoundOther) result = result.changeTo(Result.FoundOther)
} }
else if (filePackage in packagesWithTypeAliases) { else if (filePackage in packagesWithTypeAliases) {
return null return UNSURE
} }
for (importPath in file.getDefaultImports()) { for (importPath in file.getDefaultImports()) {
result = analyzeSingleImport(result, importPath.fqName, importPath.isAllUnder, importPath.alias?.asString()) result = analyzeSingleImport(result, importPath.fqName, importPath.isAllUnder, importPath.alias?.asString())
if (result == Result.Ambiguity) return null if (result == Result.Ambiguity) return UNSURE
} }
for (importDirective in file.importDirectives) { for (importDirective in file.importDirectives) {
result = analyzeSingleImport(result, importDirective.importedFqName, importDirective.isAllUnder, importDirective.aliasName) result = analyzeSingleImport(result, importDirective.importedFqName, importDirective.isAllUnder, importDirective.aliasName)
if (result == Result.Ambiguity) return null if (result == Result.Ambiguity) return UNSURE
} }
if (result.returnValue == true) { if (result.returnValue == MATCH) {
trueHits.incrementAndGet() trueHits.incrementAndGet()
} }
else if (result.returnValue == false) { else if (result.returnValue == NO_MATCH) {
falseHits.incrementAndGet() falseHits.incrementAndGet()
} }
return result.returnValue return result.returnValue
@@ -225,11 +227,11 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
return null return null
} }
enum class Result(val returnValue: Boolean?) { enum class Result(val returnValue: ImpreciseResolveResult) {
NothingFound(false), NothingFound(NO_MATCH),
Found(true), Found(MATCH),
FoundOther(false), FoundOther(NO_MATCH),
Ambiguity(null) Ambiguity(UNSURE)
} }
fun Result.changeTo(newResult: Result): Result { fun Result.changeTo(newResult: Result): Result {
@@ -28,6 +28,8 @@ import com.intellij.psi.util.PsiUtilCore
import com.intellij.util.Processor import com.intellij.util.Processor
import com.intellij.util.QueryExecutor import com.intellij.util.QueryExecutor
import com.intellij.util.indexing.FileBasedIndex import com.intellij.util.indexing.FileBasedIndex
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult.NO_MATCH
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult.UNSURE
import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
@@ -94,8 +96,8 @@ class KotlinAnnotatedElementsSearcher : QueryExecutor<PsiModifierListOwner, Anno
psiBasedClassResolver.canBeTargetReference(ref) psiBasedClassResolver.canBeTargetReference(ref)
} }
if (psiBasedResolveResult == false) return true if (psiBasedResolveResult == NO_MATCH) return true
if (psiBasedResolveResult == null) { if (psiBasedResolveResult == UNSURE) {
val context = elt.analyze(BodyResolveMode.PARTIAL) val context = elt.analyze(BodyResolveMode.PARTIAL)
val annotationDescriptor = context.get(BindingContext.ANNOTATION, elt) ?: return true val annotationDescriptor = context.get(BindingContext.ANNOTATION, elt) ?: return true
@@ -108,6 +108,8 @@ class PsiBasedClassResolverTest : KotlinLightCodeInsightFixtureTestCaseBase() {
fileText) as KtFile fileText) as KtFile
val index = fileText.indexOf(marker) val index = fileText.indexOf(marker)
val ref = file.findElementAt(index + marker.indexOf("Test"))!!.getParentOfType<KtSimpleNameExpression>(false)!! val ref = file.findElementAt(index + marker.indexOf("Test"))!!.getParentOfType<KtSimpleNameExpression>(false)!!
return resolver.canBeTargetReference(ref) val canBeTargetReference = resolver.canBeTargetReference(ref)
canBeTargetReference.ifSure { return it }
return null
} }
} }