Do not use IntelliJ extensions for declaration without body suppressor in JS

This commit is contained in:
Alexander Udalov
2017-10-24 18:21:45 +02:00
parent 7f81601123
commit 6f90a0545c
7 changed files with 40 additions and 86 deletions
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.BindingContext.*
import org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveAbstractDeclaration
import org.jetbrains.kotlin.resolve.DescriptorUtils.classCanHaveOpenMembers
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.resolve.checkers.PlatformDiagnosticSuppressor
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
@@ -49,10 +50,13 @@ internal class DeclarationsCheckerBuilder(
private val annotationChecker: AnnotationChecker,
private val identifierChecker: IdentifierChecker,
private val languageVersionSettings: LanguageVersionSettings,
private val typeSpecificityComparator: TypeSpecificityComparator
private val typeSpecificityComparator: TypeSpecificityComparator,
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
) {
fun withTrace(trace: BindingTrace) =
DeclarationsChecker(descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageVersionSettings, typeSpecificityComparator)
fun withTrace(trace: BindingTrace) = DeclarationsChecker(
descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageVersionSettings,
typeSpecificityComparator, diagnosticSuppressor
)
}
class DeclarationsChecker(
@@ -62,7 +66,8 @@ class DeclarationsChecker(
private val identifierChecker: IdentifierChecker,
private val trace: BindingTrace,
private val languageVersionSettings: LanguageVersionSettings,
typeSpecificityComparator: TypeSpecificityComparator
typeSpecificityComparator: TypeSpecificityComparator,
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
) {
private val modifiersChecker = modifiersChecker.withTrace(trace)
@@ -670,11 +675,13 @@ class DeclarationsChecker(
if (propertyDescriptor.extensionReceiverParameter != null && !hasAccessorImplementation) {
trace.report(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT.on(property))
}
else if (containingDeclaration !is ClassDescriptor || hasAccessorImplementation) {
trace.report(MUST_BE_INITIALIZED.on(property))
}
else {
trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property))
else if (diagnosticSuppressor.shouldReportNoBody(propertyDescriptor)) {
if (containingDeclaration !is ClassDescriptor || hasAccessorImplementation) {
trace.report(MUST_BE_INITIALIZED.on(property))
}
else {
trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property))
}
}
}
else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
@@ -733,12 +740,14 @@ class DeclarationsChecker(
trace.report(REDUNDANT_OPEN_IN_INTERFACE.on(function))
}
}
if (!hasBody && !hasAbstractModifier && !hasExternalModifier && !inInterface && !isExpectClass) {
if (!hasBody && !hasAbstractModifier && !hasExternalModifier && !inInterface && !isExpectClass &&
diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) {
trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor))
}
}
else /* top-level only */ {
if (!function.hasBody() && !hasAbstractModifier && !hasExternalModifier && !functionDescriptor.isExpect) {
if (!function.hasBody() && !hasAbstractModifier && !hasExternalModifier && !functionDescriptor.isExpect &&
diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) {
trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor))
}
}
@@ -17,13 +17,18 @@
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.container.DefaultImplementation
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
@DefaultImplementation(PlatformDiagnosticSuppressor.Default::class)
interface PlatformDiagnosticSuppressor {
fun shouldReportUnusedParameter(parameter: VariableDescriptor): Boolean
fun shouldReportNoBody(descriptor: CallableMemberDescriptor): Boolean
object Default : PlatformDiagnosticSuppressor {
override fun shouldReportUnusedParameter(parameter: VariableDescriptor): Boolean = true
override fun shouldReportNoBody(descriptor: CallableMemberDescriptor): Boolean = true
}
}
@@ -33,15 +33,6 @@ import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.util.ExtensionProvider
interface SuppressStringProvider {
operator fun get(annotationDescriptor: AnnotationDescriptor): List<String>
companion object {
val EP_NAME: ExtensionPointName<SuppressStringProvider> =
ExtensionPointName.create<SuppressStringProvider>("org.jetbrains.kotlin.suppressStringProvider")
}
}
interface DiagnosticSuppressor {
fun isSuppressed(diagnostic: Diagnostic): Boolean
@@ -52,8 +43,7 @@ interface DiagnosticSuppressor {
}
abstract class KotlinSuppressCache {
private val ADDITIONAL_SUPPRESS_STRING_PROVIDERS = ExtensionProvider.create(SuppressStringProvider.EP_NAME)
private val DIAGNOSTIC_SUPPRESSORS = ExtensionProvider.create(DiagnosticSuppressor.EP_NAME)
private val diagnosticSuppressors = ExtensionProvider.create(DiagnosticSuppressor.EP_NAME)
// The cache is weak: we're OK with losing it
private val suppressors = ContainerUtil.createConcurrentWeakValueMap<KtAnnotated, Suppressor>()
@@ -77,7 +67,7 @@ abstract class KotlinSuppressCache {
}
if (request is DiagnosticSuppressRequest) {
for (suppressor in DIAGNOSTIC_SUPPRESSORS.get()) {
for (suppressor in diagnosticSuppressors.get()) {
if (suppressor.isSuppressed(request.diagnostic)) return true
}
}
@@ -158,10 +148,6 @@ abstract class KotlinSuppressCache {
}
private fun processAnnotation(builder: ImmutableSet.Builder<String>, annotationDescriptor: AnnotationDescriptor) {
for (suppressStringProvider in ADDITIONAL_SUPPRESS_STRING_PROVIDERS.get()) {
builder.addAll(suppressStringProvider[annotationDescriptor])
}
if (annotationDescriptor.fqName != KotlinBuiltIns.FQ_NAMES.suppress) return
// We only add strings and skip other values to facilitate recovery in presence of erroneous code
@@ -1,43 +0,0 @@
/*
* Copyright 2010-2015 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.diagnostics
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtProperty
val FUNCTION_NO_BODY_ERRORS: List<DiagnosticFactory1<KtFunction, SimpleFunctionDescriptor>> =
listOf(Errors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY, Errors.NON_MEMBER_FUNCTION_NO_BODY)
val PROPERTY_NOT_INITIALIZED_ERRORS: List<DiagnosticFactory0<KtProperty>> =
listOf(Errors.MUST_BE_INITIALIZED, Errors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT)
abstract class SuppressDiagnosticsByAnnotations(
diagnosticsToSuppress: List<DiagnosticFactory<out Diagnostic>>,
vararg annotationFqNames: FqName
) : SuppressStringProvider {
private val stringsToSuppress = diagnosticsToSuppress.map { it.name.toLowerCase() }
private val expectedFqNames = annotationFqNames.toSet()
override fun get(annotationDescriptor: AnnotationDescriptor): List<String> {
return if (annotationDescriptor.fqName in expectedFqNames) stringsToSuppress else emptyList()
}
}
-2
View File
@@ -2,8 +2,6 @@
<id>org.jetbrains.kotlin</id>
<extensionPoints>
<extensionPoint name="suppressStringProvider"
interface="org.jetbrains.kotlin.resolve.diagnostics.SuppressStringProvider"/>
<extensionPoint name="diagnosticSuppressor"
interface="org.jetbrains.kotlin.resolve.diagnostics.DiagnosticSuppressor"/>
<extensionPoint name="expressionCodegenExtension"
@@ -2,7 +2,6 @@
<id>org.jetbrains.kotlin</id>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<suppressStringProvider implementation="org.jetbrains.kotlin.js.analyze.SuppressNoBodyErrorsForNativeDeclarations"/>
<diagnosticSuppressor implementation="org.jetbrains.kotlin.js.analyze.SuppressUninitializedErrorsForNativeDeclarations"/>
</extensions>
</idea-plugin>
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.js.analyze
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
@@ -26,25 +27,24 @@ import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.checkers.PlatformDiagnosticSuppressor
import org.jetbrains.kotlin.resolve.diagnostics.DiagnosticSuppressor
import org.jetbrains.kotlin.resolve.diagnostics.FUNCTION_NO_BODY_ERRORS
import org.jetbrains.kotlin.resolve.diagnostics.PROPERTY_NOT_INITIALIZED_ERRORS
import org.jetbrains.kotlin.resolve.diagnostics.SuppressDiagnosticsByAnnotations
private val NATIVE_ANNOTATIONS = arrayOf(NATIVE.fqName, NATIVE_INVOKE.fqName, NATIVE_GETTER.fqName, NATIVE_SETTER.fqName)
object JsNativeDiagnosticSuppressor : PlatformDiagnosticSuppressor {
override fun shouldReportUnusedParameter(parameter: VariableDescriptor): Boolean {
var descriptor: DeclarationDescriptor = parameter
while (true) {
val annotations = descriptor.annotations
if (!annotations.isEmpty() && NATIVE_ANNOTATIONS.any(annotations::hasAnnotation)) return false
descriptor = descriptor.containingDeclaration ?: break
}
return true
private fun DeclarationDescriptor.isLexicallyInsideJsNative(): Boolean {
var descriptor: DeclarationDescriptor = this
while (true) {
val annotations = descriptor.annotations
if (!annotations.isEmpty() && NATIVE_ANNOTATIONS.any(annotations::hasAnnotation)) return true
descriptor = descriptor.containingDeclaration ?: break
}
return false
}
class SuppressNoBodyErrorsForNativeDeclarations : SuppressDiagnosticsByAnnotations(FUNCTION_NO_BODY_ERRORS + PROPERTY_NOT_INITIALIZED_ERRORS, *NATIVE_ANNOTATIONS)
object JsNativeDiagnosticSuppressor : PlatformDiagnosticSuppressor {
override fun shouldReportUnusedParameter(parameter: VariableDescriptor): Boolean = !parameter.isLexicallyInsideJsNative()
override fun shouldReportNoBody(descriptor: CallableMemberDescriptor): Boolean = !descriptor.isLexicallyInsideJsNative()
}
class SuppressUninitializedErrorsForNativeDeclarations : DiagnosticSuppressor {
override fun isSuppressed(diagnostic: Diagnostic): Boolean {