diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java index 3fbdd8fcc50..adb10877a72 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java @@ -80,7 +80,9 @@ public class JavaPackageScope extends JavaClassOrPackageScope { final JavaDescriptorResolver descriptorResolver = semanticServices.getDescriptorResolver(); for (PsiPackage psiSubPackage : javaPackage.getSubPackages()) { - allDescriptors.add(descriptorResolver.resolveNamespace(psiSubPackage.getQualifiedName())); + if (semanticServices.getKotlinNamespaceDescriptor(psiSubPackage.getQualifiedName()) == null) { + allDescriptors.add(descriptorResolver.resolveNamespace(psiSubPackage.getQualifiedName())); + } } for (PsiClass psiClass : javaPackage.getClasses()) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetClassElementType.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetClassElementType.java index f6c94df4fa2..0a5273388d9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetClassElementType.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetClassElementType.java @@ -11,6 +11,7 @@ import com.intellij.util.io.StringRef; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub; import org.jetbrains.jet.lang.psi.stubs.impl.PsiJetClassStubImpl; @@ -43,7 +44,7 @@ public class JetClassElementType extends JetStubElementType { - public static final int STUB_VERSION = 1; + public static final int STUB_VERSION = 2; public JetFileElementType() { super("jet.FILE", JetLanguage.INSTANCE); 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 4c085ebebfe..3cf99a79baa 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 @@ -146,7 +146,7 @@ public class JavaElementFinder extends PsiElementFinder { final List psiFiles = collectProjectJetFiles(project, GlobalSearchScope.allScope(project)); for (JetFile psiFile : psiFiles) { - if (qualifiedName.equals(JetPsiUtil.getFQName(psiFile))) { + if (JetPsiUtil.getFQName(psiFile).startsWith(qualifiedName)) { return new PsiPackageImpl(psiFile.getManager(), qualifiedName); } } @@ -154,6 +154,23 @@ public class JavaElementFinder extends PsiElementFinder { return null; } + @NotNull + @Override + public PsiPackage[] getSubPackages(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { + final List psiFiles = collectProjectJetFiles(project, GlobalSearchScope.allScope(project)); + + Set answer = new HashSet(); + + for (JetFile psiFile : psiFiles) { + String jetRootNamespace = JetPsiUtil.getFQName(psiFile); + if (isInPackage(psiPackage.getQualifiedName(), jetRootNamespace)) { + answer.add(new JetLightPackage(psiFile.getManager(), jetRootNamespace)); + } + } + + return answer.toArray(new PsiPackage[answer.size()]); + } + @NotNull @Override public PsiClass[] getClasses(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { @@ -174,6 +191,24 @@ public class JavaElementFinder extends PsiElementFinder { return answer.toArray(new PsiClass[answer.size()]); } + private static boolean isInPackage(String packageName, String fqn) { + return fqn.startsWith(packageName + "."); + } + + private static String subPackageName(String packageName, String packageFQN) { + if (!isInPackage(packageName, packageFQN)) { + return null; + } + + int nextDotIndex = packageFQN.indexOf('.', (packageName + ".").length()); + + if (nextDotIndex != -1) { + return packageFQN.substring((packageName + ".").length(), nextDotIndex); + } + + return packageFQN.substring((packageName + ".").length()); + } + private synchronized void invalidateJetFilesCache() { jetFiles.clear(); } diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JetLightPackage.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JetLightPackage.java new file mode 100644 index 00000000000..23a52dae6dd --- /dev/null +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JetLightPackage.java @@ -0,0 +1,18 @@ +package org.jetbrains.jet.asJava; + +import com.intellij.psi.PsiManager; +import com.intellij.psi.impl.file.PsiPackageImpl; + +/** + * @author Nikolay Krasko + */ +public class JetLightPackage extends PsiPackageImpl { + public JetLightPackage(PsiManager manager, String qualifiedName) { + super(manager, qualifiedName); + } + + @Override + public boolean isValid() { + return true; + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JavaToJetCompletionResolver.java b/idea/src/org/jetbrains/jet/plugin/caches/JavaToJetCompletionResolver.java new file mode 100644 index 00000000000..5df2e4f1018 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/caches/JavaToJetCompletionResolver.java @@ -0,0 +1,56 @@ +package org.jetbrains.jet.plugin.caches; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.PsiShortNamesCache; +import com.intellij.xml.impl.schema.TypeDescriptor; +import org.jetbrains.jet.lang.resolve.java.JvmAbi; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Get jet declarations from java that could be used in completion. Unlike the real jet resolver this helper is allowed + * to return partially unresolved descriptors in exchange of execution speed. + * + * @author Nikolay Krasko + */ +class JetFromJavaDescriptorHelper { + + private JetFromJavaDescriptorHelper() { + } + + /** + * Get java equivalents for jet top level classes. + */ + static PsiClass[] getClassesForJetNamespaces(Project project, GlobalSearchScope scope) { + return PsiShortNamesCache.getInstance(project).getClassesByName(JvmAbi.PACKAGE_CLASS, scope); + } + + /** + * Get names that could have jet descriptor equivalents. It could be inaccurate and return more results than necessary. + */ + static Collection getPossiblePackageDeclarationsNames(Project project, GlobalSearchScope scope) { + final ArrayList result = new ArrayList(); + + for (PsiClass jetNamespaceClass : getClassesForJetNamespaces(project, scope)) { + for (PsiMethod psiMethod : jetNamespaceClass.getMethods()) { + if (psiMethod.getModifierList().hasModifierProperty(PsiModifier.STATIC)) { + result.add(psiMethod.getName()); + } + } + } + + return result; + } + + static Collection getTopExtensionFunctionNames(TypeDescriptor typeDescriptor, Project project, + GlobalSearchScope scope) { + + return getPossiblePackageDeclarationsNames(project, scope); + } + +} diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java b/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java index a206a38e32d..97245f30cd8 100644 --- a/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java +++ b/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java @@ -1,11 +1,9 @@ package org.jetbrains.jet.plugin.caches; -import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; import com.intellij.psi.PsiField; import com.intellij.psi.PsiMethod; import com.intellij.psi.search.GlobalSearchScope; @@ -14,12 +12,14 @@ import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.asJava.JavaElementFinder; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.JetNamedFunction; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import org.jetbrains.jet.plugin.stubindex.JetExtensionFunctionNameIndex; +import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex; +import org.jetbrains.jet.plugin.stubindex.JetShortClassNameIndex; import org.jetbrains.jet.plugin.stubindex.JetShortFunctionNameIndex; import java.util.ArrayList; @@ -27,78 +27,113 @@ import java.util.Collection; import java.util.List; /** + * Will provide both java elements from jet context and some special declarations special to jet. + * All those declaration are planned to be used in completion. + * * @author Nikolay Krasko */ public class JetShortNamesCache extends PsiShortNamesCache { private final Project project; + private final JavaElementFinder javaElementFinder; public JetShortNamesCache(Project project) { this.project = project; + this.javaElementFinder = new JavaElementFinder(project); } - @NotNull - @Override - public PsiClass[] getClassesByName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) { - return new PsiClass[0]; - } - + /** + * Return jet class names form jet project sources which should be visible from java. + */ @NotNull @Override public String[] getAllClassNames() { - return new String[0]; + final Collection classNames = JetShortClassNameIndex.getInstance().getAllKeys(project); + return classNames.toArray(new String[classNames.size()]); + +// final Collection fqNames = getALlJetClassFQNames(); +// +// return Collections2.transform(fqNames, new Function() { +// @Override +// public String apply(@Nullable String fqName) { +// assert fqName != null; +// return fqnToShortName(fqName); +// } +// }).toArray(new String[fqNames.size()]); + } + + /** + * Return fake java names form jet project sources which should be visible from java. + */ + @NotNull + @Override + public PsiClass[] getClassesByName(@NotNull @NonNls final String name, @NotNull GlobalSearchScope scope) { + + // Quick check for classes from getAllClassNames() + final Collection classNames = JetShortClassNameIndex.getInstance().getAllKeys(project); + if (!classNames.contains(name)) { + return new PsiClass[0]; + } + + List result = new ArrayList(); + + for (String fqName : JetFullClassNameIndex.getInstance().getAllKeys(project)) { + final PsiClass psiClass = javaElementFinder.findClass(fqName, scope); + if (psiClass != null) { + result.add(psiClass); + } + } + + return result.toArray(new PsiClass[result.size()]); } @Override public void getAllClassNames(@NotNull HashSet dest) { + // TODO: Implement it. Is it called somewhere? } - public List getAllJetClassNames() { - final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, GlobalSearchScope.allScope(project)); - final Collection fqNames = context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR); + public static String fqnToShortName(String fqName) { + int lastDotIndex = fqName.lastIndexOf('.'); - final ArrayList classNames = new ArrayList(); - - for (String fqName : fqNames) { - int lastDotIndex = fqName.lastIndexOf('.'); - if (lastDotIndex != -1) { - classNames.add(fqName.substring(lastDotIndex + 1, fqName.length())); - } - else { - classNames.add(fqName); - } + if (lastDotIndex != -1) { + return fqName.substring(lastDotIndex + 1, fqName.length()); } - return classNames; + return fqName; } - public Collection getClassDescriptors() { + public Collection getALlJetClassFQNames() { final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, GlobalSearchScope.allScope(project)); - - final Collection fqNames = context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR); - return Collections2.transform(fqNames, new Function() { - @Override - public ClassDescriptor apply(String fqName) { - return context.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, fqName); - } - }); + return context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR); } + +// public Collection getClassDescriptors() { +// final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, GlobalSearchScope.allScope(project)); +// +// final Collection fqNames = context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR); +// return Collections2.transform(fqNames, new Function() { +// @Override +// public ClassDescriptor apply(String fqName) { +// return context.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, fqName); +// } +// }); +// } - public List getJetClassesByName(@NotNull String name, @NotNull GlobalSearchScope scope) { - final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, scope); - final ArrayList classesResult = new ArrayList(); - - for (String fqn : getFQNamesByName(name, scope)) { - final ClassDescriptor descriptor = context.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, fqn); - final PsiElement declaration = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor); - - if (declaration instanceof JetClass) { - classesResult.add((JetClass) declaration); - } - } - - return classesResult; - } +// public List getJetClassesByName(@NotNull String name, @NotNull GlobalSearchScope scope) { +// final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, scope); +// final ArrayList classesResult = new ArrayList(); +// +// for (String fqn : getFQNamesByName(name, scope)) { +// final ClassDescriptor descriptor = context.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, fqn); +// final PsiElement declaration = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor); +// +// if (declaration instanceof JetClass) { +// classesResult.add((JetClass) declaration); +// } +// } +// +// return classesResult; +// } @NotNull public Collection getFQNamesByName(@NotNull final String name, @NotNull GlobalSearchScope scope) { @@ -111,44 +146,30 @@ public class JetShortNamesCache extends PsiShortNamesCache { }); } - public Collection getAllExtensionFunctionsByName(@NotNull String name, @NotNull GlobalSearchScope scope) { - return JetExtensionFunctionNameIndex.getInstance().get(name, project, scope); - } - @NotNull public Collection getAllTopLevelFunctionNames() { - return JetShortFunctionNameIndex.getInstance().getAllKeys(project); + final ArrayList functionNames = new ArrayList(); + functionNames.addAll(JetShortFunctionNameIndex.getInstance().getAllKeys(project)); + functionNames.addAll(JetFromJavaDescriptorHelper.getPossiblePackageDeclarationsNames(project, GlobalSearchScope.allScope(project))); + return functionNames; + } + + public Collection getTopLevelFunctionDescriptorsByName(final @NotNull String name, @NotNull GlobalSearchScope scope) { + return new ArrayList(); } public Collection getTopLevelFunctionsByName(final @NotNull String name, @NotNull GlobalSearchScope scope) { return JetShortFunctionNameIndex.getInstance().get(name, project, scope); } - -// private Collection getTopLeveFunctions(@NotNull GlobalSearchScope scope) { -// final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, scope); -// final Collection keys = context.getKeys(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR); -// -// final List result = new ArrayList(); -// -// for (String namespaceKey : keys) { -// final NamespaceDescriptor namespace = context.get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, namespaceKey); -// if (namespace != null) { -// final JetScope memberScope = namespace.getNamespaceType().getMemberScope(); -// final Collection allDescriptors = memberScope.getAllDescriptors(); -// -// for (DeclarationDescriptor descriptor : allDescriptors) { -// if (descriptor instanceof FunctionDescriptor) { -// FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; -// if (functionDescriptor.getReceiverParameter() == ReceiverDescriptor.NO_RECEIVER) { -// result.add(functionDescriptor); -// } -// } -// } -// } -// } -// -// return result; -// } + + @NotNull + public Collection getAllJetExtensionFunctionsNames(@NotNull GlobalSearchScope scope) { + return JetFromJavaDescriptorHelper.getTopExtensionFunctionNames(null, project, scope); + } + + public Collection getAllJetExtensionFunctionsByName(@NotNull String name, @NotNull GlobalSearchScope scope) { + return JetExtensionFunctionNameIndex.getInstance().get(name, project, scope); + } @NotNull @Override diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java index 29138f87f0c..a99f58b4f3a 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java @@ -13,8 +13,11 @@ import com.intellij.util.Consumer; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetQualifiedExpression; +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lang.psi.JetUserType; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.plugin.caches.JetCacheManager; import org.jetbrains.jet.plugin.caches.JetShortNamesCache; @@ -57,9 +60,13 @@ public class JetCompletionContributor extends CompletionContributor { } } +// final JetShortNamesCache namesCache = JetCacheManager.getInstance(position.getProject()).getNamesCache(); +// final GlobalSearchScope scope = GlobalSearchScope.allScope(parameters.getPosition().getProject()); +// final Collection functionNames = namesCache.getAllJetExtensionFunctionsNames(scope); + if (shouldRunClassNameCompletion(parameters)) { addJavaClasses(parameters, result); - addJetClasses(result, position); + // addJetClasses(result, position); } if (shouldRunFunctionNameCompletion(parameters)) { @@ -92,38 +99,42 @@ public class JetCompletionContributor extends CompletionContributor { for (String name : functionNames) { if (name.contains(actualPrefix)) { - for (JetNamedFunction function : namesCache.getTopLevelFunctionsByName(name, scope)) { - String functionName = function.getName(); - String qualifiedName = function.getQualifiedName(); - assert functionName != null; - - final LookupElementBuilder lookup = LookupElementBuilder.create( - new LookupPositionObject(function), functionName); - - if (qualifiedName != null) { - lookup.setTailText(qualifiedName); - } - - addCompletionToResult(result, lookup); + for (FunctionDescriptor function : namesCache.getTopLevelFunctionDescriptorsByName(name, scope)) { + addCompletionToResult(result, DescriptorLookupConverter.createLookupElement(null, function, null)); } + +// for (JetNamedFunction function : namesCache.getTopLevelFunctionsByName(name, scope)) { +// String functionName = function.getName(); +// String qualifiedName = function.getQualifiedName(); +// assert functionName != null; +// +// final LookupElementBuilder lookup = LookupElementBuilder.create( +// new LookupPositionObject(function), functionName); +// +// if (qualifiedName != null) { +// lookup.setTailText(qualifiedName); +// } +// +// addCompletionToResult(result, lookup); +// } } } } } - private void addJetClasses(@NotNull CompletionResultSet result, @NotNull PsiElement position) { - String actualPrefix = getActualCompletionPrefix(position); - if (actualPrefix != null) { - final Collection classDescriptors = - JetCacheManager.getInstance(position.getProject()).getNamesCache().getClassDescriptors(); - - for (ClassDescriptor descriptor : classDescriptors) { - if (descriptor.getName().startsWith(actualPrefix)) { - addCompletionToResult(result, DescriptorLookupConverter.createLookupElement(null, descriptor, null)); - } - } - } - } +// private void addJetClasses(@NotNull CompletionResultSet result, @NotNull PsiElement position) { +// String actualPrefix = getActualCompletionPrefix(position); +// if (actualPrefix != null) { +// final Collection classDescriptors = +// JetCacheManager.getInstance(position.getProject()).getNamesCache().getClassDescriptors(); +// +// for (ClassDescriptor descriptor : classDescriptors) { +// if (descriptor.getName().startsWith(actualPrefix)) { +// addCompletionToResult(result, DescriptorLookupConverter.createLookupElement(null, descriptor, null)); +// } +// } +// } +// } @Nullable private static String getActualCompletionPrefix(@NotNull PsiElement position) { @@ -203,9 +214,6 @@ public class JetCompletionContributor extends CompletionContributor { } } } -// if (reference == null && parent instanceof CompositeElement) { -// reference = ((CompositeElement) parent).getPsi().getReference(); -// } } return null; diff --git a/idea/src/org/jetbrains/jet/plugin/stubindex/StubIndexServiceImpl.java b/idea/src/org/jetbrains/jet/plugin/stubindex/StubIndexServiceImpl.java index 6874943d167..f72162a2838 100644 --- a/idea/src/org/jetbrains/jet/plugin/stubindex/StubIndexServiceImpl.java +++ b/idea/src/org/jetbrains/jet/plugin/stubindex/StubIndexServiceImpl.java @@ -16,6 +16,11 @@ public class StubIndexServiceImpl implements StubIndexService { if (name != null) { sink.occurrence(JetIndexKeys.SHORT_NAME_KEY, name); } + + String fqn = stub.getQualifiedName(); + if (fqn != null) { + sink.occurrence(JetIndexKeys.FQN_KEY, fqn); + } } @Override