FIR: introduce Java vs Kotlin class conflicts checker #KT-44441 Fixed

This commit is contained in:
Mikhail Glukhikh
2022-07-01 16:47:35 +02:00
committed by Space
parent d94d832309
commit 730a5d1a88
12 changed files with 231 additions and 11 deletions
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fir.analysis.checkersComponent
import org.jetbrains.kotlin.fir.analysis.extensions.additionalCheckers
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper
import org.jetbrains.kotlin.fir.extensions.*
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirDependenciesSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
@@ -120,6 +121,7 @@ internal object LLFirSessionFactory {
}
}
val javaSymbolProvider = createJavaSymbolProvider(this, moduleData, project, contentScope)
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
@@ -128,10 +130,11 @@ internal object LLFirSessionFactory {
providers = listOfNotNull(
provider.symbolProvider,
switchableExtensionDeclarationsSymbolProvider,
createJavaSymbolProvider(this, moduleData, project, contentScope)
javaSymbolProvider,
),
)
)
register(JavaSymbolProvider::class, javaSymbolProvider)
register(FirDependenciesSymbolProvider::class, dependencyProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
@@ -210,6 +213,7 @@ internal object LLFirSessionFactory {
)
}
val javaSymbolProvider = createJavaSymbolProvider(this, moduleData, project, contentScope)
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
@@ -217,10 +221,11 @@ internal object LLFirSessionFactory {
dependencyProvider,
providers = listOf(
provider.symbolProvider,
createJavaSymbolProvider(this, moduleData, project, contentScope),
javaSymbolProvider,
),
)
)
register(JavaSymbolProvider::class, javaSymbolProvider)
register(FirDependenciesSymbolProvider::class, dependencyProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
@@ -28,7 +28,8 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
override val regularClassCheckers: Set<FirRegularClassChecker>
get() = setOf(
FirJvmRecordChecker,
FirJvmInlineApplicabilityChecker
FirJvmInlineApplicabilityChecker,
FirJvmConflictsChecker,
)
override val propertyCheckers: Set<FirPropertyChecker>
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.fir.analysis.jvm.checkers.declaration
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirRegularClassChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.java.javaSymbolProvider
object FirJvmConflictsChecker : FirRegularClassChecker() {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
val javaSymbol = context.session.javaSymbolProvider.getClassLikeSymbolByClassId(declaration.classId) ?: return
reporter.reportOn(
declaration.source, FirErrors.PACKAGE_OR_CLASSIFIER_REDECLARATION, listOf(declaration.symbol, javaSymbol), context
)
}
}
@@ -5,9 +5,6 @@
package org.jetbrains.kotlin.fir.session
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.KtPsiSourceElement
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.config.JvmAnalysisFlags
import org.jetbrains.kotlin.config.LanguageVersionSettings
@@ -30,7 +27,6 @@ import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticNamesProvider
import org.jetbrains.kotlin.fir.resolve.calls.jvm.JvmCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirQualifierResolverImpl
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirTypeResolverImpl
import org.jetbrains.kotlin.fir.resolve.transformers.FirPhaseCheckingPhaseManager
@@ -197,6 +197,7 @@ object FirSessionFactory {
val dependenciesSymbolProvider = FirDependenciesSymbolProviderImpl(this)
val generatedSymbolsProvider = FirSwitchableExtensionDeclarationsSymbolProvider.create(this)
val javaSymbolProvider = JavaSymbolProvider(this, projectEnvironment.getFirJavaFacade(this, moduleData, javaSourcesScope))
register(
FirSymbolProvider::class,
FirCompositeSymbolProvider(
@@ -206,12 +207,13 @@ object FirSessionFactory {
*(incrementalCompilationContext?.previousFirSessionsSymbolProviders?.toTypedArray() ?: emptyArray()),
symbolProviderForBinariesFromIncrementalCompilation,
generatedSymbolsProvider,
JavaSymbolProvider(this, projectEnvironment.getFirJavaFacade(this, moduleData, javaSourcesScope)),
javaSymbolProvider,
dependenciesSymbolProvider,
optionalAnnotationClassesProviderForBinariesFromIncrementalCompilation,
)
)
)
register(JavaSymbolProvider::class, javaSymbolProvider)
generatedSymbolsProvider?.let { register(FirSwitchableExtensionDeclarationsSymbolProvider::class, it) }
@@ -57,3 +57,6 @@ class JavaSymbolProvider(
@OptIn(FirSymbolProviderInternals::class)
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) {}
}
val FirSession.javaSymbolProvider: JavaSymbolProvider by FirSession.sessionComponentAccessor()
@@ -0,0 +1,89 @@
// SOURCE_RETENTION_ANNOTATIONS
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: strict
// FILE: spr/Nullable.java
package spr;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Target({ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull(when = When.MAYBE)
@TypeQualifierNickname
public @interface Nullable {
}
// FILE: spr/NotNull.java
package spr;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierNickname
public @interface NotNull {
}
// FILE: J1.java
import spr.*;
public interface J1<T> {
@Nullable
T getFoo();
}
// FILE: J2.java
import spr.*;
public class J2 implements J1<String> {
@NotNull
public String getFoo() { return ""; }
}
// FILE: Nonnull.kt
package spr
import javax.annotation.meta.TypeQualifierNickname
import javax.annotation.Nonnull;
// This is a crucial part: NotNull defined in Java has no TYPE_USE target, so it has been applied only to the method
// While on use-site (main.kt) spr.NotNull shall be resolved to Kotlin version with TYPE among target
// So, even while our annotation is type use, we still should consider situation when it's applied to the method/parameter, but not to type
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.TYPE,
)
@Retention(AnnotationRetention.RUNTIME)
@Nonnull
@TypeQualifierNickname
annotation class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>NotNull<!>
// FILE: main.kt
fun bar(j2: J2) {
j2.foo.length // `j2.foo` is not nullable
}
@@ -1,4 +1,4 @@
// FIR_IDENTICAL
// SOURCE_RETENTION_ANNOTATIONS
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: strict
@@ -0,0 +1,89 @@
// SOURCE_RETENTION_ANNOTATIONS
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: strict
// !LANGUAGE: +TypeEnhancementImprovementsInStrictMode
// FILE: spr/Nullable.java
package spr;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Target({ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull(when = When.MAYBE)
@TypeQualifierNickname
public @interface Nullable {
}
// FILE: spr/NotNull.java
package spr;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierNickname
public @interface NotNull {
}
// FILE: J1.java
import spr.*;
public interface J1<T> {
T @Nullable [] getFoo();
}
// FILE: J2.java
import spr.*;
public class J2 implements J1<String> {
@NotNull
public String[] getFoo() { return null; }
}
// FILE: Nonnull.kt
package spr
import javax.annotation.meta.TypeQualifierNickname
import javax.annotation.Nonnull;
// This is a crucial part: NotNull defined in Java has no TYPE_USE target, so it has been applied only to the method
// While on use-site (main.kt) spr.NotNull shall be resolved to Kotlin version with TYPE among target
// So, even while our annotation is type use, we still should consider situation when it's applied to the method/parameter, but not to type
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.TYPE,
)
@Retention(AnnotationRetention.RUNTIME)
@Nonnull
@TypeQualifierNickname
annotation class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>NotNull<!>
// FILE: main.kt
fun bar(j2: J2) {
j2.foo<!UNSAFE_CALL!>.<!>get(0).length // `j2.foo` is not nullable
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// SOURCE_RETENTION_ANNOTATIONS
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: strict
@@ -0,0 +1,13 @@
// FILE: Hello.kt
private class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>Hello<!>()
{
val a = 4
}
fun test() {
// no exception is thrown (see KT-3897)
Hello().a
}
// FILE: Hello.java
public class Hello {}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// FILE: Hello.kt
private class Hello()
{