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 edd85586c6b..68d67345ef6 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 @@ -350,18 +350,20 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport return null; } - ClsClassImpl javaClsClass = createClsJavaClassFromVirtualFile(file, virtualFile); + JetClassOrObject classOrObject = singleOrNull(filterIsInstance(file.getDeclarations(), JetClassOrObject.class)); + + ClsClassImpl javaClsClass = createClsJavaClassFromVirtualFile(file, virtualFile, classOrObject); if (javaClsClass == null) { return null; } - JetClassOrObject declaration = singleOrNull(filterIsInstance(file.getDeclarations(), JetClassOrObject.class)); - return new KotlinLightClassForDecompiledDeclaration(javaClsClass, declaration); + return new KotlinLightClassForDecompiledDeclaration(javaClsClass, classOrObject); } @Nullable private static ClsClassImpl createClsJavaClassFromVirtualFile( @NotNull final JetFile decompiledKotlinFile, - @NotNull VirtualFile virtualFile + @NotNull VirtualFile virtualFile, + @Nullable final JetClassOrObject decompiledClassOrObject ) { final PsiJavaFileStubImpl javaFileStub = getOrCreateJavaFileStub(virtualFile); if (javaFileStub == null) { @@ -369,6 +371,15 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport } PsiManager manager = PsiManager.getInstance(decompiledKotlinFile.getProject()); ClsFileImpl fakeFile = new ClsFileImpl((PsiManagerImpl) manager, new ClassFileViewProvider(manager, virtualFile)) { + @NotNull + @Override + public PsiElement getNavigationElement() { + if (decompiledClassOrObject != null) { + return decompiledClassOrObject.getNavigationElement().getContainingFile(); + } + return super.getNavigationElement(); + } + @NotNull @Override public PsiClassHolderFileStub getStub() { diff --git a/idea/testData/filters/exceptionFilter/librarySources/dummy.txt b/idea/testData/filters/exceptionFilter/librarySources/dummy.txt new file mode 100644 index 00000000000..ab5e29d0a96 --- /dev/null +++ b/idea/testData/filters/exceptionFilter/librarySources/dummy.txt @@ -0,0 +1 @@ +This test doesn't have sources, but IDEA test framework needs sources dir \ No newline at end of file diff --git a/idea/testData/filters/exceptionFilter/mockLibrary/lib.kt b/idea/testData/filters/exceptionFilter/mockLibrary/lib.kt new file mode 100644 index 00000000000..a4fbc9800ed --- /dev/null +++ b/idea/testData/filters/exceptionFilter/mockLibrary/lib.kt @@ -0,0 +1,10 @@ +package test + +class Foo { + fun member() { + } +} + +fun foo() { + println() +} \ No newline at end of file diff --git a/idea/testData/filters/exceptionFilter/mockLibrary/other.kt b/idea/testData/filters/exceptionFilter/mockLibrary/other.kt new file mode 100644 index 00000000000..2a10208ec7a --- /dev/null +++ b/idea/testData/filters/exceptionFilter/mockLibrary/other.kt @@ -0,0 +1,5 @@ +package test + +fun other() { + println("") +} \ 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 41d7b79c2d3..69f5885a0bd 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/filters/JetExceptionFilterTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/filters/JetExceptionFilterTest.kt @@ -16,10 +16,17 @@ package org.jetbrains.kotlin.idea.filters +import com.intellij.execution.filters.FileHyperlinkInfo import com.intellij.execution.filters.OpenFileHyperlinkInfo +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.roots.ModifiableRootModel +import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.util.io.FileUtilRt import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiDocumentManager import com.intellij.psi.search.GlobalSearchScope import com.intellij.refactoring.MultiFileTestCase @@ -32,6 +39,7 @@ import org.jetbrains.kotlin.load.kotlin.PackageClassUtils.getPackageClassFqName import org.jetbrains.kotlin.load.kotlin.PackageClassUtils.getPackageClassName import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils.getPackagePartFqName import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.test.MockLibraryUtil import java.io.File public class JetExceptionFilterTest : MultiFileTestCase() { @@ -64,7 +72,7 @@ public class JetExceptionFilterTest : MultiFileTestCase() { return prefix + element + "\n" } - private fun doTest(fileName: String, lineNumber: Int, className: (VirtualFile) -> String, linePrefix: String = "\tat ") { + private fun doTest(relativePath: String, lineNumber: Int, className: (VirtualFile) -> String, linePrefix: String = "\tat ", libRootUrl: String? = null) { if (rootDir == null) { configure() } @@ -72,17 +80,22 @@ public class JetExceptionFilterTest : MultiFileTestCase() { val filter = JetExceptionFilterFactory().create(GlobalSearchScope.allScope(myProject)) - val expectedFile = VfsUtilCore.findRelativeFile(fileName, rootDir) + val expectedFile = if (libRootUrl != null) { + VirtualFileManager.getInstance().findFileByUrl(libRootUrl + relativePath); + } + else { + VfsUtilCore.findRelativeFile(relativePath, rootDir); + } TestCase.assertNotNull(expectedFile) - val line = createStackTraceElementLine(linePrefix, fileName, className.invoke(expectedFile), lineNumber) + val line = createStackTraceElementLine(linePrefix, relativePath, className(expectedFile), lineNumber) val result = filter.applyFilter(line, 0) TestCase.assertNotNull(result) val info = result.getFirstHyperlinkInfo() TestCase.assertNotNull(info) - UsefulTestCase.assertInstanceOf(info, javaClass()) - val descriptor = (info as OpenFileHyperlinkInfo).getDescriptor() + info as FileHyperlinkInfo + val descriptor = info.getDescriptor() TestCase.assertNotNull(descriptor) TestCase.assertEquals(expectedFile, descriptor.getFile()) @@ -113,4 +126,27 @@ public class JetExceptionFilterTest : MultiFileTestCase() { doTest("1/foo.kt", 4, { file -> "" + getPackagePartFqName(packageClassFqName, file) + "\$foo\$f\$1" }) doTest("2/foo.kt", 4, { file -> "" + getPackagePartFqName(packageClassFqName, file) + "\$foo\$f\$1" }) } + + public fun testLibrarySources() { + val mockLibrary = MockLibraryUtil.compileLibraryToJar(getTestDataPath() + getTestRoot() + "mockLibrary", "mockLibrary", true) + + val libRootUrl = "jar://" + FileUtilRt.toSystemIndependentName(mockLibrary.getAbsolutePath()) + "!/" + + ApplicationManager.getApplication().runWriteAction { + val moduleModel = ModuleRootManager.getInstance(myModule).getModifiableModel() + with(moduleModel.getModuleLibraryTable().getModifiableModel().createLibrary("mockLibrary").getModifiableModel()) { + addRoot(libRootUrl, OrderRootType.CLASSES) + addRoot(libRootUrl + "src/", OrderRootType.SOURCES) + commit() + } + moduleModel.commit() + } + + val packageClassFqName = FqName("test.TestPackage") + + doTest("src/lib.kt", 3, { "test.Foo" }, libRootUrl = libRootUrl) + doTest("src/lib.kt", 4, { "test.Foo" }, libRootUrl = libRootUrl) + doTest("src/lib.kt", 9, { "" + getPackagePartFqName(packageClassFqName, it) }, libRootUrl = libRootUrl) + doTest("src/other.kt", 4, { "" + getPackagePartFqName(packageClassFqName, it) }, libRootUrl = libRootUrl) + } }