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 org.jetbrains.annotations.TestOnly
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.idea.caches.resolve.getNullableModuleInfo
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,
* null if full resolve is required to answer that question.
*/
fun canBeTargetReference(ref: KtSimpleNameExpression): Boolean? {
fun canBeTargetReference(ref: KtSimpleNameExpression): ImpreciseResolveResult {
attempts.incrementAndGet()
// The names can be different if the target was imported via an import alias
if (ref.getReferencedName() != targetShortName) {
return null
return UNSURE
}
// 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.
val userType = ref.getStrictParentOfType<KtUserType>() ?: return null
val userType = ref.getStrictParentOfType<KtUserType>() ?: return UNSURE
if (forceAmbiguityForNonAnnotations && userType.getParentOfTypeAndBranch<KtAnnotationEntry> { typeReference } == null) {
return null
return UNSURE
}
if (forceAmbiguity) {
return null
return UNSURE
}
val qualifiedCheckResult = checkQualifiedReferenceToTarget(ref)
@@ -156,23 +158,23 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
result = result.changeTo(Result.FoundOther)
}
else if (filePackage in packagesWithTypeAliases) {
return null
return UNSURE
}
for (importPath in file.getDefaultImports()) {
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) {
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()
}
else if (result.returnValue == false) {
else if (result.returnValue == NO_MATCH) {
falseHits.incrementAndGet()
}
return result.returnValue
@@ -225,11 +227,11 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
return null
}
enum class Result(val returnValue: Boolean?) {
NothingFound(false),
Found(true),
FoundOther(false),
Ambiguity(null)
enum class Result(val returnValue: ImpreciseResolveResult) {
NothingFound(NO_MATCH),
Found(MATCH),
FoundOther(NO_MATCH),
Ambiguity(UNSURE)
}
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.QueryExecutor
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.toLightClass
import org.jetbrains.kotlin.idea.caches.resolve.analyze
@@ -94,8 +96,8 @@ class KotlinAnnotatedElementsSearcher : QueryExecutor<PsiModifierListOwner, Anno
psiBasedClassResolver.canBeTargetReference(ref)
}
if (psiBasedResolveResult == false) return true
if (psiBasedResolveResult == null) {
if (psiBasedResolveResult == NO_MATCH) return true
if (psiBasedResolveResult == UNSURE) {
val context = elt.analyze(BodyResolveMode.PARTIAL)
val annotationDescriptor = context.get(BindingContext.ANNOTATION, elt) ?: return true
@@ -108,6 +108,8 @@ class PsiBasedClassResolverTest : KotlinLightCodeInsightFixtureTestCaseBase() {
fileText) as KtFile
val index = fileText.indexOf(marker)
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
}
}