Introduce CheckerContext and ClassifierUsageCheckerContext

To reduce the number of parameters in classifier usage checker
implementations, and to unify the API with call checkers
This commit is contained in:
Alexander Udalov
2017-12-06 17:45:33 +01:00
parent e2def0c60e
commit 4cb5483c13
8 changed files with 118 additions and 118 deletions
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.load.java.descriptors.getImplClassNameForDeserialized import org.jetbrains.kotlin.load.java.descriptors.getImplClassNameForDeserialized
@@ -28,14 +27,13 @@ import org.jetbrains.kotlin.load.java.structure.impl.VirtualFileBoundJavaClass
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DeprecationResolver
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.checkers.ClassifierUsageChecker import org.jetbrains.kotlin.resolve.checkers.ClassifierUsageChecker
import org.jetbrains.kotlin.resolve.checkers.ClassifierUsageCheckerContext
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.* import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.*
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver.AccessError.* import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver.AccessError.*
@@ -101,27 +99,21 @@ class JvmModuleAccessibilityChecker(project: Project) : CallChecker {
} }
inner class ClassifierUsage : ClassifierUsageChecker { inner class ClassifierUsage : ClassifierUsageChecker {
override fun check( override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
targetDescriptor: ClassifierDescriptor,
trace: BindingTrace,
element: PsiElement,
languageVersionSettings: LanguageVersionSettings,
deprecationResolver: DeprecationResolver
) {
val virtualFile = element.containingFile.virtualFile val virtualFile = element.containingFile.virtualFile
when (targetDescriptor) { when (targetDescriptor) {
is ClassDescriptor -> { is ClassDescriptor -> {
diagnosticFor(targetDescriptor, targetDescriptor, virtualFile, element)?.let(trace::report) diagnosticFor(targetDescriptor, targetDescriptor, virtualFile, element)?.let(context.trace::report)
} }
is TypeAliasDescriptor -> { is TypeAliasDescriptor -> {
val containingClassOrPackage = DescriptorUtils.getParentOfType(targetDescriptor, ClassOrPackageFragmentDescriptor::class.java) val containingClassOrPackage = DescriptorUtils.getParentOfType(targetDescriptor, ClassOrPackageFragmentDescriptor::class.java)
if (containingClassOrPackage != null) { if (containingClassOrPackage != null) {
diagnosticFor(containingClassOrPackage, targetDescriptor, virtualFile, element)?.let(trace::report) diagnosticFor(containingClassOrPackage, targetDescriptor, virtualFile, element)?.let(context.trace::report)
} }
val expandedClass = targetDescriptor.expandedType.constructor.declarationDescriptor as? ClassDescriptor val expandedClass = targetDescriptor.expandedType.constructor.declarationDescriptor as? ClassDescriptor
if (expandedClass != null) { if (expandedClass != null) {
diagnosticFor(expandedClass, expandedClass, virtualFile, element)?.let(trace::report) diagnosticFor(expandedClass, expandedClass, virtualFile, element)?.let(context.trace::report)
} }
} }
} }
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.checkers.ClassifierUsageChecker import org.jetbrains.kotlin.resolve.checkers.ClassifierUsageChecker
import org.jetbrains.kotlin.resolve.checkers.ClassifierUsageCheckerContext
import org.jetbrains.kotlin.resolve.checkers.checkClassifierUsages
import org.jetbrains.kotlin.resolve.lazy.* import org.jetbrains.kotlin.resolve.lazy.*
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
@@ -223,7 +225,10 @@ class LazyTopDownAnalyzer(
resolveImportsInAllFiles(c) resolveImportsInAllFiles(c)
ClassifierUsageChecker.check(declarations, trace, languageVersionSettings, deprecationResolver, classifierUsageCheckers) checkClassifierUsages(
declarations, classifierUsageCheckers,
ClassifierUsageCheckerContext(trace, languageVersionSettings, deprecationResolver)
)
return c return c
} }
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.resolve.DeprecationResolver
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.checkers.CheckerContext
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.types.DeferredType import org.jetbrains.kotlin.types.DeferredType
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -37,10 +38,10 @@ interface CallChecker {
class CallCheckerContext( class CallCheckerContext(
val resolutionContext: ResolutionContext<*>, val resolutionContext: ResolutionContext<*>,
val trace: BindingTrace, override val trace: BindingTrace,
val languageVersionSettings: LanguageVersionSettings, override val languageVersionSettings: LanguageVersionSettings,
val deprecationResolver: DeprecationResolver override val deprecationResolver: DeprecationResolver
) { ) : CheckerContext {
val scope: LexicalScope val scope: LexicalScope
get() = resolutionContext.scope get() = resolutionContext.scope
@@ -17,23 +17,16 @@
package org.jetbrains.kotlin.resolve.checkers package org.jetbrains.kotlin.resolve.checkers
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DeprecationResolver
import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility
object ApiVersionClassifierUsageChecker : ClassifierUsageChecker { object ApiVersionClassifierUsageChecker : ClassifierUsageChecker {
override fun check( override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
targetDescriptor: ClassifierDescriptor, targetDescriptor.checkSinceKotlinVersionAccessibility(context.languageVersionSettings) { version ->
trace: BindingTrace, context.trace.report(
element: PsiElement, Errors.API_NOT_AVAILABLE.on(element, version.versionString, context.languageVersionSettings.apiVersion.versionString)
languageVersionSettings: LanguageVersionSettings, )
deprecationResolver: DeprecationResolver
) {
targetDescriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings) { version ->
trace.report(Errors.API_NOT_AVAILABLE.on(element, version.versionString, languageVersionSettings.apiVersion.versionString))
} }
} }
} }
@@ -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.resolve.checkers
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DeprecationResolver
interface CheckerContext {
val trace: BindingTrace
val languageVersionSettings: LanguageVersionSettings
val deprecationResolver: DeprecationResolver
}
@@ -32,21 +32,20 @@ import org.jetbrains.kotlin.resolve.DeprecationResolver
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
interface ClassifierUsageChecker { interface ClassifierUsageChecker {
fun check( fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext)
targetDescriptor: ClassifierDescriptor, }
trace: BindingTrace,
element: PsiElement,
languageVersionSettings: LanguageVersionSettings,
deprecationResolver: DeprecationResolver
)
companion object { class ClassifierUsageCheckerContext(
fun check( override val trace: BindingTrace,
override val languageVersionSettings: LanguageVersionSettings,
override val deprecationResolver: DeprecationResolver
) : CheckerContext
fun checkClassifierUsages(
declarations: Collection<PsiElement>, declarations: Collection<PsiElement>,
trace: BindingTrace, checkers: Iterable<ClassifierUsageChecker>,
languageVersionSettings: LanguageVersionSettings, context: ClassifierUsageCheckerContext
deprecationResolver: DeprecationResolver,
checkers: Iterable<ClassifierUsageChecker>
) { ) {
val visitor = object : KtTreeVisitorVoid() { val visitor = object : KtTreeVisitorVoid() {
override fun visitReferenceExpression(expression: KtReferenceExpression) { override fun visitReferenceExpression(expression: KtReferenceExpression) {
@@ -73,12 +72,12 @@ interface ClassifierUsageChecker {
private fun runCheckersWithTarget(target: ClassifierDescriptor, expression: KtReferenceExpression) { private fun runCheckersWithTarget(target: ClassifierDescriptor, expression: KtReferenceExpression) {
for (checker in checkers) { for (checker in checkers) {
checker.check(target, trace, expression, languageVersionSettings, deprecationResolver) checker.check(target, expression, context)
} }
} }
private fun getReferencedClassifier(expression: KtReferenceExpression): ClassifierDescriptor? { private fun getReferencedClassifier(expression: KtReferenceExpression): ClassifierDescriptor? {
val target = trace.get(BindingContext.REFERENCE_TARGET, expression) as? ClassifierDescriptor val target = context.trace.get(BindingContext.REFERENCE_TARGET, expression) as? ClassifierDescriptor
if (target != null) return target if (target != null) return target
// "Comparable" in "import java.lang.Comparable" references both a class and a SAM constructor and prevents // "Comparable" in "import java.lang.Comparable" references both a class and a SAM constructor and prevents
@@ -86,7 +85,7 @@ interface ClassifierUsageChecker {
// to report if there's something wrong with the class. We characterize this case below by the following properties: // to report if there's something wrong with the class. We characterize this case below by the following properties:
// 1) Exactly one of the references is a classifier // 1) Exactly one of the references is a classifier
// 2) All references refer to the same source element, i.e. their source is the same // 2) All references refer to the same source element, i.e. their source is the same
val targets = trace.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, expression) ?: return null val targets = context.trace.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, expression) ?: return null
if (targets.groupBy { (it as? DeclarationDescriptorWithSource)?.source }.size != 1) return null if (targets.groupBy { (it as? DeclarationDescriptorWithSource)?.source }.size != 1) return null
return targets.filterIsInstance<ClassifierDescriptor>().singleOrNull() return targets.filterIsInstance<ClassifierDescriptor>().singleOrNull()
} }
@@ -96,7 +95,7 @@ interface ClassifierUsageChecker {
target: ClassifierDescriptor target: ClassifierDescriptor
): ClassifierDescriptor? { ): ClassifierDescriptor? {
if (!DescriptorUtils.isCompanionObject(target)) return null if (!DescriptorUtils.isCompanionObject(target)) return null
return trace.get(BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, expression) return context.trace.get(BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, expression)
} }
} }
@@ -104,5 +103,3 @@ interface ClassifierUsageChecker {
declaration.accept(visitor) declaration.accept(visitor)
} }
} }
}
}
@@ -17,24 +17,16 @@
package org.jetbrains.kotlin.resolve.checkers package org.jetbrains.kotlin.resolve.checkers
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.psi.KtThisExpression import org.jetbrains.kotlin.psi.KtThisExpression
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DeprecationResolver
import org.jetbrains.kotlin.resolve.createDeprecationDiagnostic import org.jetbrains.kotlin.resolve.createDeprecationDiagnostic
class DeprecatedClassifierUsageChecker : ClassifierUsageChecker { class DeprecatedClassifierUsageChecker : ClassifierUsageChecker {
override fun check( override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
targetDescriptor: ClassifierDescriptor,
trace: BindingTrace,
element: PsiElement,
languageVersionSettings: LanguageVersionSettings,
deprecationResolver: DeprecationResolver
) {
if (element.parent is KtThisExpression) return if (element.parent is KtThisExpression) return
for (deprecation in deprecationResolver.getDeprecations(targetDescriptor)) {
trace.report(createDeprecationDiagnostic(element, deprecation, languageVersionSettings)) for (deprecation in context.deprecationResolver.getDeprecations(targetDescriptor)) {
context.trace.report(createDeprecationDiagnostic(element, deprecation, context.languageVersionSettings))
} }
} }
} }
@@ -17,12 +17,9 @@
package org.jetbrains.kotlin.resolve.checkers package org.jetbrains.kotlin.resolve.checkers
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DeprecationResolver
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.checkers.isComputingDeferredType import org.jetbrains.kotlin.resolve.calls.checkers.isComputingDeferredType
@@ -92,17 +89,11 @@ object MissingDependencyClassChecker : CallChecker {
} }
object ClassifierUsage : ClassifierUsageChecker { object ClassifierUsage : ClassifierUsageChecker {
override fun check( override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
targetDescriptor: ClassifierDescriptor, diagnosticFor(targetDescriptor, element)?.let(context.trace::report)
trace: BindingTrace,
element: PsiElement,
languageVersionSettings: LanguageVersionSettings,
deprecationResolver: DeprecationResolver
) {
diagnosticFor(targetDescriptor, element)?.let(trace::report)
val containerSource = (targetDescriptor as? DeserializedMemberDescriptor)?.containerSource val containerSource = (targetDescriptor as? DeserializedMemberDescriptor)?.containerSource
incompatibilityDiagnosticFor(containerSource, element)?.let(trace::report) incompatibilityDiagnosticFor(containerSource, element)?.let(context.trace::report)
} }
} }
} }