- 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:
Dmitry Petrov
2015-10-26 17:07:45 +03:00
parent 4fcd35a5a9
commit 09f0b3fe87
10 changed files with 48 additions and 124 deletions
@@ -370,7 +370,6 @@ public class KotlinCoreEnvironment private constructor(
with (projectEnvironment.getProject()) {
registerService(javaClass<JetScriptDefinitionProvider>(), JetScriptDefinitionProvider())
registerService(javaClass<KotlinJavaPsiFacade>(), KotlinJavaPsiFacade(this))
registerService(javaClass<KotlinLightClassForFacade.PackageFacadeStubCache>(), KotlinLightClassForFacade.PackageFacadeStubCache(this))
registerService(javaClass<KotlinLightClassForFacade.FacadeStubCache>(), KotlinLightClassForFacade.FacadeStubCache(this))
}
}
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.fileClasses
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
@@ -70,88 +70,6 @@ import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToD
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
public static CachedValueProvider<KotlinFacadeLightClassData> createForFacadeClass(
@NotNull final Project project,
@@ -219,7 +137,7 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
public void generate(@NotNull GenerationState state, @NotNull Collection<KtFile> files) {
if (!files.isEmpty()) {
KtFile representativeFile = files.iterator().next();
JvmFileClassInfo fileClassInfo = NoResolveFileClassesProvider.INSTANCE$.getFileClassInfo(representativeFile);
JvmFileClassInfo fileClassInfo = NoResolveFileClassesProvider.INSTANCE.getFileClassInfo(representativeFile);
if (!fileClassInfo.getWithJvmMultifileClass()) {
PackageCodegen codegen = state.getFactory().forPackage(representativeFile.getPackageFqName(), files);
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION);
@@ -46,33 +46,6 @@ public class KotlinLightClassForFacade private constructor(
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) {
private inner class FacadeCacheData {
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.Nullable;
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.org.objectweb.asm.ClassVisitor;
import org.jetbrains.org.objectweb.asm.FieldVisitor;
@@ -47,6 +50,7 @@ public class StubClassBuilder extends AbstractClassBuilder {
private final StubElement parent;
private StubBuildingVisitor v;
private final Stack<StubElement> parentStack;
private boolean isPackageClass = false;
public StubClassBuilder(@NotNull Stack<StubElement> parentStack) {
this.parentStack = parentStack;
@@ -75,7 +79,18 @@ public class StubClassBuilder extends AbstractClassBuilder {
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);
}
@@ -134,8 +149,10 @@ public class StubClassBuilder extends AbstractClassBuilder {
@Override
public void done() {
StubElement pop = parentStack.pop();
assert pop == v.getResult();
if (!isPackageClass) {
StubElement pop = parentStack.pop();
assert pop == v.getResult() : "parentStack: got " + pop + ", expected " + v.getResult();
}
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.DiagnosticFactory.*
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
public fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Diagnostics, moduleScope: GlobalSearchScope): Diagnostics? {
fun getDiagnosticsForPackage(file: KtFile): Diagnostics? {
val project = file.getProject()
val cache = KotlinLightClassForFacade.PackageFacadeStubCache.getInstance(project)
return cache[file.getPackageFqName(), moduleScope].getValue()?.extraDiagnostics
fun getDiagnosticsForFileFacade(file: KtFile): Diagnostics? {
val project = file.project
val cache = KotlinLightClassForFacade.FacadeStubCache.getInstance(project)
val facadeFqName = NoResolveFileClassesProvider.getFileClassInfo(file).facadeClassFqName
return cache[facadeFqName, moduleScope].getValue()?.extraDiagnostics
}
fun getDiagnosticsForClass(ktClassOrObject: KtClassOrObject): Diagnostics {
@@ -58,7 +60,7 @@ public fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Dia
when (parent) {
is KtFile -> {
return getDiagnosticsForPackage(parent)
return getDiagnosticsForFileFacade(parent)
}
is KtClassBody -> {
val parentsParent = parent.getParent()
@@ -31,7 +31,7 @@ public final class PackageClassUtils {
// ex. <root> -> _DefaultPackage, a -> APackage, a.b -> BPackage
@NotNull
private static String getPackageClassName(@NotNull FqName packageFQN) {
public static String getPackageClassName(@NotNull FqName packageFQN) {
if (packageFQN.isRoot()) {
return DEFAULT_PACKAGE_CLASS_NAME;
}
-3
View File
@@ -246,9 +246,6 @@
<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"
serviceImplementation="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$FacadeStubCache"/>
@@ -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);
}
@TestMetadata("topLevelMultifileRuntime.kt")
public void testTopLevelMultifileRuntime() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/checker/duplicateJvmSignature/functionAndProperty/topLevelMultifileRuntime.kt");
doTest(fileName);
}
@TestMetadata("trait.kt")
public void testTrait() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/checker/duplicateJvmSignature/functionAndProperty/trait.kt");