diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DslMarkerUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DslMarkerUtils.kt new file mode 100644 index 00000000000..0992bf7eb38 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DslMarkerUtils.kt @@ -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 { + val result = mutableSetOf() + + result.addAll(kotlinType.annotations.extractDslMarkerFqNames()) + + kotlinType.getAbbreviation()?.constructor?.declarationDescriptor?.run { + result.addAll(annotations.extractDslMarkerFqNames()) + safeAs()?.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) +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DslScopeViolationCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DslScopeViolationCallChecker.kt index 3bf77542e2b..2b80123de57 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DslScopeViolationCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DslScopeViolationCallChecker.kt @@ -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 { - val result = mutableSetOf() - - result.addAll(annotations.extractDslMarkerFqNames()) - - getAbbreviation()?.constructor?.declarationDescriptor?.run { - result.addAll(annotations.extractDslMarkerFqNames()) - safeAs()?.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") +} \ No newline at end of file diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt index 26879cf0934..a018331c56a 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt @@ -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.shadowedByDslMarkers(): Set { 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 } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index 376fefc7663..cd427e66ee4 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -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 diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/dsl/DslHighlighterExtension.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/dsl/DslHighlighterExtension.kt index c500306cf06..ac68e74a694 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/dsl/DslHighlighterExtension.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/dsl/DslHighlighterExtension.kt @@ -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 } }