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")
}