Noarg: prohibit noarg for inner and local classes
Report warning if old JVM backend is used, and error for JVM IR, which is supposed to be enabled as default in the next Kotlin release. #KT-43725 Fixed
This commit is contained in:
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
|
||||
import org.jetbrains.kotlin.compiler.plugin.*
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||
import org.jetbrains.kotlin.container.useInstance
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
@@ -88,24 +89,29 @@ class NoArgComponentRegistrar : ComponentRegistrar {
|
||||
SUPPORTED_PRESETS[preset]?.let { annotations += it }
|
||||
}
|
||||
if (annotations.isNotEmpty()) {
|
||||
registerNoArgComponents(project, annotations, configuration.getBoolean(INVOKE_INITIALIZERS))
|
||||
registerNoArgComponents(
|
||||
project, annotations, configuration.getBoolean(JVMConfigurationKeys.IR), configuration.getBoolean(INVOKE_INITIALIZERS),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
fun registerNoArgComponents(project: Project, annotations: List<String>, invokeInitializers: Boolean) {
|
||||
StorageComponentContainerContributor.registerExtension(project, CliNoArgComponentContainerContributor(annotations))
|
||||
fun registerNoArgComponents(project: Project, annotations: List<String>, useIr: Boolean, invokeInitializers: Boolean) {
|
||||
StorageComponentContainerContributor.registerExtension(project, CliNoArgComponentContainerContributor(annotations, useIr))
|
||||
ExpressionCodegenExtension.registerExtension(project, CliNoArgExpressionCodegenExtension(annotations, invokeInitializers))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CliNoArgComponentContainerContributor(val annotations: List<String>) : StorageComponentContainerContributor {
|
||||
private class CliNoArgComponentContainerContributor(
|
||||
private val annotations: List<String>,
|
||||
private val useIr: Boolean,
|
||||
) : StorageComponentContainerContributor {
|
||||
override fun registerModuleComponents(
|
||||
container: StorageComponentContainer, platform: TargetPlatform, moduleDescriptor: ModuleDescriptor
|
||||
) {
|
||||
if (!platform.isJvm()) return
|
||||
|
||||
container.useInstance(CliNoArgDeclarationChecker(annotations))
|
||||
container.useInstance(CliNoArgDeclarationChecker(annotations, useIr))
|
||||
}
|
||||
}
|
||||
|
||||
+23
-7
@@ -16,32 +16,48 @@
|
||||
|
||||
package org.jetbrains.kotlin.noarg.diagnostic
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.extensions.AnnotationBasedExtension
|
||||
import org.jetbrains.kotlin.noarg.diagnostic.ErrorsNoArg.*
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
|
||||
class CliNoArgDeclarationChecker(private val noArgAnnotationFqNames: List<String>) : AbstractNoArgDeclarationChecker() {
|
||||
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?) = noArgAnnotationFqNames
|
||||
internal class CliNoArgDeclarationChecker(
|
||||
private val noArgAnnotationFqNames: List<String>,
|
||||
useIr: Boolean,
|
||||
) : AbstractNoArgDeclarationChecker(useIr) {
|
||||
override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?): List<String> = noArgAnnotationFqNames
|
||||
}
|
||||
|
||||
abstract class AbstractNoArgDeclarationChecker : DeclarationChecker, AnnotationBasedExtension {
|
||||
internal abstract class AbstractNoArgDeclarationChecker(private val useIr: Boolean) : DeclarationChecker, AnnotationBasedExtension {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
// Handle only classes
|
||||
if (descriptor !is ClassDescriptor || declaration !is KtClass) return
|
||||
if (descriptor.kind != ClassKind.CLASS) return
|
||||
if (!descriptor.hasSpecialAnnotation(declaration)) return
|
||||
|
||||
if (descriptor.isInner) {
|
||||
val diagnostic = if (useIr) NOARG_ON_INNER_CLASS_ERROR else NOARG_ON_INNER_CLASS
|
||||
context.trace.report(diagnostic.on(declaration.reportTarget))
|
||||
} else if (DescriptorUtils.isLocal(descriptor)) {
|
||||
val diagnostic = if (useIr) NOARG_ON_LOCAL_CLASS_ERROR else NOARG_ON_LOCAL_CLASS
|
||||
context.trace.report(diagnostic.on(declaration.reportTarget))
|
||||
}
|
||||
|
||||
val superClass = descriptor.getSuperClassOrAny()
|
||||
if (superClass.constructors.none { it.isNoArgConstructor() } && !superClass.hasSpecialAnnotation(declaration)) {
|
||||
val reportTarget = declaration.nameIdentifier ?: declaration.getClassOrInterfaceKeyword() ?: declaration
|
||||
context.trace.report(ErrorsNoArg.NO_NOARG_CONSTRUCTOR_IN_SUPERCLASS.on(reportTarget))
|
||||
context.trace.report(NO_NOARG_CONSTRUCTOR_IN_SUPERCLASS.on(declaration.reportTarget))
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConstructorDescriptor.isNoArgConstructor() = valueParameters.all(ValueParameterDescriptor::declaresDefaultValue)
|
||||
private val KtClass.reportTarget: PsiElement
|
||||
get() = nameIdentifier ?: getClassOrInterfaceKeyword() ?: this
|
||||
|
||||
private fun ConstructorDescriptor.isNoArgConstructor(): Boolean =
|
||||
valueParameters.all(ValueParameterDescriptor::declaresDefaultValue)
|
||||
}
|
||||
|
||||
+11
-1
@@ -25,5 +25,15 @@ object DefaultErrorMessagesNoArg : DefaultErrorMessages.Extension {
|
||||
|
||||
init {
|
||||
MAP.put(ErrorsNoArg.NO_NOARG_CONSTRUCTOR_IN_SUPERCLASS, "Zero-argument constructor was not found in the superclass")
|
||||
MAP.put(
|
||||
ErrorsNoArg.NOARG_ON_INNER_CLASS,
|
||||
"Noarg constructor generation for inner classes is deprecated and will be prohibited soon"
|
||||
)
|
||||
MAP.put(ErrorsNoArg.NOARG_ON_INNER_CLASS_ERROR, "Noarg constructor generation is not possible for inner classes")
|
||||
MAP.put(
|
||||
ErrorsNoArg.NOARG_ON_LOCAL_CLASS,
|
||||
"Noarg constructor generation for local classes is deprecated and will be prohibited soon"
|
||||
)
|
||||
MAP.put(ErrorsNoArg.NOARG_ON_LOCAL_CLASS_ERROR, "Noarg constructor generation is not possible for local classes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,15 @@ import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
|
||||
import static org.jetbrains.kotlin.diagnostics.Severity.ERROR;
|
||||
import static org.jetbrains.kotlin.diagnostics.Severity.WARNING;
|
||||
|
||||
public interface ErrorsNoArg {
|
||||
DiagnosticFactory0<PsiElement> NO_NOARG_CONSTRUCTOR_IN_SUPERCLASS = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> NOARG_ON_INNER_CLASS = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> NOARG_ON_INNER_CLASS_ERROR = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> NOARG_ON_LOCAL_CLASS = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> NOARG_ON_LOCAL_CLASS_ERROR = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
Object _initializer = new Object() {
|
||||
@@ -31,5 +36,4 @@ public interface ErrorsNoArg {
|
||||
Errors.Initializer.initializeFactoryNamesAndDefaultErrorMessages(ErrorsNoArg.class, DefaultErrorMessagesNoArg.INSTANCE);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user