KT-983 Code completion for not-imported classes - Show kotlin classes (another temp commit)
This commit is contained in:
@@ -40,6 +40,12 @@ public class AnalyzerFacade {
|
||||
private final static Key<CachedValue<BindingContext>> BINDING_CONTEXT = Key.create("BINDING_CONTEXT");
|
||||
private static final Object lock = new Object();
|
||||
|
||||
/**
|
||||
* Analyze project with string cache for given file. Given file will be fully analyzed.
|
||||
* @param file
|
||||
* @param declarationProvider
|
||||
* @return
|
||||
*/
|
||||
public static BindingContext analyzeFileWithCache(@NotNull final JetFile file, @NotNull final Function<JetFile, Collection<JetFile>> declarationProvider) {
|
||||
// Need lock for getValue(), because parallel threads can start evaluation of compute() simultaneously
|
||||
synchronized (lock) {
|
||||
@@ -49,7 +55,11 @@ public class AnalyzerFacade {
|
||||
@Override
|
||||
public Result<BindingContext> compute() {
|
||||
try {
|
||||
BindingContext bindingContext = analyzeFilesWithJavaIntegration(file.getProject(), declarationProvider.fun(file), Predicates.<PsiFile>equalTo(file), JetControlFlowDataTraceFactory.EMPTY);
|
||||
BindingContext bindingContext = analyzeFilesWithJavaIntegration(
|
||||
file.getProject(),
|
||||
declarationProvider.fun(file),
|
||||
Predicates.<PsiFile>equalTo(file),
|
||||
JetControlFlowDataTraceFactory.EMPTY);
|
||||
return new Result<BindingContext>(bindingContext, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
@@ -71,11 +81,49 @@ public class AnalyzerFacade {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze project with string cache for the whole project. All given files will be analyzed only for descriptors.
|
||||
*/
|
||||
public static BindingContext analyzeProjectWithCache(@NotNull final Project project,
|
||||
@NotNull final Collection<JetFile> files) {
|
||||
// Need lock for getValue(), because parallel threads can start evaluation of compute() simultaneously
|
||||
synchronized (lock) {
|
||||
CachedValue<BindingContext> bindingContextCachedValue = project.getUserData(BINDING_CONTEXT);
|
||||
if (bindingContextCachedValue == null) {
|
||||
bindingContextCachedValue = CachedValuesManager.getManager(project).createCachedValue(new CachedValueProvider<BindingContext>() {
|
||||
@Override
|
||||
public Result<BindingContext> compute() {
|
||||
try {
|
||||
BindingContext bindingContext = analyzeFilesWithJavaIntegration(
|
||||
project,
|
||||
files,
|
||||
Predicates.<PsiFile>alwaysFalse(),
|
||||
JetControlFlowDataTraceFactory.EMPTY);
|
||||
return new Result<BindingContext>(bindingContext, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
DiagnosticUtils.throwIfRunningOnServer(e);
|
||||
e.printStackTrace();
|
||||
BindingTraceContext bindingTraceContext = new BindingTraceContext();
|
||||
return new Result<BindingContext>(bindingTraceContext.getBindingContext(), PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
project.putUserData(BINDING_CONTEXT, bindingContextCachedValue);
|
||||
}
|
||||
return bindingContextCachedValue.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
public static BindingContext analyzeOneFileWithJavaIntegration(JetFile file, JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||
return analyzeFilesWithJavaIntegration(file.getProject(), Collections.singleton(file), Predicates.<PsiFile>alwaysTrue(), flowDataTraceFactory);
|
||||
}
|
||||
|
||||
public static BindingContext analyzeFilesWithJavaIntegration(Project project, Collection<JetFile> files, Predicate<PsiFile> filesToAnalyzeCompletely, JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||
public static BindingContext analyzeFilesWithJavaIntegration(Project project, Collection<JetFile> files, Predicate<PsiFile> filesToAnalyzeCompletely,
|
||||
JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||
BindingTraceContext bindingTraceContext = new BindingTraceContext();
|
||||
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project);
|
||||
return AnalyzingUtils.analyzeFilesWithGivenTrace(
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
*/
|
||||
package org.jetbrains.jet.asJava;
|
||||
|
||||
import com.intellij.openapi.compiler.ex.CompilerPathsEx;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElementFinder;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiPackage;
|
||||
import com.intellij.psi.impl.file.PsiPackageImpl;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.SmartList;
|
||||
@@ -18,9 +17,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.plugin.JetFileType;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class JavaElementFinder extends PsiElementFinder {
|
||||
private final Project project;
|
||||
@@ -181,29 +182,8 @@ public class JavaElementFinder extends PsiElementFinder {
|
||||
List<JetFile> cachedFiles = jetFiles.get(scope);
|
||||
|
||||
if (cachedFiles == null) {
|
||||
final List<JetFile> answer = new ArrayList<JetFile>();
|
||||
|
||||
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
|
||||
|
||||
List<VirtualFile> contentRoots = Arrays.asList(ProjectRootManager.getInstance(project).getContentRoots());
|
||||
|
||||
CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() {
|
||||
@Override
|
||||
protected void acceptFile(VirtualFile file, String fileRoot, String filePath) {
|
||||
final FileType fileType = fileTypeManager.getFileTypeByFile(file);
|
||||
if (fileType != JetFileType.INSTANCE) return;
|
||||
|
||||
if (scope.accept(file)) {
|
||||
final PsiFile psiFile = psiManager.findFile(file);
|
||||
if (psiFile instanceof JetFile) {
|
||||
answer.add((JetFile) psiFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cachedFiles = answer;
|
||||
jetFiles.put(scope, answer);
|
||||
cachedFiles = JetFileUtil.collectJetFiles(project, scope);
|
||||
jetFiles.put(scope, cachedFiles);
|
||||
}
|
||||
|
||||
return cachedFiles;
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.jetbrains.jet.asJava;
|
||||
|
||||
import com.intellij.openapi.compiler.ex.CompilerPathsEx;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.plugin.JetFileType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Nikolay Krasko
|
||||
*/
|
||||
public final class JetFileUtil {
|
||||
|
||||
private JetFileUtil() {}
|
||||
|
||||
public static List<JetFile> collectJetFiles(final Project project, @NotNull final GlobalSearchScope scope) {
|
||||
final List<JetFile> answer = new ArrayList<JetFile>();
|
||||
|
||||
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
|
||||
List<VirtualFile> contentRoots = Arrays.asList(ProjectRootManager.getInstance(project).getContentRoots());
|
||||
final PsiManager manager = PsiManager.getInstance(project);
|
||||
|
||||
CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() {
|
||||
@Override
|
||||
protected void acceptFile(VirtualFile file, String fileRoot, String filePath) {
|
||||
final FileType fileType = fileTypeManager.getFileTypeByFile(file);
|
||||
if (fileType != JetFileType.INSTANCE) return;
|
||||
|
||||
if (scope.accept(file)) {
|
||||
final PsiFile psiFile = manager.findFile(file);
|
||||
if (psiFile instanceof JetFile) {
|
||||
answer.add((JetFile) psiFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,9 @@
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.jet.plugin.compiler.JetCompilerManager</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.jet.plugin.caches.JetCacheManager</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<actions>
|
||||
@@ -74,6 +77,7 @@
|
||||
<codeInsight.overrideMethod language="jet" implementationClass="org.jetbrains.jet.plugin.codeInsight.OverrideMethodsHandler"/>
|
||||
|
||||
<java.elementFinder implementation="org.jetbrains.jet.asJava.JavaElementFinder"/>
|
||||
<java.shortNamesCache implementation="org.jetbrains.jet.plugin.caches.JetShortNamesCache"/>
|
||||
|
||||
<psi.treeChangePreprocessor implementation="org.jetbrains.jet.asJava.JetCodeBlockModificationListener"/>
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.jetbrains.jet.plugin.caches;
|
||||
|
||||
import com.intellij.openapi.components.ProjectComponent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Nikolay Krasko
|
||||
*/
|
||||
public class JetCacheManager implements ProjectComponent {
|
||||
private Project myProject;
|
||||
private JetShortNamesCache myCache;
|
||||
|
||||
public static JetCacheManager getInstance(Project project) {
|
||||
return project.getComponent(JetCacheManager.class);
|
||||
}
|
||||
|
||||
public JetCacheManager(Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectOpened() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectClosed() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getComponentName() {
|
||||
return "Kotlin caches manager";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initComponent() {
|
||||
myCache = new JetShortNamesCache(myProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeComponent() {
|
||||
|
||||
}
|
||||
|
||||
public JetShortNamesCache getNamesCache() {
|
||||
return myCache;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
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;
|
||||
import com.intellij.psi.search.PsiShortNamesCache;
|
||||
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.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Nikolay Krasko
|
||||
*/
|
||||
public class JetShortNamesCache extends PsiShortNamesCache {
|
||||
|
||||
private final Project project;
|
||||
|
||||
public JetShortNamesCache(Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClass[] getClassesByName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) {
|
||||
return new PsiClass[0];
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String[] getAllClassNames() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getAllClassNames(@NotNull HashSet<String> dest) {
|
||||
}
|
||||
|
||||
public List<String> getAllJetClassNames() {
|
||||
final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, GlobalSearchScope.allScope(project));
|
||||
final Collection<String> fqNames = context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR);
|
||||
|
||||
final ArrayList<String> classNames = new ArrayList<String>();
|
||||
|
||||
for (String fqName : fqNames) {
|
||||
int lastDotIndex = fqName.lastIndexOf('.');
|
||||
if (lastDotIndex != -1) {
|
||||
classNames.add(fqName.substring(lastDotIndex + 1, fqName.length()));
|
||||
}
|
||||
else {
|
||||
classNames.add(fqName);
|
||||
}
|
||||
}
|
||||
|
||||
return classNames;
|
||||
}
|
||||
|
||||
public Collection<ClassDescriptor> getClassDescriptors() {
|
||||
final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, GlobalSearchScope.allScope(project));
|
||||
|
||||
final Collection<String> fqNames = context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR);
|
||||
return Collections2.transform(fqNames, new Function<String, ClassDescriptor>() {
|
||||
@Override
|
||||
public ClassDescriptor apply(String fqName) {
|
||||
return context.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, fqName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public List<JetClass> getJetClassesByName(@NotNull String name, @NotNull GlobalSearchScope scope) {
|
||||
final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, scope);
|
||||
final ArrayList<JetClass> classesResult = new ArrayList<JetClass>();
|
||||
|
||||
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<String> getFQNamesByName(@NotNull final String name, @NotNull GlobalSearchScope scope) {
|
||||
final BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCache(project, scope);
|
||||
return Collections2.filter(context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR), new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable String fqName) {
|
||||
return fqName != null && (fqName.endsWith('.' + name) || fqName.equals(name));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiMethod[] getMethodsByName(@NonNls @NotNull String name, @NotNull GlobalSearchScope scope) {
|
||||
return new PsiMethod[0];
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiMethod[] getMethodsByNameIfNotMoreThan(@NonNls @NotNull String name, @NotNull GlobalSearchScope scope, int maxCount) {
|
||||
return new PsiMethod[0];
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String[] getAllMethodNames() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getAllMethodNames(@NotNull HashSet<String> set) {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiField[] getFieldsByName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) {
|
||||
return new PsiField[0];
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String[] getAllFieldNames() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getAllFieldNames(@NotNull HashSet<String> set) {
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,10 @@ import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.asJava.JetFileUtil;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
|
||||
@@ -63,9 +65,13 @@ public final class WholeProjectAnalyzerFacade {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@NotNull
|
||||
public static BindingContext analyzeProjectWithCacheOnAFile(@NotNull JetFile file) {
|
||||
return AnalyzerFacade.analyzeFileWithCache(file, WHOLE_PROJECT_DECLARATION_PROVIDER);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static BindingContext analyzeProjectWithCache(@NotNull Project project, @NotNull GlobalSearchScope scope) {
|
||||
return AnalyzerFacade.analyzeProjectWithCache(project, JetFileUtil.collectJetFiles(project, scope));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package org.jetbrains.jet.plugin.completion;
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler;
|
||||
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||
|
||||
/**
|
||||
* @author Nikolay Krasko
|
||||
*/
|
||||
public final class DescriptorLookupConverter {
|
||||
|
||||
private final static JetFunctionInsertHandler EMPTY_FUNCTION_HANDLER = new JetFunctionInsertHandler(
|
||||
JetFunctionInsertHandler.CaretPosition.AFTER_BRACKETS);
|
||||
|
||||
private final static JetFunctionInsertHandler PARAMS_FUNCTION_HANDLER = new JetFunctionInsertHandler(
|
||||
JetFunctionInsertHandler.CaretPosition.IN_BRACKETS);
|
||||
|
||||
@NotNull
|
||||
public static LookupElement createLookupElement(@NotNull DeclarationDescriptor descriptor, @Nullable PsiElement declaration) {
|
||||
LookupElementBuilder element = LookupElementBuilder.create(descriptor, descriptor.getName());
|
||||
String typeText = "";
|
||||
String tailText = "";
|
||||
boolean tailTextGrayed = false;
|
||||
|
||||
if (descriptor instanceof FunctionDescriptor) {
|
||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||
JetType returnType = functionDescriptor.getReturnType();
|
||||
typeText = DescriptorRenderer.TEXT.renderType(returnType);
|
||||
|
||||
tailText = "(" + StringUtil.join(functionDescriptor.getValueParameters(), new Function<ValueParameterDescriptor, String>() {
|
||||
@Override
|
||||
public String fun(ValueParameterDescriptor valueParameterDescriptor) {
|
||||
return valueParameterDescriptor.getName() + ":" +
|
||||
DescriptorRenderer.TEXT.renderType(valueParameterDescriptor.getOutType());
|
||||
}
|
||||
}, ",") + ")";
|
||||
|
||||
|
||||
// TODO: A special case when it's impossible to resolve type parameters from arguments. Need '<' caret '>'
|
||||
// TODO: Support omitting brackets for one argument functions
|
||||
if (functionDescriptor.getValueParameters().isEmpty()) {
|
||||
element = element.setInsertHandler(EMPTY_FUNCTION_HANDLER);
|
||||
} else {
|
||||
element = element.setInsertHandler(PARAMS_FUNCTION_HANDLER);
|
||||
}
|
||||
}
|
||||
else if (descriptor instanceof VariableDescriptor) {
|
||||
JetType outType = ((VariableDescriptor) descriptor).getOutType();
|
||||
typeText = DescriptorRenderer.TEXT.renderType(outType);
|
||||
}
|
||||
else if (descriptor instanceof ClassDescriptor) {
|
||||
tailText = " (" + DescriptorUtils.getFQName(descriptor.getContainingDeclaration()) + ")";
|
||||
tailTextGrayed = true;
|
||||
}
|
||||
else {
|
||||
typeText = DescriptorRenderer.TEXT.render(descriptor);
|
||||
}
|
||||
|
||||
element = element.setTailText(tailText, tailTextGrayed).setTypeText(typeText);
|
||||
|
||||
if (declaration != null) {
|
||||
element = element.setIcon(declaration.getIcon(Iconable.ICON_FLAG_OPEN | Iconable.ICON_FLAG_VISIBILITY));
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static LookupElement createLookupElement(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor descriptor) {
|
||||
return createLookupElement(descriptor, bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor.getOriginal()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -2,17 +2,22 @@ package org.jetbrains.jet.plugin.completion;
|
||||
|
||||
import com.intellij.codeInsight.completion.*;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.patterns.PlatformPatterns;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
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 java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Nikolay Krasko
|
||||
@@ -23,9 +28,9 @@ public class JetCompletionContributor extends CompletionContributor {
|
||||
new CompletionProvider<CompletionParameters>() {
|
||||
@Override
|
||||
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context,
|
||||
final @NotNull CompletionResultSet _result) {
|
||||
final @NotNull CompletionResultSet result) {
|
||||
|
||||
if (_result.getPrefixMatcher().getPrefix().isEmpty()) {
|
||||
if (result.getPrefixMatcher().getPrefix().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -34,23 +39,55 @@ public class JetCompletionContributor extends CompletionContributor {
|
||||
return;
|
||||
}
|
||||
|
||||
CompletionResultSet result = _result.withPrefixMatcher(CompletionUtil.findReferenceOrAlphanumericPrefix(parameters));
|
||||
|
||||
if (shouldRunClassNameCompletion(parameters, context)) {
|
||||
JavaClassNameCompletionContributor.addAllClasses(parameters, JavaCompletionSorting.addJavaSorting(
|
||||
parameters, result), parameters.getInvocationCount() <= 1, new Consumer<LookupElement>() {
|
||||
|
||||
@Override
|
||||
public void consume(LookupElement element) {
|
||||
_result.addElement(element);
|
||||
|
||||
}
|
||||
});
|
||||
addJavaClasses(parameters, result);
|
||||
addJetClasses(result, position);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void addJetClasses(CompletionResultSet result, PsiElement position) {
|
||||
if (position.getParent() instanceof JetSimpleNameExpression) {
|
||||
final JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) position.getParent();
|
||||
if (PsiTreeUtil.getParentOfType(nameExpression, JetQualifiedExpression.class) == null) {
|
||||
Project project = position.getProject();
|
||||
|
||||
final String referencedName = nameExpression.getReferencedName();
|
||||
|
||||
if (referencedName != null && referencedName.endsWith(CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED)) {
|
||||
int lastPrefixIndex = referencedName.length() -
|
||||
CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED.length();
|
||||
String actualPrefix = referencedName.substring(0, lastPrefixIndex);
|
||||
|
||||
final Collection<ClassDescriptor> classDescriptors =
|
||||
JetCacheManager.getInstance(project).getNamesCache().getClassDescriptors();
|
||||
|
||||
for (ClassDescriptor descriptor : classDescriptors) {
|
||||
if (descriptor.getName().startsWith(actualPrefix)) {
|
||||
result.addElement(DescriptorLookupConverter.createLookupElement(descriptor, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addJavaClasses(CompletionParameters parameters, final CompletionResultSet result) {
|
||||
|
||||
CompletionResultSet tempResult = result.withPrefixMatcher(CompletionUtil.findReferenceOrAlphanumericPrefix(parameters));
|
||||
|
||||
JavaClassNameCompletionContributor.addAllClasses(parameters, JavaCompletionSorting.addJavaSorting(
|
||||
parameters, tempResult), parameters.getInvocationCount() <= 1, new Consumer<LookupElement>() {
|
||||
|
||||
@Override
|
||||
public void consume(LookupElement element) {
|
||||
result.addElement(element);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean shouldRunClassNameCompletion(@NotNull CompletionParameters parameters, ProcessingContext context) {
|
||||
final PsiElement element = parameters.getPosition();
|
||||
|
||||
@@ -75,4 +112,9 @@ public class JetCompletionContributor extends CompletionContributor {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeCompletion(@NotNull CompletionInitializationContext context) {
|
||||
super.beforeCompletion(context); //To change body of overridden methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.jetbrains.jet.plugin.quickfix;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -25,10 +24,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
|
||||
import org.jetbrains.jet.plugin.JetFileType;
|
||||
import org.jetbrains.jet.plugin.actions.JetAddImportAction;
|
||||
import org.jetbrains.jet.plugin.caches.JetCacheManager;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -56,31 +54,29 @@ public class ImportClassFix extends JetHintAction<JetSimpleNameExpression> imple
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final BindingContext context = AnalyzerFacade.analyzeFileWithCache(
|
||||
(JetFile) file, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER);
|
||||
|
||||
return getClassNames(element, context, file.getProject());
|
||||
return getClassNames(element, file.getProject());
|
||||
}
|
||||
|
||||
/*
|
||||
* Searches for possible class names in kotlin context and java facade.
|
||||
*/
|
||||
public static List<String> getClassNames(@NotNull JetSimpleNameExpression expression, @NotNull BindingContext context, @NotNull Project project) {
|
||||
public static List<String> getClassNames(@NotNull JetSimpleNameExpression expression, @NotNull Project project) {
|
||||
final String referenceName = expression.getReferencedName();
|
||||
|
||||
if (referenceName == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
|
||||
Set<String> possibleResolveNames = Sets.newHashSet();
|
||||
possibleResolveNames.addAll(filterPossibleTypes(referenceName, context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR)));
|
||||
possibleResolveNames.addAll(getJavaClasses(referenceName, project));
|
||||
possibleResolveNames.addAll(JetCacheManager.getInstance(project).getNamesCache().getFQNamesByName(referenceName, scope));
|
||||
possibleResolveNames.addAll(getJavaClasses(referenceName, project, scope));
|
||||
|
||||
// TODO: Do appropriate sorting
|
||||
return Lists.newArrayList(possibleResolveNames);
|
||||
}
|
||||
|
||||
private static Collection<String> getJavaClasses(@NotNull final String typeName, @NotNull Project project) {
|
||||
private static Collection<String> getJavaClasses(@NotNull final String typeName, @NotNull Project project, final GlobalSearchScope scope) {
|
||||
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
|
||||
|
||||
PsiClass[] classes = cache.getClassesByName(typeName, new DelegatingGlobalSearchScope(GlobalSearchScope.allScope(project)) {
|
||||
@@ -100,16 +96,6 @@ public class ImportClassFix extends JetHintAction<JetSimpleNameExpression> imple
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<String> filterPossibleTypes(@NotNull final String typeName, @NotNull Collection<String> variants) {
|
||||
return Collections2.filter(variants, new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable String fqName) {
|
||||
return fqName != null && (fqName.endsWith('.' + typeName) || fqName.equals(typeName));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showHint(@NotNull Editor editor) {
|
||||
if (suggestions.isEmpty()) {
|
||||
|
||||
@@ -2,23 +2,18 @@ package org.jetbrains.jet.plugin.references;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.compiler.TipsManager;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetPsiFactory;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
|
||||
import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler;
|
||||
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||
import org.jetbrains.jet.plugin.completion.DescriptorLookupConverter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,12 +22,6 @@ import java.util.List;
|
||||
*/
|
||||
class JetSimpleNameReference extends JetPsiReference {
|
||||
|
||||
private final static JetFunctionInsertHandler EMPTY_FUNCTION_HANDLER = new JetFunctionInsertHandler(
|
||||
JetFunctionInsertHandler.CaretPosition.AFTER_BRACKETS);
|
||||
|
||||
private final static JetFunctionInsertHandler PARAMS_FUNCTION_HANDLER = new JetFunctionInsertHandler(
|
||||
JetFunctionInsertHandler.CaretPosition.IN_BRACKETS);
|
||||
|
||||
private final JetSimpleNameExpression myExpression;
|
||||
|
||||
public JetSimpleNameReference(JetSimpleNameExpression jetSimpleNameExpression) {
|
||||
@@ -71,54 +60,9 @@ class JetSimpleNameReference extends JetPsiReference {
|
||||
List<LookupElement> result = Lists.newArrayList();
|
||||
|
||||
for (final DeclarationDescriptor descriptor : descriptors) {
|
||||
LookupElementBuilder element = LookupElementBuilder.create(descriptor, descriptor.getName());
|
||||
String typeText = "";
|
||||
String tailText = "";
|
||||
boolean tailTextGrayed = false;
|
||||
|
||||
if (descriptor instanceof FunctionDescriptor) {
|
||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||
JetType returnType = functionDescriptor.getReturnType();
|
||||
typeText = DescriptorRenderer.TEXT.renderType(returnType);
|
||||
|
||||
tailText = "(" + StringUtil.join(functionDescriptor.getValueParameters(), new Function<ValueParameterDescriptor, String>() {
|
||||
@Override
|
||||
public String fun(ValueParameterDescriptor valueParameterDescriptor) {
|
||||
return valueParameterDescriptor.getName() + ":" +
|
||||
DescriptorRenderer.TEXT.renderType(valueParameterDescriptor.getOutType());
|
||||
}
|
||||
}, ",") + ")";
|
||||
|
||||
|
||||
// TODO: A special case when it's impossible to resolve type parameters from arguments. Need '<' caret '>'
|
||||
// TODO: Support omitting brackets for one argument functions
|
||||
if (functionDescriptor.getValueParameters().isEmpty()) {
|
||||
element = element.setInsertHandler(EMPTY_FUNCTION_HANDLER);
|
||||
} else {
|
||||
element = element.setInsertHandler(PARAMS_FUNCTION_HANDLER);
|
||||
}
|
||||
}
|
||||
else if (descriptor instanceof VariableDescriptor) {
|
||||
JetType outType = ((VariableDescriptor) descriptor).getOutType();
|
||||
typeText = DescriptorRenderer.TEXT.renderType(outType);
|
||||
}
|
||||
else if (descriptor instanceof ClassDescriptor) {
|
||||
tailText = " (" + DescriptorUtils.getFQName(descriptor.getContainingDeclaration()) + ")";
|
||||
tailTextGrayed = true;
|
||||
}
|
||||
else {
|
||||
typeText = DescriptorRenderer.TEXT.render(descriptor);
|
||||
}
|
||||
|
||||
element = element.setTailText(tailText, tailTextGrayed).setTypeText(typeText);
|
||||
|
||||
PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor.getOriginal());
|
||||
if (declaration != null) {
|
||||
element = element.setIcon(declaration.getIcon(Iconable.ICON_FLAG_OPEN | Iconable.ICON_FLAG_VISIBILITY));
|
||||
}
|
||||
|
||||
result.add(element);
|
||||
result.add(DescriptorLookupConverter.createLookupElement(bindingContext, descriptor));
|
||||
}
|
||||
|
||||
return result.toArray();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user