diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/FakeLightClassForFileOfPackage.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/FakeLightClassForFileOfPackage.java new file mode 100644 index 00000000000..bae0aa36a4b --- /dev/null +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/FakeLightClassForFileOfPackage.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010-2013 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.jet.asJava; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.resolve.java.JetJavaMirrorMarker; +import org.jetbrains.jet.lang.resolve.name.FqName; + +/** + * This class serves as a workaround for usages of {@link JavaElementFinder#findClasses} which eventually only need names of files + * containing the class. When queried for a package class (e.g. test/TestPackage), {@code findClasses} along with a + * {@link KotlinLightClassForPackage} would also return multiple instances of this class for each file present in the package. The client + * code can make use of every file in the package then, since {@code getContainingFile} of these instances will represent the whole package. + *

+ * See {@link LineBreakpoint#findClassCandidatesInSourceContent} for the primary usage this was introduced + */ +/* package */ class FakeLightClassForFileOfPackage extends KotlinLightClassForPackageBase implements KotlinLightClass, JetJavaMirrorMarker { + private final KotlinLightClassForPackage delegate; + private final JetFile file; + + public FakeLightClassForFileOfPackage( + @NotNull PsiManager manager, @NotNull KotlinLightClassForPackage delegate, @NotNull JetFile file + ) { + super(manager); + this.delegate = delegate; + this.file = file; + } + + @Override + public PsiFile getContainingFile() { + return file; + } + + @Override + public boolean isValid() { + // This is intentionally false to prevent using this as a real class + return false; + } + + + @NotNull + @Override + public FqName getFqName() { + return delegate.getFqName(); + } + + @NotNull + @Override + public PsiClass getDelegate() { + return delegate; + } + + @NotNull + @Override + public PsiElement copy() { + return new FakeLightClassForFileOfPackage(getManager(), delegate, file); + } +} diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JavaElementFinder.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JavaElementFinder.java index 3f7cd9f77a5..b0047b134db 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JavaElementFinder.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JavaElementFinder.java @@ -117,6 +117,13 @@ public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacade KotlinLightClassForPackage lightClass = KotlinLightClassForPackage.create(psiManager, qualifiedName, filesForPackage); if (lightClass != null) { answer.add(lightClass); + + if (filesForPackage.size() > 1) { + for (JetFile file : filesForPackage) { + FakeLightClassForFileOfPackage fakeLightClass = new FakeLightClassForFileOfPackage(psiManager, lightClass, file); + answer.add(fakeLightClass); + } + } } } } diff --git a/compiler/testData/asJava/findClasses/multiFile/MultiFile1.kt b/compiler/testData/asJava/findClasses/multiFile/MultiFile1.kt new file mode 100644 index 00000000000..914da73cc00 --- /dev/null +++ b/compiler/testData/asJava/findClasses/multiFile/MultiFile1.kt @@ -0,0 +1,3 @@ +package test + +fun foo() = 42 diff --git a/compiler/testData/asJava/findClasses/multiFile/MultiFile2.kt b/compiler/testData/asJava/findClasses/multiFile/MultiFile2.kt new file mode 100644 index 00000000000..63db9f5e8bd --- /dev/null +++ b/compiler/testData/asJava/findClasses/multiFile/MultiFile2.kt @@ -0,0 +1,3 @@ +package test + +fun bar() = 239 + foo() diff --git a/compiler/tests/org/jetbrains/jet/asJava/JavaElementFinderMultiFileTest.java b/compiler/tests/org/jetbrains/jet/asJava/JavaElementFinderMultiFileTest.java new file mode 100644 index 00000000000..3caec5279c5 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/asJava/JavaElementFinderMultiFileTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2013 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.jet.asJava; + +import com.google.common.collect.Sets; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiFile; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.jet.cli.jvm.compiler.CliLightClassGenerationSupport; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.resolve.name.FqName; + +import java.io.File; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +public class JavaElementFinderMultiFileTest extends KotlinAsJavaTestBase { + private static final String PREFIX = "compiler/testData/asJava/findClasses/multiFile/"; + + @Override + protected List getKotlinSourceRoots() { + return Arrays.asList( + new File(PREFIX + getTestName(false) + "1.kt"), + new File(PREFIX + getTestName(false) + "2.kt") + ); + } + + public void testMultiFile() { + GlobalSearchScope searchScope = GlobalSearchScope.allScope(getProject()); + PsiClass[] classes = finder.findClasses("test.TestPackage", searchScope); + + assertEquals(3, classes.length); + + assertInstanceOf(classes[0], KotlinLightClassForPackage.class); + + Set expectedFiles = Sets.newHashSet( + CliLightClassGenerationSupport.getInstanceForCli(getProject()).findFilesForPackage(new FqName("test"), searchScope) + ); + + Set actualFiles = Sets.newHashSet(); + for (int i = 1; i < classes.length; i++) { + assertInstanceOf(classes[i], FakeLightClassForFileOfPackage.class); + actualFiles.add(((FakeLightClassForFileOfPackage) classes[i]).getContainingFile()); + } + + assertEquals(expectedFiles, actualFiles); + } +}