diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt index 2e55c141598..b060205c253 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -188,6 +188,12 @@ class KtPsiFactory(private val project: Project) { return file } + fun createFileWithLightClassSupport(fileName: String, text: String, contextToAnalyzeIn: PsiElement): KtFile { + val file = createPhysicalFile(fileName, text) + file.analysisContext = contextToAnalyzeIn + return file + } + fun createPhysicalFile(fileName: String, text: String): KtFile { return PsiFileFactory.getInstance(project).createFileFromText(fileName, KotlinFileType.INSTANCE, text, LocalTimeCounter.currentTime(), true) as KtFile } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt index 25e7aec9781..3b406db6813 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -360,6 +360,9 @@ class KtFileClassProviderImpl(val lightClassGenerationSupport: LightClassGenerat val fileClassFqName = file.javaFileFacadeFqName val facadeClasses = when { + file.analysisContext != null && PackagePartClassUtils.fileHasTopLevelCallables(file) -> + listOf(KtLightClassForFacade.createForSyntheticFile(PsiManager.getInstance(file.project), fileClassFqName, file)) + jvmClassInfo.withJvmMultifileClass -> lightClassGenerationSupport.getFacadeClasses(fileClassFqName, moduleInfo.contentScope()) diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignature.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignature.kt index 9c09b9c52ff..45fe2ae65ab 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignature.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/KotlinChangeSignature.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -147,8 +147,7 @@ class KotlinChangeSignature(project: Project, append("class Dummy {\n").append(ktSignature).append("{}\n}") toString() } - val dummyFile = LightVirtualFile("dummy.kt", KotlinFileType.INSTANCE, dummyFileText).toPsiFile(project) as KtFile - dummyFile.analysisContext = originalMethod + val dummyFile = KtPsiFactory(project).createFileWithLightClassSupport("dummy.kt", dummyFileText, originalMethod) val dummyDeclaration = (dummyFile.declarations.first() as KtClass).getBody()!!.declarations.first() // Convert to PsiMethod which can be used in Change Signature dialog diff --git a/idea/tests/org/jetbrains/kotlin/asJava/LightClassFromTextTest.kt b/idea/tests/org/jetbrains/kotlin/asJava/LightClassFromTextTest.kt new file mode 100644 index 00000000000..fc2ad105fbd --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/asJava/LightClassFromTextTest.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.asJava + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiClassType +import com.intellij.psi.PsiType +import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtPsiFactory + +// see KtFileLightClassTest +class LightClassFromTextTest : KotlinLightCodeInsightFixtureTestCase() { + override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE + + fun testSimple() { + myFixture.configureByText("Dummy.kt", "") as KtFile + val classes = classesFromText("class C {}\nobject O {}") + assertEquals(2, classes.size) + assertEquals("C", classes[0].qualifiedName) + assertEquals("O", classes[1].qualifiedName) + } + + fun testFileClass() { + myFixture.configureByText("A.kt", "fun f() {}") as KtFile + val classes = classesFromText("fun g() {}", fileName = "A.kt") + + assertEquals(1, classes.size) + val facadeClass = classes.single() + assertEquals("AKt", facadeClass.qualifiedName) + + val gMethods = facadeClass.findMethodsByName("g", false) + assertEquals(1, gMethods.size) + assertEquals(PsiType.VOID, gMethods.single().returnType) + + val fMethods = facadeClass.findMethodsByName("f", false) + assertEquals(0, fMethods.size) + } + + fun testMultifileClass() { + myFixture.configureByFiles("multifile1.kt", "multifile2.kt") + + val facadeClass = classesFromText(""" + @file:kotlin.jvm.JvmMultifileClass + @file:kotlin.jvm.JvmName("Foo") + + fun jar() { + } + + fun boo() { + } + """).single() + + assertEquals(1, facadeClass.findMethodsByName("jar", false).size) + assertEquals(1, facadeClass.findMethodsByName("boo", false).size) + assertEquals(0, facadeClass.findMethodsByName("bar", false).size) + assertEquals(0, facadeClass.findMethodsByName("foo", false).size) + } + + fun testReferenceToOuterContext() { + val contextFile = myFixture.configureByText("Example.kt", "package foo\n class Example") as KtFile + + val syntheticClass = classesFromText(""" + package bar + + import foo.Example + + class Usage { + fun f(): Example = Example() + } + """).single() + + val exampleClass = contextFile.classes.single() + assertEquals("Example", exampleClass.name) + + val f = syntheticClass.findMethodsByName("f", false).single() + assertEquals(exampleClass, (f.returnType as PsiClassType).resolve()) + } + + private fun classesFromText(text: String, fileName: String = "A.kt"): Array { + val file = KtPsiFactory(project).createFileWithLightClassSupport(fileName, text, myFixture.file) + val classes = file.classes + return classes + } + + override fun getTestDataPath(): String? { + return PluginTestCaseBase.getTestDataPathBase() + "/asJava/fileLightClass/" + } +} \ No newline at end of file