From 5ca8f7409aec22845b1671ec66bb09ff76eac897 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 1 Sep 2015 17:31:43 +0300 Subject: [PATCH] Fix debugger tests. - Index binaries by facade class fqName - Fix DebuggerUtils: should understand new facades - Refactor IDELightClassGenerationSupport - Add facadeSimpleName to KotlinFileStub --- .../load/kotlin/PackagePartClassUtils.kt | 4 +- .../kotlin/psi/stubs/StubInterfaces.kt | 1 + .../stubs/elements/JetFileElementType.java | 4 +- .../psi/stubs/impl/KotlinFileStubImpl.kt | 27 +++- .../IDELightClassGenerationSupport.java | 115 ++++++++++-------- .../stubBuilder/KotlinClsStubBuilder.kt | 4 +- .../KotlinJavaScriptStubBuilder.kt | 2 +- .../decompiler/stubBuilder/clsStubBuilding.kt | 28 ++++- .../stubindex/JetStaticFacadeClassIndex.kt | 4 +- .../idea/stubindex/StaticFacadeIndexUtil.kt | 11 +- .../idea/stubindex/StubIndexServiceImpl.java | 14 ++- .../idea/filters/JetExceptionFilter.java | 29 ++--- .../kotlin/idea/util/DebuggerUtils.java | 30 ++++- .../filters/exceptionFilter/kotlinClass/a.kt | 5 + .../idea/filters/JetExceptionFilterTest.kt | 5 + 15 files changed, 185 insertions(+), 98 deletions(-) create mode 100644 idea/testData/filters/exceptionFilter/kotlinClass/a.kt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt index 3fb0acb4f4d..38001ec8965 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt @@ -59,7 +59,7 @@ import java.util.* getPackagePartFqName(facadeClassFqName.parent(), file.name) public @jvmStatic fun getPackagePartFqName(packageFqName: FqName, fileName: String): FqName { - val partClassName = getPartClassName(FileUtil.getNameWithoutExtension(fileName)) + val partClassName = getFilePartShortName(fileName) return packageFqName.child(Name.identifier(partClassName)) } @@ -91,4 +91,6 @@ import java.util.* public @jvmStatic fun getFilesForPart(partFqName: FqName, files: Collection): List = getFilesWithCallables(files).filter { getPackagePartFqName(it) == partFqName } + public @jvmStatic fun getFilePartShortName(fileName: String): String = + getPartClassName(FileUtil.getNameWithoutExtension(fileName)) } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/StubInterfaces.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/StubInterfaces.kt index 4840377a248..b61a2b28365 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/StubInterfaces.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/StubInterfaces.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.psi.* public interface KotlinFileStub : PsiFileStub { public fun getPackageFqName(): FqName + public fun getFacadeSimpleName(): String? public fun isScript(): Boolean public fun findImportsByAlias(alias: String): List } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetFileElementType.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetFileElementType.java index ff173347d97..afae7de1f1e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetFileElementType.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetFileElementType.java @@ -68,6 +68,7 @@ public class JetFileElementType extends IStubFileElementType { public void serialize(@NotNull KotlinFileStub stub, @NotNull StubOutputStream dataStream) throws IOException { dataStream.writeName(stub.getPackageFqName().asString()); + dataStream.writeName(stub.getFacadeSimpleName()); dataStream.writeBoolean(stub.isScript()); } @@ -76,7 +77,8 @@ public class JetFileElementType extends IStubFileElementType { public KotlinFileStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException { StringRef packageFqNameAsString = dataStream.readName(); boolean isScript = dataStream.readBoolean(); - return new KotlinFileStubImpl(null, packageFqNameAsString, isScript); + StringRef facadeSimpleName = dataStream.readName(); + return new KotlinFileStubImpl(null, packageFqNameAsString, facadeSimpleName, isScript); } @Override diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/impl/KotlinFileStubImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/impl/KotlinFileStubImpl.kt index 8f48ea63b77..b3940051364 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/impl/KotlinFileStubImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/impl/KotlinFileStubImpl.kt @@ -28,14 +28,19 @@ import org.jetbrains.kotlin.psi.stubs.KotlinFileStub import org.jetbrains.kotlin.psi.stubs.KotlinImportDirectiveStub import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes -public class KotlinFileStubImpl(jetFile: JetFile?, private val packageName: StringRef, private val isScript: Boolean)// SCRIPT: PsiJetFileStubImpl knows about scripting - : PsiFileStubImpl(jetFile), KotlinFileStub, PsiClassHolderFileStub { +// SCRIPT: PsiJetFileStubImpl knows about scripting +public class KotlinFileStubImpl( + jetFile: JetFile?, + private val packageName: StringRef, + private val facadeShortName: StringRef?, + private val isScript: Boolean +) : PsiFileStubImpl(jetFile), KotlinFileStub, PsiClassHolderFileStub { public constructor(jetFile: JetFile?, packageName: String, isScript: Boolean) - : this(jetFile, StringRef.fromString(packageName)!!, isScript) { - } + : this(jetFile, StringRef.fromString(packageName)!!, null, isScript) override fun getPackageFqName(): FqName = FqName(StringRef.toString(packageName)!!) + override fun getFacadeSimpleName(): String? = StringRef.toString(facadeShortName) override fun isScript(): Boolean = isScript override fun getType(): IStubFileElementType = JetStubElementTypes.FILE @@ -49,4 +54,18 @@ public class KotlinFileStubImpl(jetFile: JetFile?, private val packageName: Stri val importList = childrenStubs.firstOrNull { it.stubType == JetStubElementTypes.IMPORT_LIST } ?: return emptyList() return importList.childrenStubs.filterIsInstance().filter { it.getAliasName() == alias } } + + companion object { + public fun forPackageStub(packageFqName: FqName, isScript: Boolean): KotlinFileStubImpl = + KotlinFileStubImpl(null, + StringRef.fromString(packageFqName.asString())!!, + null, + isScript) + + public fun forFileFacadeStub(facadeFqName: FqName, isScript: Boolean): KotlinFileStubImpl = + KotlinFileStubImpl(null, + StringRef.fromString(facadeFqName.parent().asString())!!, + StringRef.fromString(facadeFqName.shortName().asString())!!, + isScript) + } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.java index bbf84709919..7a5c3e5eab2 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.java @@ -26,7 +26,6 @@ import com.intellij.psi.ClassFileViewProvider; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiManager; -import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.psi.impl.compiled.ClsClassImpl; import com.intellij.psi.impl.compiled.ClsFileImpl; import com.intellij.psi.impl.java.stubs.PsiJavaFileStub; @@ -49,7 +48,6 @@ import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil; import org.jetbrains.kotlin.idea.stubindex.StaticFacadeIndexUtil; import org.jetbrains.kotlin.idea.util.ProjectRootsUtil; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; -import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; @@ -64,6 +62,7 @@ import java.util.*; import static kotlin.KotlinPackage.*; import static org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope.kotlinSourceAndClassFiles; +import static org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope.kotlinSourcesAndLibraries; public class IDELightClassGenerationSupport extends LightClassGenerationSupport { @@ -187,19 +186,6 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport return PackageIndexUtil.findFilesWithExactPackage(fqName, kotlinSourceAndClassFiles(searchScope, project), project); } - @NotNull - private static Map> groupByModuleInfo(@NotNull Collection allFiles) { - return KotlinPackage.groupByTo( - allFiles, - new LinkedHashMap>(), - new Function1() { - @Override - public IdeaModuleInfo invoke(JetFile file) { - return ResolvePackage.getModuleInfo(file); - } - }); - } - @NotNull @Override public Collection findClassOrObjectDeclarationsInPackage( @@ -294,27 +280,43 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport IdeaModuleInfo moduleInfo = info.getModuleInfo(); if (moduleInfo instanceof ModuleSourceInfo) { - KotlinLightClassForFacade lightClass = - KotlinLightClassForFacade.Factory.createForPackageFacade(psiManager, packageFqName, moduleInfo.contentScope(), files); - if (lightClass == null) continue; - - result.add(lightClass); - - if (files.size() > 1) { - for (JetFile file : files) { - result.add(new FakeLightClassForFileOfPackage(psiManager, lightClass, file)); - } - } + result.addAll(getLightClassesForPackageFacadeWithSources(packageFqName, files, moduleInfo)); } else { - FqName packageFacadeFqName = PackageClassUtils.getPackageClassFqName(packageFqName); - List clsClasses = getLightClassesForDecompiledFacadeFiles(packageFacadeFqName, files); - result.addAll(clsClasses); + result.addAll(getLightClassesForDecompiledFacadeFiles(files)); } } return result; } + @NotNull + private List getLightClassesForPackageFacadeWithSources( + @NotNull FqName packageFqName, + @NotNull List facadeFiles, + @NotNull IdeaModuleInfo moduleInfo + ) { + KotlinLightClassForFacade lightClassForFacade = + KotlinLightClassForFacade.Factory.createForPackageFacade(psiManager, packageFqName, moduleInfo.contentScope(), facadeFiles); + return getLightClassesForFacadeWithFiles(lightClassForFacade, facadeFiles); + } + + @NotNull + private List getLightClassesForFacadeWithFiles( + @Nullable KotlinLightClassForFacade lightClassForFacade, + @NotNull List facadeFiles + ) { + if (lightClassForFacade == null) return emptyList(); + + List lightClasses = new ArrayList(); + lightClasses.add(lightClassForFacade); + if (facadeFiles.size() > 1) { + for (JetFile file : facadeFiles) { + lightClasses.add(new FakeLightClassForFileOfPackage(psiManager, lightClassForFacade, file)); + } + } + return lightClasses; + } + @NotNull @Override public Collection getFacadeClasses(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) { @@ -326,36 +328,48 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport IdeaModuleInfo moduleInfo = info.getModuleInfo(); if (moduleInfo instanceof ModuleSourceInfo) { - KotlinLightClassForFacade lightClass = - KotlinLightClassForFacade.Factory.createForFacade(psiManager, facadeFqName, moduleInfo.contentScope(), files); - if (lightClass == null) continue; - - result.add(lightClass); - - if (files.size() > 1) { - for (JetFile file : files) { - result.add(new FakeLightClassForFileOfPackage(psiManager, lightClass, file)); - } - } + result.addAll(getLightClassesForStaticFacadeWithSources(facadeFqName, files, moduleInfo)); } else { - List clsClasses = getLightClassesForDecompiledFacadeFiles(facadeFqName, files); - result.addAll(clsClasses); + result.addAll(getLightClassesForDecompiledFacadeFiles(files)); } } return result; } + private List getLightClassesForStaticFacadeWithSources( + @NotNull FqName facadeFqName, + @NotNull List facadeFiles, + @NotNull IdeaModuleInfo moduleInfo + ) { + KotlinLightClassForFacade lightClassForFacade = KotlinLightClassForFacade.Factory.createForFacade( + psiManager, facadeFqName, moduleInfo.contentScope(), facadeFiles); + return getLightClassesForFacadeWithFiles(lightClassForFacade, facadeFiles); + } + @NotNull @Override public Collection findFilesForFacade(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) { - return StaticFacadeIndexUtil.findFilesForStaticFacade(facadeFqName, kotlinSourceAndClassFiles(scope, project), project); + return StaticFacadeIndexUtil.findFilesForStaticFacade(facadeFqName, kotlinSourcesAndLibraries(scope, project), project); } @NotNull private List findFacadeClassesInfos(FqName facadeFqName, GlobalSearchScope scope) { Collection facadeFiles = findFilesForFacade(facadeFqName, scope); - Map> filesByInfo = groupByModuleInfo(facadeFiles); + return groupFilesIntoFacadeLightClassesByModuleInfo(facadeFiles); + } + + @NotNull + private static List groupFilesIntoFacadeLightClassesByModuleInfo(Collection facadeFiles) { + Map> filesByInfo = KotlinPackage.groupByTo( + facadeFiles, + new LinkedHashMap>(), + new Function1() { + @Override + public IdeaModuleInfo invoke(JetFile file) { + return ResolvePackage.getModuleInfo(file); + } + }); List result = new ArrayList(); for (Map.Entry> entry : filesByInfo.entrySet()) { result.add(new KotlinLightFacadeClassInfo(entry.getValue(), entry.getKey())); @@ -374,8 +388,8 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport } } - @Nullable - private static List getLightClassesForDecompiledFacadeFiles(@NotNull FqName facadeFqName, @NotNull List filesWithCallables) { + @NotNull + private static List getLightClassesForDecompiledFacadeFiles(@NotNull List filesWithCallables) { List lightClasses = new ArrayList(); for (JetFile file : filesWithCallables) { if (file.isCompiled()) { @@ -390,12 +404,7 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport @NotNull FqName fqName, @NotNull GlobalSearchScope wholeScope ) { Collection allFiles = findFilesForPackage(fqName, wholeScope); - Map> filesByInfo = groupByModuleInfo(allFiles); - List result = new ArrayList(); - for (Map.Entry> entry : filesByInfo.entrySet()) { - result.add(new KotlinLightFacadeClassInfo(entry.getValue(), entry.getKey())); - } - return result; + return groupFilesIntoFacadeLightClassesByModuleInfo(allFiles); } private static final class KotlinLightFacadeClassInfo { @@ -445,7 +454,7 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport return null; } PsiManager manager = PsiManager.getInstance(decompiledKotlinFile.getProject()); - ClsFileImpl fakeFile = new ClsFileImpl((PsiManagerImpl) manager, new ClassFileViewProvider(manager, virtualFile)) { + ClsFileImpl fakeFile = new ClsFileImpl(new ClassFileViewProvider(manager, virtualFile)) { @NotNull @Override public PsiElement getNavigationElement() { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinClsStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinClsStubBuilder.kt index 175804b9920..d8def1974e6 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinClsStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinClsStubBuilder.kt @@ -68,7 +68,7 @@ public open class KotlinClsStubBuilder : ClsStubBuilder() { header.isCompatiblePackageFacadeKind() -> { val packageData = JvmProtoBufUtil.readPackageDataFrom(annotationData) val context = components.createContext(packageData.getNameResolver(), packageFqName) - createPackageFacadeFileStub(packageData.getPackageProto(), packageFqName, context) + createPackageFacadeStub(packageData.getPackageProto(), packageFqName, context) } header.isCompatibleClassKind() -> { if (header.classKind != JvmAnnotationNames.KotlinClass.Kind.CLASS) return null @@ -79,7 +79,7 @@ public open class KotlinClsStubBuilder : ClsStubBuilder() { header.isCompatibleFileFacadeKind() -> { val packageData = JvmProtoBufUtil.readPackageDataFrom(annotationData) val context = components.createContext(packageData.getNameResolver(), packageFqName) - createPackageFacadeFileStub(packageData.getPackageProto(), packageFqName, context) + createFileFacadeStub(packageData.getPackageProto(), classId.asSingleFqName(), context) } else -> throw IllegalStateException("Should have processed " + file.getPath() + " with header $header") } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinJavaScriptStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinJavaScriptStubBuilder.kt index 6b554d9001a..8007713524e 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinJavaScriptStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinJavaScriptStubBuilder.kt @@ -63,7 +63,7 @@ public open class KotlinJavaScriptStubBuilder : ClsStubBuilder() { if (isPackageHeader) { val packageData = content.toPackageData(nameResolver) val context = components.createContext(packageData.getNameResolver(), packageFqName) - return createPackageFacadeFileStub(packageData.getPackageProto(), packageFqName, context) + return createPackageFacadeStub(packageData.getPackageProto(), packageFqName, context) } else { val classData = content.toClassData(nameResolver) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt index fc0c4760d92..bfd3e269b32 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt @@ -42,12 +42,13 @@ fun createTopLevelClassStub(classId: ClassId, classProto: ProtoBuf.Class, contex return fileStub } -fun createPackageFacadeFileStub( +fun createPackageFacadeStub( packageProto: ProtoBuf.Package, packageFqName: FqName, c: ClsStubBuilderContext ): KotlinFileStubImpl { - val fileStub = createFileStub(packageFqName) + val fileStub = KotlinFileStubImpl.forPackageStub(packageFqName, packageFqName.isRoot) + setupFileStub(fileStub, packageFqName) val container = ProtoContainer(null, packageFqName) for (callableProto in packageProto.getMemberList()) { createCallableStub(fileStub, callableProto, c, container) @@ -55,14 +56,33 @@ fun createPackageFacadeFileStub( return fileStub } +fun createFileFacadeStub( + packageProto: ProtoBuf.Package, + facadeFqName: FqName, + c: ClsStubBuilderContext +): KotlinFileStubImpl { + val packageFqName = facadeFqName.parent() + val fileStub = KotlinFileStubImpl.forFileFacadeStub(facadeFqName, packageFqName.isRoot) + setupFileStub(fileStub, packageFqName) + val container = ProtoContainer(null, facadeFqName.parent()) + for (callableProto in packageProto.getMemberList()) { + createCallableStub(fileStub, callableProto, c, container) + } + return fileStub +} + fun createIncompatibleAbiVersionFileStub() = createFileStub(FqName.ROOT) fun createFileStub(packageFqName: FqName): KotlinFileStubImpl { - val fileStub = KotlinFileStubImpl(null, packageFqName.asString(), packageFqName.isRoot()) + val fileStub = KotlinFileStubImpl.forPackageStub(packageFqName, packageFqName.isRoot) + setupFileStub(fileStub, packageFqName) + return fileStub +} + +private fun setupFileStub(fileStub: KotlinFileStubImpl, packageFqName: FqName) { val packageDirectiveStub = KotlinPlaceHolderStubImpl(fileStub, JetStubElementTypes.PACKAGE_DIRECTIVE) createStubForPackageName(packageDirectiveStub, packageFqName) KotlinPlaceHolderStubImpl(fileStub, JetStubElementTypes.IMPORT_LIST) - return fileStub } fun createStubForPackageName(packageDirectiveStub: KotlinPlaceHolderStubImpl, packageFqName: FqName) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/JetStaticFacadeClassIndex.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/JetStaticFacadeClassIndex.kt index 5dc7c932b09..27cff5f29d1 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/JetStaticFacadeClassIndex.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/JetStaticFacadeClassIndex.kt @@ -29,10 +29,10 @@ public class JetStaticFacadeClassIndex private constructor() : StringStubIndexEx super.get(key, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project)) companion object { - private val KEY = KotlinIndexUtil.createIndexKey(javaClass()) + private val KEY = KotlinIndexUtil.createIndexKey(JetStaticFacadeClassIndex::class.java) public val INSTANCE: JetStaticFacadeClassIndex = JetStaticFacadeClassIndex() - public fun getInstance(): JetStaticFacadeClassIndex = INSTANCE + public @jvmStatic fun getInstance(): JetStaticFacadeClassIndex = INSTANCE } } \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/StaticFacadeIndexUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/StaticFacadeIndexUtil.kt index 2a3e886d429..e6afc59b1a7 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/StaticFacadeIndexUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/StaticFacadeIndexUtil.kt @@ -18,17 +18,26 @@ package org.jetbrains.kotlin.idea.stubindex import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.JetFile import kotlin.platform.platformStatic public object StaticFacadeIndexUtil { - platformStatic public fun findFilesForStaticFacade( + @jvmStatic public fun findFilesForStaticFacade( facadeFqName: FqName, searchScope: GlobalSearchScope, project: Project ) : Collection = JetStaticFacadeClassIndex.INSTANCE.get(facadeFqName.asString(), project, searchScope) + // TODO change as we introduce multi-file facades (this will require a separate index) + @jvmStatic public fun findFilesForFilePart( + partFqName: FqName, + searchScope: GlobalSearchScope, + project: Project + ) : Collection = + PackagePartClassUtils.getFilesWithCallables( + JetStaticFacadeClassIndex.INSTANCE.get(partFqName.asString(), project, searchScope)) } \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/StubIndexServiceImpl.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/StubIndexServiceImpl.java index 7f8f111958c..63706721f10 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/StubIndexServiceImpl.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/StubIndexServiceImpl.java @@ -20,6 +20,7 @@ import com.intellij.psi.stubs.IndexSink; import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; import com.intellij.psi.stubs.StubElement; import org.jetbrains.kotlin.name.FqName; +import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.JetClassOrObject; import org.jetbrains.kotlin.psi.JetFile; import org.jetbrains.kotlin.psi.stubs.*; @@ -36,11 +37,18 @@ public class StubIndexServiceImpl implements StubIndexService { sink.occurrence(JetExactPackagesIndex.getInstance().getKey(), packageFqName.asString()); - JetFile psi = stub.getPsi(); - if (psi != null) { - FqName staticFacadeFqName = PackagePartClassUtils.getPackagePartFqName(psi); + String facadeSimpleName = stub.getFacadeSimpleName(); + if (facadeSimpleName != null) { + FqName staticFacadeFqName = packageFqName.child(Name.identifier(facadeSimpleName)); sink.occurrence(JetStaticFacadeClassIndex.INSTANCE.getKey(), staticFacadeFqName.asString()); } + else { + JetFile psi = stub.getPsi(); + if (psi != null) { + FqName staticFacadeFqName = PackagePartClassUtils.getPackagePartFqName(psi); + sink.occurrence(JetStaticFacadeClassIndex.INSTANCE.getKey(), staticFacadeFqName.asString()); + } + } } @Override diff --git a/idea/src/org/jetbrains/kotlin/idea/filters/JetExceptionFilter.java b/idea/src/org/jetbrains/kotlin/idea/filters/JetExceptionFilter.java index c220424fbdb..20653ba115b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/filters/JetExceptionFilter.java +++ b/idea/src/org/jetbrains/kotlin/idea/filters/JetExceptionFilter.java @@ -28,8 +28,6 @@ import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.idea.util.DebuggerUtils; -import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; -import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.JetFile; import org.jetbrains.kotlin.resolve.jvm.JvmClassName; @@ -53,38 +51,25 @@ public class JetExceptionFilter implements Filter { StackTraceElement element = parseStackTraceLine(line); if (element == null) return null; + // All true classes should be handled correctly in the default ExceptionFilter. Special cases: + // - static facades; + // - package facades / package parts (generated by pre-M13 compiled); + // - local classes (and closures) in top-level function and property declarations. String fileName = element.getFileName(); - // fullyQualifiedName is of format "package.Class$Inner" String fullyQualifiedName = element.getClassName(); - - // All classes except package classes, package parts and top level closures are handled correctly in the default ExceptionFilter - if (!isPackageClassOrPackagePartPrefixedName(fullyQualifiedName)) return null; + int lineNumber = element.getLineNumber() - 1; String internalName = fullyQualifiedName.replace('.', '/'); JvmClassName jvmClassName = JvmClassName.byInternalName(internalName); - JetFile file = DebuggerUtils.findSourceFileForClass(project, searchScope, jvmClassName, fileName, element.getLineNumber() - 1); + JetFile file = DebuggerUtils.findSourceFileForClass(project, searchScope, jvmClassName, fileName, lineNumber); if (file == null) return null; VirtualFile virtualFile = file.getVirtualFile(); if (virtualFile == null) return null; - return new OpenFileHyperlinkInfo(project, virtualFile, element.getLineNumber() - 1); - } - - private static boolean isPackageClassOrPackagePartPrefixedName(String fqName) { - if (fqName.equals(PackageClassUtils.getPackageClassName(FqName.ROOT))) { - return true; - } - - int lastDot = fqName.lastIndexOf('.'); - String classNameWithInners = fqName.substring(lastDot + 1); - int firstDollar = classNameWithInners.indexOf('$'); - String className = firstDollar >= 0 ? classNameWithInners.substring(0, firstDollar) : classNameWithInners; - - String packageClassName = PackageClassUtils.getPackageClassName(new FqName(fqName).parent()); - return packageClassName.equals(className); + return new OpenFileHyperlinkInfo(project, virtualFile, lineNumber); } // Matches strings like "\tat test.TestPackage$foo$f$1.invoke(a.kt:3)\n" diff --git a/idea/src/org/jetbrains/kotlin/idea/util/DebuggerUtils.java b/idea/src/org/jetbrains/kotlin/idea/util/DebuggerUtils.java index a4781313d6d..00961c5a1ce 100644 --- a/idea/src/org/jetbrains/kotlin/idea/util/DebuggerUtils.java +++ b/idea/src/org/jetbrains/kotlin/idea/util/DebuggerUtils.java @@ -19,8 +19,10 @@ package org.jetbrains.kotlin.idea.util; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.libraries.LibraryUtil; +import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.psi.PsiElement; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; @@ -32,13 +34,14 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade; import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils; import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde; import org.jetbrains.kotlin.idea.debugger.DebuggerPackage; -import org.jetbrains.kotlin.idea.resolve.ResolvePackage; +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade; +import org.jetbrains.kotlin.idea.stubindex.StaticFacadeIndexUtil; import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; +import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.CompositeBindingContext; @@ -56,6 +59,8 @@ public class DebuggerUtils { private DebuggerUtils() { } + private static final Set KOTLIN_EXTENSIONS = Sets.newHashSet("kt", "kts"); + @Nullable public static JetFile findSourceFileForClass( @NotNull Project project, @@ -64,6 +69,9 @@ public class DebuggerUtils { @NotNull final String fileName, final int lineNumber ) { + String extension = FileUtilRt.getExtension(fileName); + if (!KOTLIN_EXTENSIONS.contains(extension)) return null; + Collection filesInPackage = findFilesWithExactPackage(className.getPackageFqName(), searchScope, project); Collection filesWithExactName = Collections2.filter(filesInPackage, new Predicate() { @Override @@ -78,6 +86,19 @@ public class DebuggerUtils { return filesWithExactName.iterator().next(); } + // Static facade or inner class of such facade? + FqName partFqName = className.getFqNameForClassNameWithoutDollars(); + Collection filesForPart = StaticFacadeIndexUtil.findFilesForFilePart(partFqName, searchScope, project); + if (!filesForPart.isEmpty()) { + for (JetFile file : filesForPart) { + if (file.getName().equals(fileName)) { + return file; + } + } + // Do not fall back to decompiled files (which have different name). + return null; + } + if (isPackageClassName(className)) { for (JetFile file : filesWithExactName) { boolean hasTopLevelMembers = KotlinPackage.any(file.getDeclarations(), new Function1() { @@ -108,10 +129,11 @@ public class DebuggerUtils { @Override public Boolean invoke(JetFile file) { Integer startLineOffset = CodeInsightUtils.getStartLineOffset(file, lineNumber); - assert startLineOffset != null : "Cannot find start line offset for file " + file.getName() + ", line " + lineNumber; + assert startLineOffset != null : "Cannot find start line offset for file " + file.getName() + ", line " + + lineNumber; JetDeclaration elementAt = PsiTreeUtil.getParentOfType(file.findElementAt(startLineOffset), JetDeclaration.class); return elementAt != null && - className.getInternalName().equals(DebuggerPackage.findPackagePartInternalNameForLibraryFile(elementAt)); + className.getInternalName().equals(DebuggerPackage.findPackagePartInternalNameForLibraryFile(elementAt)); } })); } diff --git a/idea/testData/filters/exceptionFilter/kotlinClass/a.kt b/idea/testData/filters/exceptionFilter/kotlinClass/a.kt new file mode 100644 index 00000000000..a4d7958fa92 --- /dev/null +++ b/idea/testData/filters/exceptionFilter/kotlinClass/a.kt @@ -0,0 +1,5 @@ +class A { + fun foo() { + println("Hello!") + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/filters/JetExceptionFilterTest.kt b/idea/tests/org/jetbrains/kotlin/idea/filters/JetExceptionFilterTest.kt index b593b5fe6b8..e9c27c55f05 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/filters/JetExceptionFilterTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/filters/JetExceptionFilterTest.kt @@ -129,6 +129,11 @@ public class JetExceptionFilterTest : MultiFileTestCase() { doTest("2/foo2.kt", 4, { file -> "" + PackagePartClassUtils.getDefaultPartFqName(packageClassFqName, file) + "\$foo\$f\$1" }) } + public fun testKotlinClass() { + val kotlinClassFqName = "A" + doTest("a.kt", 3, { kotlinClassFqName }) + } + public fun testLibrarySources() { val mockLibrary = MockLibraryUtil.compileLibraryToJar(getTestDataPath() + getTestRoot() + "mockLibrary", "mockLibrary", true)