KT-9721:
- Kotlin/JS still uses package facades. Handle them properly in StubClassBuilder parentStack. - Generate backend-related diagnostics in IDE using light class generation for file facades. - Drop PackageFacadeStubCache.
This commit is contained in:
@@ -370,7 +370,6 @@ public class KotlinCoreEnvironment private constructor(
|
|||||||
with (projectEnvironment.getProject()) {
|
with (projectEnvironment.getProject()) {
|
||||||
registerService(javaClass<JetScriptDefinitionProvider>(), JetScriptDefinitionProvider())
|
registerService(javaClass<JetScriptDefinitionProvider>(), JetScriptDefinitionProvider())
|
||||||
registerService(javaClass<KotlinJavaPsiFacade>(), KotlinJavaPsiFacade(this))
|
registerService(javaClass<KotlinJavaPsiFacade>(), KotlinJavaPsiFacade(this))
|
||||||
registerService(javaClass<KotlinLightClassForFacade.PackageFacadeStubCache>(), KotlinLightClassForFacade.PackageFacadeStubCache(this))
|
|
||||||
registerService(javaClass<KotlinLightClassForFacade.FacadeStubCache>(), KotlinLightClassForFacade.FacadeStubCache(this))
|
registerService(javaClass<KotlinLightClassForFacade.FacadeStubCache>(), KotlinLightClassForFacade.FacadeStubCache(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fileClasses
|
package org.jetbrains.kotlin.fileClasses
|
||||||
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-83
@@ -70,88 +70,6 @@ import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToD
|
|||||||
|
|
||||||
public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostics> implements CachedValueProvider<T> {
|
public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostics> implements CachedValueProvider<T> {
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static KotlinJavaFileStubProvider<KotlinFacadeLightClassData> createForPackageClass(
|
|
||||||
@NotNull final Project project,
|
|
||||||
@NotNull final FqName packageFqName,
|
|
||||||
@NotNull final GlobalSearchScope searchScope
|
|
||||||
) {
|
|
||||||
return new KotlinJavaFileStubProvider<KotlinFacadeLightClassData>(
|
|
||||||
project,
|
|
||||||
false,
|
|
||||||
new StubGenerationStrategy<KotlinFacadeLightClassData>() {
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public LightClassConstructionContext getContext(@NotNull Collection<KtFile> files) {
|
|
||||||
return LightClassGenerationSupport.getInstance(project).getContextForPackage(files);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Collection<KtFile> getFiles() {
|
|
||||||
// Don't memoize this, it can be called again after an out-of-code-block modification occurs,
|
|
||||||
// and the set of files changes
|
|
||||||
return LightClassGenerationSupport.getInstance(project).findFilesForPackage(packageFqName, searchScope);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public KotlinFacadeLightClassData createLightClassData(
|
|
||||||
PsiJavaFileStub javaFileStub,
|
|
||||||
BindingContext bindingContext,
|
|
||||||
Diagnostics extraDiagnostics
|
|
||||||
) {
|
|
||||||
return new KotlinFacadeLightClassData(javaFileStub, extraDiagnostics);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public FqName getPackageFqName() {
|
|
||||||
return packageFqName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GenerationState.GenerateClassFilter getGenerateClassFilter() {
|
|
||||||
return new GenerationState.GenerateClassFilter() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldGeneratePackagePart(KtFile jetFile) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldAnnotateClass(KtClassOrObject classOrObject) {
|
|
||||||
return shouldGenerateClass(classOrObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldGenerateClass(KtClassOrObject classOrObject) {
|
|
||||||
// Top-level classes and such should not be generated for performance reasons.
|
|
||||||
// Local classes in top-level functions must still be generated
|
|
||||||
return KtPsiUtil.isLocal(classOrObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldGenerateScript(KtScript script) {
|
|
||||||
// Scripts yield top-level classes, and should not be generated
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void generate(@NotNull GenerationState state, @NotNull Collection<KtFile> files) {
|
|
||||||
KotlinCodegenFacade.doGenerateFiles(files, state, CompilationErrorHandler.THROW_EXCEPTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return StubGenerationStrategy.class.getName() + " for package class";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static CachedValueProvider<KotlinFacadeLightClassData> createForFacadeClass(
|
public static CachedValueProvider<KotlinFacadeLightClassData> createForFacadeClass(
|
||||||
@NotNull final Project project,
|
@NotNull final Project project,
|
||||||
@@ -219,7 +137,7 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
|
|||||||
public void generate(@NotNull GenerationState state, @NotNull Collection<KtFile> files) {
|
public void generate(@NotNull GenerationState state, @NotNull Collection<KtFile> files) {
|
||||||
if (!files.isEmpty()) {
|
if (!files.isEmpty()) {
|
||||||
KtFile representativeFile = files.iterator().next();
|
KtFile representativeFile = files.iterator().next();
|
||||||
JvmFileClassInfo fileClassInfo = NoResolveFileClassesProvider.INSTANCE$.getFileClassInfo(representativeFile);
|
JvmFileClassInfo fileClassInfo = NoResolveFileClassesProvider.INSTANCE.getFileClassInfo(representativeFile);
|
||||||
if (!fileClassInfo.getWithJvmMultifileClass()) {
|
if (!fileClassInfo.getWithJvmMultifileClass()) {
|
||||||
PackageCodegen codegen = state.getFactory().forPackage(representativeFile.getPackageFqName(), files);
|
PackageCodegen codegen = state.getFactory().forPackage(representativeFile.getPackageFqName(), files);
|
||||||
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION);
|
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION);
|
||||||
|
|||||||
@@ -46,33 +46,6 @@ public class KotlinLightClassForFacade private constructor(
|
|||||||
|
|
||||||
private data class StubCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope)
|
private data class StubCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope)
|
||||||
|
|
||||||
public class PackageFacadeStubCache(private val project: Project) {
|
|
||||||
private inner class PackageFacadeCacheData {
|
|
||||||
val cache = object : SLRUCache<StubCacheKey, CachedValue<KotlinFacadeLightClassData>>(20, 30) {
|
|
||||||
override fun createValue(key: StubCacheKey): CachedValue<KotlinFacadeLightClassData> {
|
|
||||||
val stubProvider = KotlinJavaFileStubProvider.createForPackageClass(project, key.fqName, key.searchScope)
|
|
||||||
return CachedValuesManager.getManager(project).createCachedValue<KotlinFacadeLightClassData>(stubProvider, /*trackValue = */false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val cachedValue: CachedValue<PackageFacadeCacheData> = CachedValuesManager.getManager(project).createCachedValue<PackageFacadeCacheData>(
|
|
||||||
{ CachedValueProvider.Result.create(PackageFacadeCacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) },
|
|
||||||
/*trackValue = */ false)
|
|
||||||
|
|
||||||
public fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue<KotlinFacadeLightClassData> {
|
|
||||||
synchronized (cachedValue) {
|
|
||||||
return cachedValue.getValue().cache.get(StubCacheKey(qualifiedName, searchScope))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
public fun getInstance(project: Project): PackageFacadeStubCache {
|
|
||||||
return ServiceManager.getService<PackageFacadeStubCache>(project, javaClass<PackageFacadeStubCache>())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FacadeStubCache(private val project: Project) {
|
public class FacadeStubCache(private val project: Project) {
|
||||||
private inner class FacadeCacheData {
|
private inner class FacadeCacheData {
|
||||||
val cache = object : SLRUCache<StubCacheKey, CachedValue<KotlinFacadeLightClassData>>(20, 30) {
|
val cache = object : SLRUCache<StubCacheKey, CachedValue<KotlinFacadeLightClassData>>(20, 30) {
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ import com.intellij.util.containers.Stack;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.codegen.AbstractClassBuilder;
|
import org.jetbrains.kotlin.codegen.AbstractClassBuilder;
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
|
||||||
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||||
import org.jetbrains.org.objectweb.asm.ClassVisitor;
|
import org.jetbrains.org.objectweb.asm.ClassVisitor;
|
||||||
import org.jetbrains.org.objectweb.asm.FieldVisitor;
|
import org.jetbrains.org.objectweb.asm.FieldVisitor;
|
||||||
@@ -47,6 +50,7 @@ public class StubClassBuilder extends AbstractClassBuilder {
|
|||||||
private final StubElement parent;
|
private final StubElement parent;
|
||||||
private StubBuildingVisitor v;
|
private StubBuildingVisitor v;
|
||||||
private final Stack<StubElement> parentStack;
|
private final Stack<StubElement> parentStack;
|
||||||
|
private boolean isPackageClass = false;
|
||||||
|
|
||||||
public StubClassBuilder(@NotNull Stack<StubElement> parentStack) {
|
public StubClassBuilder(@NotNull Stack<StubElement> parentStack) {
|
||||||
this.parentStack = parentStack;
|
this.parentStack = parentStack;
|
||||||
@@ -75,7 +79,18 @@ public class StubClassBuilder extends AbstractClassBuilder {
|
|||||||
|
|
||||||
super.defineClass(origin, version, access, name, signature, superName, interfaces);
|
super.defineClass(origin, version, access, name, signature, superName, interfaces);
|
||||||
|
|
||||||
parentStack.push(v.getResult());
|
if (origin instanceof KtFile) {
|
||||||
|
FqName packageName = ((KtFile) origin).getPackageFqName();
|
||||||
|
String packageClassName = PackageClassUtils.getPackageClassName(packageName);
|
||||||
|
|
||||||
|
if (name.equals(packageClassName) || name.endsWith("/" + packageClassName)) {
|
||||||
|
isPackageClass = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPackageClass) {
|
||||||
|
parentStack.push(v.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
((StubBase) v.getResult()).putUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT, origin);
|
((StubBase) v.getResult()).putUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT, origin);
|
||||||
}
|
}
|
||||||
@@ -134,8 +149,10 @@ public class StubClassBuilder extends AbstractClassBuilder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void done() {
|
public void done() {
|
||||||
StubElement pop = parentStack.pop();
|
if (!isPackageClass) {
|
||||||
assert pop == v.getResult();
|
StubElement pop = parentStack.pop();
|
||||||
|
assert pop == v.getResult() : "parentStack: got " + pop + ", expected " + v.getResult();
|
||||||
|
}
|
||||||
super.done();
|
super.done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,14 +26,16 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.*
|
|||||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory.*
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory.*
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||||
|
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||||
|
|
||||||
public fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Diagnostics, moduleScope: GlobalSearchScope): Diagnostics? {
|
public fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Diagnostics, moduleScope: GlobalSearchScope): Diagnostics? {
|
||||||
fun getDiagnosticsForPackage(file: KtFile): Diagnostics? {
|
fun getDiagnosticsForFileFacade(file: KtFile): Diagnostics? {
|
||||||
val project = file.getProject()
|
val project = file.project
|
||||||
val cache = KotlinLightClassForFacade.PackageFacadeStubCache.getInstance(project)
|
val cache = KotlinLightClassForFacade.FacadeStubCache.getInstance(project)
|
||||||
return cache[file.getPackageFqName(), moduleScope].getValue()?.extraDiagnostics
|
val facadeFqName = NoResolveFileClassesProvider.getFileClassInfo(file).facadeClassFqName
|
||||||
|
return cache[facadeFqName, moduleScope].getValue()?.extraDiagnostics
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDiagnosticsForClass(ktClassOrObject: KtClassOrObject): Diagnostics {
|
fun getDiagnosticsForClass(ktClassOrObject: KtClassOrObject): Diagnostics {
|
||||||
@@ -58,7 +60,7 @@ public fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Dia
|
|||||||
|
|
||||||
when (parent) {
|
when (parent) {
|
||||||
is KtFile -> {
|
is KtFile -> {
|
||||||
return getDiagnosticsForPackage(parent)
|
return getDiagnosticsForFileFacade(parent)
|
||||||
}
|
}
|
||||||
is KtClassBody -> {
|
is KtClassBody -> {
|
||||||
val parentsParent = parent.getParent()
|
val parentsParent = parent.getParent()
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ public final class PackageClassUtils {
|
|||||||
|
|
||||||
// ex. <root> -> _DefaultPackage, a -> APackage, a.b -> BPackage
|
// ex. <root> -> _DefaultPackage, a -> APackage, a.b -> BPackage
|
||||||
@NotNull
|
@NotNull
|
||||||
private static String getPackageClassName(@NotNull FqName packageFQN) {
|
public static String getPackageClassName(@NotNull FqName packageFQN) {
|
||||||
if (packageFQN.isRoot()) {
|
if (packageFQN.isRoot()) {
|
||||||
return DEFAULT_PACKAGE_CLASS_NAME;
|
return DEFAULT_PACKAGE_CLASS_NAME;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,9 +246,6 @@
|
|||||||
|
|
||||||
<projectService serviceImplementation="org.jetbrains.kotlin.idea.versions.SuppressNotificationState"/>
|
<projectService serviceImplementation="org.jetbrains.kotlin.idea.versions.SuppressNotificationState"/>
|
||||||
|
|
||||||
<projectService serviceInterface="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$PackageFacadeStubCache"
|
|
||||||
serviceImplementation="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$PackageFacadeStubCache"/>
|
|
||||||
|
|
||||||
<projectService serviceInterface="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$FacadeStubCache"
|
<projectService serviceInterface="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$FacadeStubCache"
|
||||||
serviceImplementation="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$FacadeStubCache"/>
|
serviceImplementation="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$FacadeStubCache"/>
|
||||||
|
|
||||||
|
|||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
@file:JvmName("TopLevelMultifile")
|
||||||
|
@file:JvmMultifileClass
|
||||||
|
package test
|
||||||
|
|
||||||
|
import kotlin.jvm.JvmName
|
||||||
|
import kotlin.jvm.JvmMultifileClass
|
||||||
|
|
||||||
|
<error descr="[CONFLICTING_JVM_DECLARATIONS] Platform declaration clash: The following declarations have the same JVM signature (getX()I):
|
||||||
|
fun <get-x>(): kotlin.Int
|
||||||
|
fun getX(): kotlin.Int">val x</error> = 1
|
||||||
|
<error descr="[CONFLICTING_JVM_DECLARATIONS] Platform declaration clash: The following declarations have the same JVM signature (getX()I):
|
||||||
|
fun <get-x>(): kotlin.Int
|
||||||
|
fun getX(): kotlin.Int">fun getX()</error> = 1
|
||||||
@@ -630,6 +630,12 @@ public class JetPsiCheckerTestGenerated extends AbstractJetPsiCheckerTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("topLevelMultifileRuntime.kt")
|
||||||
|
public void testTopLevelMultifileRuntime() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/checker/duplicateJvmSignature/functionAndProperty/topLevelMultifileRuntime.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("trait.kt")
|
@TestMetadata("trait.kt")
|
||||||
public void testTrait() throws Exception {
|
public void testTrait() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/checker/duplicateJvmSignature/functionAndProperty/trait.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/checker/duplicateJvmSignature/functionAndProperty/trait.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user