Navigate to source when functions differ only in upper bounds of type parameters.
This commit is contained in:
@@ -17,8 +17,7 @@
|
|||||||
package org.jetbrains.jet.plugin.libraries;
|
package org.jetbrains.jet.plugin.libraries;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.*;
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.roots.OrderEntry;
|
import com.intellij.openapi.roots.OrderEntry;
|
||||||
import com.intellij.openapi.roots.OrderRootType;
|
import com.intellij.openapi.roots.OrderRootType;
|
||||||
@@ -31,6 +30,7 @@ import com.intellij.psi.search.GlobalSearchScope;
|
|||||||
import com.intellij.psi.search.GlobalSearchScopes;
|
import com.intellij.psi.search.GlobalSearchScopes;
|
||||||
import com.intellij.psi.stubs.StringStubIndexExtension;
|
import com.intellij.psi.stubs.StringStubIndexExtension;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
|
import com.intellij.util.Function;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -42,12 +42,14 @@ import org.jetbrains.jet.lang.resolve.lazy.FileBasedDeclarationProviderFactory;
|
|||||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
|
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
|
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
|
||||||
import org.jetbrains.jet.plugin.stubindex.JetTopLevelFunctionsFqnNameIndex;
|
import org.jetbrains.jet.plugin.stubindex.JetTopLevelFunctionsFqnNameIndex;
|
||||||
import org.jetbrains.jet.plugin.stubindex.JetTopLevelPropertiesFqnNameIndex;
|
import org.jetbrains.jet.plugin.stubindex.JetTopLevelPropertiesFqnNameIndex;
|
||||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||||
|
import org.jetbrains.jet.util.CommonSuppliers;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -257,7 +259,8 @@ public class JetSourceNavigationHelper {
|
|||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
Descr candidateDescriptor = (Descr) resolveSession.resolveToDescriptor(candidate);
|
Descr candidateDescriptor = (Descr) resolveSession.resolveToDescriptor(candidate);
|
||||||
if (receiversMatch(receiverType, candidateDescriptor.getReceiverParameter())
|
if (receiversMatch(receiverType, candidateDescriptor.getReceiverParameter())
|
||||||
&& navigationStrategy.declarationAndDescriptorMatchByParameterTypes(decompiledDeclaration, candidateDescriptor)) {
|
&& navigationStrategy.declarationAndDescriptorMatchByParameterTypes(decompiledDeclaration, candidateDescriptor)
|
||||||
|
&& typeParametersMatch((JetTypeParameterListOwner) decompiledDeclaration, candidateDescriptor.getTypeParameters())) {
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,6 +372,55 @@ public class JetSourceNavigationHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean typeParametersMatch(
|
||||||
|
@NotNull JetTypeParameterListOwner typeParameterListOwner,
|
||||||
|
@NotNull List<TypeParameterDescriptor> typeParameterDescriptors
|
||||||
|
) {
|
||||||
|
List<JetTypeParameter> decompiledParameters = typeParameterListOwner.getTypeParameters();
|
||||||
|
if (decompiledParameters.size() != typeParameterDescriptors.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Multimap<Name, String> decompiledParameterToBounds = Multimaps.newSetMultimap(
|
||||||
|
Maps.<Name, Collection<String>>newHashMap(), CommonSuppliers.<String>getHashSetSupplier());
|
||||||
|
for (JetTypeParameter parameter : decompiledParameters) {
|
||||||
|
JetTypeReference extendsBound = parameter.getExtendsBound();
|
||||||
|
if (extendsBound != null) {
|
||||||
|
decompiledParameterToBounds.put(parameter.getNameAsName(), extendsBound.getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (JetTypeConstraint typeConstraint : typeParameterListOwner.getTypeConstraints()) {
|
||||||
|
Name name = typeConstraint.getSubjectTypeParameterName().getReferencedNameAsName();
|
||||||
|
decompiledParameterToBounds.put(name, typeConstraint.getBoundTypeReference().getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < decompiledParameters.size(); i++) {
|
||||||
|
JetTypeParameter decompiledParameter = decompiledParameters.get(i);
|
||||||
|
TypeParameterDescriptor descriptor = typeParameterDescriptors.get(i);
|
||||||
|
|
||||||
|
if (!decompiledParameter.getNameAsName().equals(descriptor.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> descriptorUpperBounds = Sets.newHashSet(ContainerUtil.map(
|
||||||
|
descriptor.getUpperBounds(), new Function<JetType, String>() {
|
||||||
|
@Override
|
||||||
|
public String fun(JetType type) {
|
||||||
|
return DescriptorRenderer.TEXT.renderType(type);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
Set<String> decompiledUpperBounds = decompiledParameterToBounds.get(descriptor.getName()).isEmpty()
|
||||||
|
? Sets.newHashSet(DescriptorRenderer.TEXT.renderType(KotlinBuiltIns.getInstance().getDefaultBound()))
|
||||||
|
: Sets.newHashSet(decompiledParameterToBounds.get(descriptor.getName()));
|
||||||
|
if (!descriptorUpperBounds.equals(decompiledUpperBounds)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static JetNamedDeclaration getSourceProperty(final @NotNull JetProperty decompiledProperty) {
|
public static JetNamedDeclaration getSourceProperty(final @NotNull JetProperty decompiledProperty) {
|
||||||
return getSourcePropertyOrFunction(decompiledProperty, new PropertyNavigationStrategy());
|
return getSourcePropertyOrFunction(decompiledProperty, new PropertyNavigationStrategy());
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ package testData.libraries
|
|||||||
|
|
||||||
[public val <T> testData.libraries.Pair<T, T>.exProp : jet.String] /* compiled code */
|
[public val <T> testData.libraries.Pair<T, T>.exProp : jet.String] /* compiled code */
|
||||||
|
|
||||||
|
[public fun <T : jet.CharSequence> funWithTypeParam(t : T) : Unit { /* compiled code */ }]
|
||||||
|
|
||||||
|
[public fun <T : jet.Number> funWithTypeParam(t : T) : Unit { /* compiled code */ }]
|
||||||
|
|
||||||
[public fun func() : Unit { /* compiled code */ }]
|
[public fun func() : Unit { /* compiled code */ }]
|
||||||
|
|
||||||
[public fun func(cs : jet.CharSequence) : Unit { /* compiled code */ }]
|
[public fun func(cs : jet.CharSequence) : Unit { /* compiled code */ }]
|
||||||
|
|||||||
@@ -109,4 +109,11 @@ public class Double
|
|||||||
|
|
||||||
public fun processDouble(d: Double) {}
|
public fun processDouble(d: Double) {}
|
||||||
|
|
||||||
public fun processDouble(d: jet.Double) {}
|
public fun processDouble(d: jet.Double) {}
|
||||||
|
|
||||||
|
|
||||||
|
public fun <T: CharSequence> funWithTypeParam(t: T) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun <T: Number> funWithTypeParam(t: T) {
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import testData.libraries.*
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
funWithTypeParam(1)
|
||||||
|
funWithTypeParam("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// main.kt
|
||||||
|
//public fun <T: CharSequence> <2>funWithTypeParam(t: T) {
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//public fun <T: Number> <1>funWithTypeParam(t: T) {
|
||||||
@@ -84,6 +84,10 @@ public class NavigateToLibrarySourceTest extends AbstractNavigateToLibraryTest {
|
|||||||
doTest();
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testOverloadedFunWithTypeParam() {
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
private void doTest() {
|
private void doTest() {
|
||||||
userFile = LocalFileSystem.getInstance().findFileByPath(TEST_DATA_PATH + "/usercode/" + getTestName(false) + ".kt");
|
userFile = LocalFileSystem.getInstance().findFileByPath(TEST_DATA_PATH + "/usercode/" + getTestName(false) + ".kt");
|
||||||
assertNotNull(userFile);
|
assertNotNull(userFile);
|
||||||
|
|||||||
Reference in New Issue
Block a user