Refactor: extract utils related to DslMarker to a separate object

This commit is contained in:
Pavel V. Talanov
2018-02-08 16:50:36 +01:00
parent d570b863ce
commit 8600add7f7
5 changed files with 54 additions and 46 deletions
@@ -0,0 +1,46 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.calls
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.getAbbreviation
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object DslMarkerUtils {
fun extractDslMarkerFqNames(kotlinType: KotlinType): Set<FqName> {
val result = mutableSetOf<FqName>()
result.addAll(kotlinType.annotations.extractDslMarkerFqNames())
kotlinType.getAbbreviation()?.constructor?.declarationDescriptor?.run {
result.addAll(annotations.extractDslMarkerFqNames())
safeAs<TypeAliasDescriptor>()?.run {
result.addAll(extractDslMarkerFqNames(this.underlyingType))
}
}
kotlinType.constructor.declarationDescriptor?.getAllSuperClassifiers()?.asIterable()
?.flatMapTo(result) { it.annotations.extractDslMarkerFqNames() }
return result
}
private fun Annotations.extractDslMarkerFqNames() =
filter(AnnotationDescriptor::isDslMarker).map { it.fqName!! }
val DSL_MARKER_FQ_NAME = FqName("kotlin.DslMarker")
}
private fun AnnotationDescriptor.isDslMarker(): Boolean {
val classDescriptor = annotationClass ?: return false
return classDescriptor.annotations.hasAnnotation(DslMarkerUtils.DSL_MARKER_FQ_NAME)
}
@@ -18,22 +18,13 @@ package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.calls.DslMarkerUtils.extractDslMarkerFqNames
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getImplicitReceivers
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.getAbbreviation
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object DslScopeViolationCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
@@ -58,44 +49,15 @@ object DslScopeViolationCallChecker : CallChecker {
if (receiversUntilOneFromTheCall.isEmpty()) return
val callDslMarkers = callImplicitReceiver.type.extractDslMarkerFqNames()
val callDslMarkers = extractDslMarkerFqNames(callImplicitReceiver.type)
if (callDslMarkers.isEmpty()) return
val closestAnotherReceiverWithSameDslMarker =
receiversUntilOneFromTheCall.firstOrNull { receiver -> receiver.type.extractDslMarkerFqNames().any(callDslMarkers::contains) }
receiversUntilOneFromTheCall.firstOrNull { receiver -> extractDslMarkerFqNames(receiver.type).any(callDslMarkers::contains) }
if (closestAnotherReceiverWithSameDslMarker != null) {
// TODO: report receivers configuration (what's one is used and what's one is the closest)
context.trace.report(Errors.DSL_SCOPE_VIOLATION.on(reportOn, resolvedCall.resultingDescriptor))
}
}
fun KotlinType.extractDslMarkerFqNames(): Set<FqName> {
val result = mutableSetOf<FqName>()
result.addAll(annotations.extractDslMarkerFqNames())
getAbbreviation()?.constructor?.declarationDescriptor?.run {
result.addAll(annotations.extractDslMarkerFqNames())
safeAs<TypeAliasDescriptor>()?.run {
result.addAll(underlyingType.extractDslMarkerFqNames())
}
}
constructor.declarationDescriptor?.getAllSuperClassifiers()?.asIterable()
?.flatMapTo(result) { it.annotations.extractDslMarkerFqNames() }
return result
}
}
private fun Annotations.extractDslMarkerFqNames() =
filter(AnnotationDescriptor::isDslMarker).map { it.fqName!! }
private fun AnnotationDescriptor.isDslMarker(): Boolean {
val classDescriptor = annotationClass ?: return false
return classDescriptor.annotations.hasAnnotation(DSL_MARKER_FQ_NAME)
}
private val DSL_MARKER_FQ_NAME = FqName("kotlin.DslMarker")
}
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression
import org.jetbrains.kotlin.psi.psiUtil.isPackageDirectiveExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.checkers.DslScopeViolationCallChecker.extractDslMarkerFqNames
import org.jetbrains.kotlin.resolve.calls.DslMarkerUtils
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
@@ -350,7 +350,7 @@ fun Collection<ReceiverType>.shadowedByDslMarkers(): Set<ReceiverType> {
this
.mapNotNull { receiver ->
val dslMarkers = receiver.type.extractDslMarkerFqNames()
val dslMarkers = DslMarkerUtils.extractDslMarkerFqNames(receiver.type)
(receiver to dslMarkers).takeIf { dslMarkers.isNotEmpty() }
}
.forEach { (v, dslMarkers) -> dslMarkers.forEach { typesByDslScopes.getOrPut(it, { mutableListOf() }) += v } }
@@ -44,7 +44,6 @@ import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.checkers.DslScopeViolationCallChecker.extractDslMarkerFqNames
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
@@ -11,6 +11,7 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.highlighter.HighlighterExtension
import org.jetbrains.kotlin.resolve.calls.DslMarkerUtils
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -61,6 +62,6 @@ class DslHighlighterExtension : HighlighterExtension() {
internal fun ClassDescriptor.isDslHighlightingMarker(): Boolean {
return annotations.any {
it.annotationClass?.fqNameSafe?.asString() == "kotlin.DslMarker"
it.annotationClass?.fqNameSafe == DslMarkerUtils.DSL_MARKER_FQ_NAME
}
}