Report "declaration should be marked with impl" when possible
Also support a quick fix to add 'impl' modifier (KT-18454), although it doesn't work yet on classes because there's no error on them in the IDE #KT-18087 Fixed #KT-18452 Fixed #KT-18454
This commit is contained in:
@@ -570,6 +570,7 @@ public interface Errors {
|
||||
DiagnosticFactory2<KtDeclaration, ClassDescriptor,
|
||||
List<Pair<CallableMemberDescriptor, Map<Incompatible, Collection<CallableMemberDescriptor>>>>> HEADER_CLASS_MEMBERS_ARE_NOT_IMPLEMENTED =
|
||||
DiagnosticFactory2.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtDeclaration> IMPL_MISSING = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
+1
@@ -277,6 +277,7 @@ public class DefaultErrorMessages {
|
||||
|
||||
MAP.put(HEADER_CLASS_MEMBERS_ARE_NOT_IMPLEMENTED, "''impl'' class ''{0}'' has no implementation of ''header'' class members:{1}",
|
||||
NAME, IncompatibleHeaderImplClassScopesRenderer.INSTANCE);
|
||||
MAP.put(IMPL_MISSING, "Declaration should be marked with 'impl' (suppress with -Xno-check-impl)");
|
||||
|
||||
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
|
||||
MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here");
|
||||
|
||||
+16
-7
@@ -63,11 +63,13 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
||||
if (descriptor !is MemberDescriptor) return
|
||||
|
||||
val checkImpl = !languageVersionSettings.getFlag(AnalysisFlag.multiPlatformDoNotCheckImpl)
|
||||
if (descriptor.isHeader && declaration.hasModifier(KtTokens.HEADER_KEYWORD)) {
|
||||
checkHeaderDeclarationHasImplementation(declaration, descriptor, diagnosticHolder, descriptor.module, checkImpl)
|
||||
if (descriptor.isHeader) {
|
||||
if (declaration.hasModifier(KtTokens.HEADER_KEYWORD)) {
|
||||
checkHeaderDeclarationHasImplementation(declaration, descriptor, diagnosticHolder, descriptor.module, checkImpl)
|
||||
}
|
||||
}
|
||||
else if (checkImpl && descriptor.isImpl && declaration.hasModifier(KtTokens.IMPL_KEYWORD)) {
|
||||
checkImplementationHasHeaderDeclaration(declaration, descriptor, diagnosticHolder)
|
||||
else {
|
||||
checkImplementationHasHeaderDeclaration(declaration, descriptor, diagnosticHolder, checkImpl)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,13 +125,20 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
|
||||
private fun checkImplementationHasHeaderDeclaration(
|
||||
reportOn: KtDeclaration, descriptor: MemberDescriptor, diagnosticHolder: DiagnosticSink
|
||||
reportOn: KtDeclaration, descriptor: MemberDescriptor, diagnosticHolder: DiagnosticSink, checkImpl: Boolean
|
||||
) {
|
||||
// Using the platform module instead of the common module is sort of fine here because the former always depends on the latter.
|
||||
// However, it would be clearer to find the common module this platform module implements and look for headers there instead.
|
||||
// TODO: use common module here
|
||||
val compatibility = findHeaderForImpl(descriptor, descriptor.module) ?: return
|
||||
|
||||
if (!descriptor.isImpl || !reportOn.hasModifier(KtTokens.IMPL_KEYWORD)) {
|
||||
if (checkImpl && (Compatible in compatibility || Incompatible.NoImpl in compatibility)) {
|
||||
diagnosticHolder.report(Errors.IMPL_MISSING.on(reportOn))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 'firstOrNull' is needed because in diagnostic tests, common sources appear twice, so the same class is duplicated
|
||||
// TODO: replace with 'singleOrNull' as soon as multi-module diagnostic tests are refactored
|
||||
val singleIncompatibility = compatibility.keys.firstOrNull()
|
||||
@@ -173,7 +182,7 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
||||
DescriptorToSourceUtils.getSourceFromDescriptor(this) is KtConstructor<*>
|
||||
}
|
||||
else {
|
||||
isImpl && kind == CallableMemberDescriptor.Kind.DECLARATION
|
||||
kind == CallableMemberDescriptor.Kind.DECLARATION
|
||||
}
|
||||
|
||||
private fun findHeaderForImpl(impl: MemberDescriptor, commonModule: ModuleDescriptor): Map<Compatibility, List<MemberDescriptor>>? {
|
||||
@@ -201,7 +210,7 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
||||
Substitutor(headerClass.declaredTypeParameters, container.declaredTypeParameters)
|
||||
}
|
||||
else null
|
||||
areCompatibleCallables(declaration, impl, checkImpl = false, parentSubstitutor = substitutor)
|
||||
areCompatibleCallables(declaration, impl, checkImpl = true, parentSubstitutor = substitutor)
|
||||
}
|
||||
}
|
||||
is ClassifierDescriptorWithTypeParameters -> {
|
||||
|
||||
Reference in New Issue
Block a user