KT-1373 Completion suggests constructors in type position

KT-1316 Type name completion inserts fully qualified name when works in incomplete code
This commit is contained in:
Nikolay Krasko
2012-03-05 18:36:12 +04:00
parent b6161cb41b
commit 77150f02d9
19 changed files with 218 additions and 32 deletions
@@ -425,4 +425,9 @@ public class JetStandardClasses {
List<TypeProjection> arguments = type.getArguments();
return arguments.get(arguments.size() - 1).getType();
}
@NotNull
public static Collection<DeclarationDescriptor> getAllStandardClasses() {
return STANDARD_CLASSES.getAllDescriptors();
}
}
@@ -193,6 +193,22 @@ public class JetStandardLibrary {
jetArrayTypeToPrimitiveJetType.put(arrayType, type);
}
public Collection<ClassDescriptor> getStandardTypes() {
initStdClasses();
Collection<ClassDescriptor> classDescriptors = new ArrayList<ClassDescriptor>(primitiveTypeToClass.values());
classDescriptors.add(numberClass);
classDescriptors.add(stringClass);
classDescriptors.add(charSequenceClass);
classDescriptors.add(arrayClass);
classDescriptors.add(volatileClass);
classDescriptors.add(throwableClass);
classDescriptors.add(iterableClass);
classDescriptors.add(comparableClass);
return classDescriptors;
}
@NotNull
public ClassDescriptor getNumber() {
initStdClasses();
@@ -258,7 +274,7 @@ public class JetStandardLibrary {
}
@NotNull
public ClassDescriptor getArray() {
public ClassDescriptor getArray() {
initStdClasses();
return arrayClass;
}
@@ -16,6 +16,7 @@
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;
@@ -32,9 +33,13 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.asJava.JavaElementFinder;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.plugin.stubindex.JetExtensionFunctionNameIndex;
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
@@ -42,10 +47,7 @@ import org.jetbrains.jet.plugin.stubindex.JetShortClassNameIndex;
import org.jetbrains.jet.plugin.stubindex.JetShortFunctionNameIndex;
import org.jetbrains.jet.util.QualifiedNamesUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
* Will provide both java elements from jet context and some special declarations special to jet.
@@ -79,7 +81,6 @@ public class JetShortNamesCache extends PsiShortNamesCache {
@NotNull
@Override
public PsiClass[] getClassesByName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) {
// Quick check for classes from getAllClassNames()
Collection<String> classNames = JetShortClassNameIndex.getInstance().getAllKeys(project);
if (!classNames.contains(name)) {
@@ -101,14 +102,29 @@ public class JetShortNamesCache extends PsiShortNamesCache {
}
@Override
public void getAllClassNames(@NotNull HashSet<String> dest) {
// TODO: Implement it. Is it called somewhere?
public void getAllClassNames(@NotNull HashSet<String> destination) {
destination.addAll(Arrays.asList(getAllClassNames()));
}
// public Collection<String> getALlJetClassFQNames() {
// final BindingContext context = getResolutionContext(GlobalSearchScope.allScope(project));
// return context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR);
// }
/**
* Types that should be visible in completion from kotlin but should be absent in java.
* @return
*/
@NotNull
public static Collection<DeclarationDescriptor> getJetOnlyTypes() {
Collection<DeclarationDescriptor> standardTypes = JetStandardClasses.getAllStandardClasses();
standardTypes.addAll(
Collections2.transform(JetStandardLibrary.getInstance().getStandardTypes(),
new Function<ClassDescriptor, DeclarationDescriptor>() {
@Override
public DeclarationDescriptor apply(@Nullable ClassDescriptor classDescriptor) {
assert classDescriptor != null;
return classDescriptor;
}
}));
return standardTypes;
}
@NotNull
public Collection<String> getFQNamesByName(@NotNull final String name, @NotNull GlobalSearchScope scope) {
@@ -18,16 +18,24 @@ 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.PsiReference;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.Consumer;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.plugin.caches.JetCacheManager;
import org.jetbrains.jet.plugin.caches.JetShortNamesCache;
import org.jetbrains.jet.plugin.completion.handlers.JetJavaClassInsertHandler;
import org.jetbrains.jet.plugin.references.JetSimpleNameReference;
import java.util.Collection;
/**
* @author Nikolay Krasko
*/
@@ -67,9 +75,22 @@ public class JetClassCompletionContributor extends CompletionContributor {
@NotNull final Consumer<LookupElement> consumer) {
CompletionResultSet tempResult = result.withPrefixMatcher(CompletionUtil.findReferenceOrAlphanumericPrefix(parameters));
Project project = parameters.getPosition().getProject();
JetShortNamesCache namesCache = JetCacheManager.getInstance(project).getNamesCache();
// TODO: Make icon for standard types
Collection<DeclarationDescriptor> jetOnlyClasses = JetShortNamesCache.getJetOnlyTypes();
BindingContext bindingContext = namesCache.getResolutionContext(GlobalSearchScope.allScope(project));
for (DeclarationDescriptor jetOnlyClass : jetOnlyClasses) {
consumer.consume(DescriptorLookupConverter.createLookupElement(bindingContext, jetOnlyClass));
}
JavaClassNameCompletionContributor.addAllClasses(
parameters,
parameters.getInvocationCount() <= 2,
false,
JavaCompletionSorting.addJavaSorting(parameters, tempResult).getPrefixMatcher(),
new Consumer<LookupElement>() {
@Override
@@ -62,10 +62,6 @@ public class JetCompletionContributor extends CompletionContributor {
Set<LookupPositionObject> positions = new HashSet<LookupPositionObject>();
if (result.getPrefixMatcher().getPrefix().isEmpty()) {
return;
}
PsiElement position = parameters.getPosition();
if (!(position.getContainingFile() instanceof JetFile)) {
return;
@@ -73,12 +69,23 @@ public class JetCompletionContributor extends CompletionContributor {
JetSimpleNameReference jetReference = getJetReference(parameters);
if (jetReference != null) {
if (shouldRunTypeCompletionOnly(position, jetReference)) {
addClasses(parameters, result);
result.stopHere();
return;
}
for (Object variant : jetReference.getVariants()) {
addReferenceVariant(result, variant, positions);
}
if (result.getPrefixMatcher().getPrefix().isEmpty()) {
return;
}
if (shouldRunTopLevelCompletion(parameters)) {
addClasses(parameters, result, positions);
addClasses(parameters, result);
addJetTopLevelFunctions(result, position, positions);
addJetExtensionFunctions(jetReference.getExpression(), result, position);
}
@@ -95,7 +102,6 @@ public class JetCompletionContributor extends CompletionContributor {
BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) position.getContainingFile());
JetExpression receiverExpression = expression.getReceiverExpression();
if (receiverExpression != null) {
JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
JetScope scope = context.get(BindingContext.RESOLUTION_SCOPE, receiverExpression);
@@ -185,17 +191,28 @@ public class JetCompletionContributor extends CompletionContributor {
*/
private static void addClasses(
@NotNull CompletionParameters parameters,
@NotNull final CompletionResultSet result,
@NotNull final Set<LookupPositionObject> positions) {
@NotNull final CompletionResultSet result
) {
JetClassCompletionContributor.addClasses(parameters, result, new Consumer<LookupElement>() {
@Override
public void consume(@NotNull LookupElement element) {
addCompletionToResult(result, element, positions);
result.addElement(element);
}
});
}
private static boolean shouldRunTypeCompletionOnly(PsiElement position, JetSimpleNameReference jetReference) {
// Check that completion in the type annotation context and if there's a qualified
// expression we are at first of it
JetTypeReference typeReference = PsiTreeUtil.getParentOfType(position, JetTypeReference.class);
if (typeReference != null) {
JetSimpleNameExpression firstPartReference = PsiTreeUtil.findChildOfType(typeReference, JetSimpleNameExpression.class);
return firstPartReference == jetReference.getExpression();
}
return false;
}
private static boolean shouldRunTopLevelCompletion(@NotNull CompletionParameters parameters) {
PsiElement element = parameters.getPosition();
@@ -260,11 +277,9 @@ public class JetCompletionContributor extends CompletionContributor {
private static LookupPositionObject getLookupPosition(LookupElement element) {
Object lookupObject = element.getObject();
if (lookupObject instanceof PsiElement) {
// PsiElement psiElement = (PsiElement) lookupObject;
return new LookupPositionObject((PsiElement) lookupObject);
}
else if (lookupObject instanceof JetLookupObject) {
// JetLookupObject jetLookupObject = (JetLookupObject) lookupObject;
PsiElement psiElement = ((JetLookupObject) lookupObject).getPsiElement();
if (psiElement != null) {
return new LookupPositionObject(psiElement);
@@ -344,6 +344,4 @@ public class JetKeywordCompletionContributor extends CompletionContributor {
new FilterPattern(new AndFilter(GENERAL_FILTER, placeFilter)));
}
}
}
@@ -0,0 +1,14 @@
public StringMethod() : String {
}
open class StringMy() {
}
public class Test : String<caret> {
}
// EXIST: StringMy
// EXIST: String
// ABSENT: StringMethod
@@ -0,0 +1,8 @@
class Test {
fun test() {
<caret>
}
}
// EXIST: Any, Nothing, Tuple0, Int, Number
// EXIST: Array, Math, Hashable, OutputStream
@@ -0,0 +1,7 @@
class Test : <caret> {
fun test() {
}
}
// EXIST: Any, Nothing, Tuple0, Int, Number
// EXIST: Array, Math, Hashable, OutputStream
@@ -0,0 +1,3 @@
package classCompletionImport
fun other() : SortedS<caret>
@@ -0,0 +1,5 @@
package classCompletionImport
import java.util.SortedSet
fun other() : SortedSet
@@ -1,3 +1,5 @@
package somefortest
fun test(a: Int) {
}
@@ -1,3 +1,5 @@
package somefortest
fun test(a: Int) {
}
@@ -1,3 +1,5 @@
package propertiesSetter
class TestClass {
val a : Int
ge<caret>
@@ -1,3 +1,5 @@
package propertiesSetter
class TestClass {
val a : Int
get()<caret>
@@ -77,6 +77,10 @@ public class JetBasicCompletionTest extends JetCompletionTestBase {
doTest();
}
public void testInTypeAnnotation() {
doTest();
}
public void testJavaClassNames() {
doTest();
}
@@ -0,0 +1,47 @@
/*
* Copyright 2000-2012 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.completion;
import com.intellij.codeInsight.completion.CompletionType;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
import java.io.File;
/**
* @author Nikolay Krasko
*/
public class JetClassCompletionTest extends JetCompletionTestBase {
public void testInExpressionNoPrefix() {
doTest();
}
public void testInExtendTypeAnnotation() {
doTest();
}
@Override
protected CompletionType getCompletionType(String testName, String fileText) {
return CompletionType.CLASS_NAME;
}
@Override
protected String getTestDataPath() {
return new File(PluginTestCaseBase.getTestDataPathBase(), "/completion/class").getPath() +
File.separator;
}
}
@@ -45,12 +45,10 @@ public abstract class JetCompletionTestBase extends LightCompletionTestCase {
protected void doTest() {
try {
final String testName = getTestName(false);
type = (testName.startsWith("Smart")) ? CompletionType.SMART : CompletionType.BASIC;
configureByFileNoComplete(testName + ".kt");
final String fileText = getFile().getText();
type = getCompletionType(testName, fileText);
boolean withKotlinRuntime = ExpectedCompletionUtils.getPrefixedInt(fileText, "// RUNTIME:") != null;
@@ -88,6 +86,10 @@ public abstract class JetCompletionTestBase extends LightCompletionTestCase {
}
}
protected CompletionType getCompletionType(String testName, String fileText) {
return (testName.startsWith("Smart")) ? CompletionType.SMART : CompletionType.BASIC;
}
protected static void configureWithKotlinRuntime() {
final ModuleRootManager rootManager = ModuleRootManager.getInstance(getModule());
final ModifiableRootModel rootModel = rootManager.getModifiableModel();
@@ -16,8 +16,11 @@
package org.jetbrains.jet.completion.handlers;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.LightCompletionTestCase;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.projectRoots.Sdk;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
import java.io.File;
@@ -27,6 +30,10 @@ import java.io.File;
*/
public class CompletionHandlerTest extends LightCompletionTestCase {
public void testClassCompletionImport() {
doTest(CompletionType.CLASS_NAME, 1, "SortedSet");
}
public void testNoParamsFunction() {
doTest();
}
@@ -54,15 +61,25 @@ public class CompletionHandlerTest extends LightCompletionTestCase {
}
public void doTest() {
doTest(CompletionType.BASIC, 2, null);
}
public void doTest(CompletionType type, int time, @Nullable String completeItem) {
String fileName = getTestName(false);
try {
configureByFileNoComplete(fileName + ".kt");
complete(2);
setType(type);
complete(time);
if (completeItem != null) {
selectItem(LookupElementBuilder.create(completeItem), '\t');
}
checkResultByFile(fileName + ".kt.after");
} catch (Exception e) {
throw new AssertionError(e);
}
}
@Override