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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user