When checking overrides, compare methods structurally
Because they may come from different copies of the same class from different modules
This commit is contained in:
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.lang.resolve
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.Visibilities
|
||||
import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo
|
||||
import org.jetbrains.jet.lang.resolve
|
||||
|
||||
object DescriptorEquivalenceForOverrides {
|
||||
|
||||
public fun areEquivalent(a: DeclarationDescriptor?, b: DeclarationDescriptor?): Boolean {
|
||||
return when {
|
||||
a is ClassDescriptor &&
|
||||
b is ClassDescriptor -> areClassesEquivalent(a, b)
|
||||
|
||||
a is TypeParameterDescriptor &&
|
||||
b is TypeParameterDescriptor -> areTypeParametersEquivalent(a, b)
|
||||
|
||||
a is CallableMemberDescriptor &&
|
||||
b is CallableMemberDescriptor -> areCallableMemberDescriptorsEquivalent(a, b)
|
||||
|
||||
a is PackageFragmentDescriptor &&
|
||||
b is PackageFragmentDescriptor -> (a).fqName == (b).fqName
|
||||
|
||||
else -> a == b
|
||||
}
|
||||
}
|
||||
|
||||
private fun areClassesEquivalent(a: ClassDescriptor, b: ClassDescriptor): Boolean {
|
||||
// type constructors are compared by fqName
|
||||
return a.getTypeConstructor() == b.getTypeConstructor()
|
||||
}
|
||||
|
||||
private fun areTypeParametersEquivalent(
|
||||
a: TypeParameterDescriptor,
|
||||
b: TypeParameterDescriptor,
|
||||
equivalentCallables: (DeclarationDescriptor?, DeclarationDescriptor?) -> Boolean = {x, y -> false}
|
||||
): Boolean {
|
||||
if (a == b) return true
|
||||
if (a.getContainingDeclaration() == b.getContainingDeclaration()) return false
|
||||
|
||||
if (!ownersEquivalent(a, b, equivalentCallables)) return false
|
||||
|
||||
return a.getIndex() == b.getIndex() // We ignore type parameter names
|
||||
}
|
||||
|
||||
private fun areCallableMemberDescriptorsEquivalent(a: CallableMemberDescriptor, b: CallableMemberDescriptor): Boolean {
|
||||
if (a == b) return true
|
||||
if (a.getName() != b.getName()) return false
|
||||
if (a.getContainingDeclaration() == b.getContainingDeclaration()) return false
|
||||
|
||||
// Distinct locals are not equivalent
|
||||
if (DescriptorUtils.isLocal(a) || DescriptorUtils.isLocal(b)) return false
|
||||
|
||||
if (!ownersEquivalent(a, b, {x, y -> false})) return false
|
||||
|
||||
val overridingUtil = OverridingUtil.createWithEqualityAxioms @eq {
|
||||
(c1, c2): Boolean ->
|
||||
if (c1 == c2) return@eq true
|
||||
|
||||
val d1 = c1.getDeclarationDescriptor()
|
||||
val d2 = c2.getDeclarationDescriptor()
|
||||
|
||||
if (d1 !is TypeParameterDescriptor || d2 !is TypeParameterDescriptor) return@eq false
|
||||
|
||||
areTypeParametersEquivalent(d1, d2, {x, y -> x == a && y == b})
|
||||
}
|
||||
|
||||
return overridingUtil.isOverridableBy(a, b).getResult() == OverrideCompatibilityInfo.Result.OVERRIDABLE
|
||||
&& overridingUtil.isOverridableBy(b, a).getResult() == OverrideCompatibilityInfo.Result.OVERRIDABLE
|
||||
|
||||
}
|
||||
|
||||
private fun ownersEquivalent(
|
||||
a: DeclarationDescriptor,
|
||||
b: DeclarationDescriptor,
|
||||
equivalentCallables: (DeclarationDescriptor?, DeclarationDescriptor?) -> Boolean
|
||||
): Boolean {
|
||||
val aOwner = a.getContainingDeclaration()
|
||||
val bOwner = b.getContainingDeclaration()
|
||||
|
||||
// This check is needed when we call areTypeParametersEquivalent() from areCallableMemberDescriptorsEquivalent:
|
||||
// if the type parameter owners are, e.g., functions, we'll go into infinite recursion here
|
||||
if (aOwner is CallableMemberDescriptor || bOwner is CallableMemberDescriptor) {
|
||||
return equivalentCallables(aOwner, bOwner)
|
||||
}
|
||||
else {
|
||||
return areEquivalent(aOwner, bOwner)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.LinkedMultiMap;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.containers.hash.EqualityPolicy;
|
||||
import kotlin.Function1;
|
||||
import kotlin.Unit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -40,6 +41,7 @@ import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.jet.utils.HashSetUtil;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.*;
|
||||
@@ -225,14 +227,37 @@ public class OverrideResolver {
|
||||
@NotNull
|
||||
private static <D> Set<D> filterOverrides(
|
||||
@NotNull Set<D> candidateSet,
|
||||
@NotNull Function<? super D, ? extends CallableDescriptor> transform,
|
||||
@NotNull final Function<? super D, ? extends CallableDescriptor> transform,
|
||||
@NotNull Filtering filtering
|
||||
) {
|
||||
if (candidateSet.size() <= 1) return candidateSet;
|
||||
|
||||
// In a multi-module project different "copies" of the same class may be present in different libraries,
|
||||
// that's why we use structural equivalence for members (DescriptorEquivalenceForOverrides).
|
||||
// Here we filter out structurally equivalent descriptors before processing overrides, because such descriptors
|
||||
// "override" each other (overrides(f, g) = overrides(g, f) = true) and the code below removes them all from the
|
||||
// candidates, unless we first compute noDuplicates
|
||||
Set<D> noDuplicates = HashSetUtil.linkedHashSet(
|
||||
candidateSet,
|
||||
new EqualityPolicy<D>() {
|
||||
@Override
|
||||
public int getHashCode(D d) {
|
||||
return DescriptorUtils.getFqName(transform.fun(d).getContainingDeclaration()).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEqual(D d1, D d2) {
|
||||
CallableDescriptor f = transform.fun(d1);
|
||||
CallableDescriptor g = transform.fun(d2);
|
||||
return DescriptorEquivalenceForOverrides.instance$.areEquivalent(f.getOriginal(), g.getOriginal());
|
||||
}
|
||||
});
|
||||
|
||||
Set<D> candidates = Sets.newLinkedHashSet();
|
||||
outerLoop:
|
||||
for (D meD : candidateSet) {
|
||||
for (D meD : noDuplicates) {
|
||||
CallableDescriptor me = transform.fun(meD);
|
||||
for (D otherD : candidateSet) {
|
||||
for (D otherD : noDuplicates) {
|
||||
CallableDescriptor other = transform.fun(otherD);
|
||||
if (me == other) continue;
|
||||
if (filtering == Filtering.RETAIN_OVERRIDING) {
|
||||
@@ -259,13 +284,22 @@ public class OverrideResolver {
|
||||
}
|
||||
candidates.add(meD);
|
||||
}
|
||||
|
||||
assert !candidates.isEmpty() : "All candidates filtered out from " + candidateSet;
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
||||
// check whether f overrides g
|
||||
public static <D extends CallableDescriptor> boolean overrides(@NotNull D f, @NotNull D g) {
|
||||
// This first check cover the case of duplicate classes in different modules:
|
||||
// when B is defined in modules m1 and m2, and C (indirectly) inherits from both versions,
|
||||
// we'll be getting sets of members that do not override each other, but are structurally equivalent.
|
||||
// As other code relies on no equal descriptors passed here, we guard against f == g, but this may not be necessary
|
||||
if (!f.equals(g) && DescriptorEquivalenceForOverrides.instance$.areEquivalent(f.getOriginal(), g.getOriginal())) return true;
|
||||
CallableDescriptor originalG = g.getOriginal();
|
||||
for (D overriddenFunction : getAllOverriddenDescriptors(f)) {
|
||||
if (originalG.equals(overriddenFunction.getOriginal())) return true;
|
||||
if (DescriptorEquivalenceForOverrides.instance$.areEquivalent(originalG, overriddenFunction.getOriginal())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B<T> {
|
||||
public fun foo(a: T)
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C<X> : B<X> {
|
||||
override fun foo(a: X)
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B<T> {
|
||||
public fun foo(a: T)
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B<String>?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.foo("")
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// !DIAGNOSTICS: -BASE_WITH_NULLABLE_UPPER_BOUND -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B<T> {
|
||||
public fun foo(a: T?)
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C<X> : B<X> {
|
||||
override fun foo(a: X?)
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait Tr
|
||||
|
||||
public trait B<T: Tr?> {
|
||||
public fun foo(a: T?)
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B<Tr>?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.foo(null)
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// !DIAGNOSTICS: -BASE_WITH_NULLABLE_UPPER_BOUND
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B<T, _> {
|
||||
public fun foo(a: T?)
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C<X, _> : B<X, _> {
|
||||
override fun foo(a: X?)
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B<_, T> {
|
||||
public fun foo(a: T?)
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun <Y, Z> test(b: B<Y, Z>?) {
|
||||
if (b is C<Y, Z>) {
|
||||
b?.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>(null)
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B<T> {
|
||||
public fun foo(a: T)
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C<X> : B<X> {
|
||||
override fun foo(a: X)
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B<T1> {
|
||||
public fun foo(a: T1)
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun <Y> test(b: B<Y>?, y: Y) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.foo(y)
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B<T> {
|
||||
public fun <R> foo(a: T, b : R)
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B<Any?> {
|
||||
override fun <R> foo(a: Any?, b : R)
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun <T, R> foo(a: T, b: R)
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?, c: C) {
|
||||
b?.foo(1, 1)
|
||||
c.foo(1, 1)
|
||||
if (b is C) {
|
||||
b?.<!CANNOT_COMPLETE_RESOLVE!>foo<!>(1, 1)
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun foo(a: Int, b: String): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B {
|
||||
override fun foo(a: Int, b: String): B?
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun foo(a1: Int, b1: String): B?
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.foo(1, "")
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m0
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait G1<T>
|
||||
public trait G2<A, B>
|
||||
|
||||
// MODULE: m1(m0)
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun foo(a: G1<Int>?, b: G2<B, String>?)
|
||||
}
|
||||
|
||||
// MODULE: m2(m1, m0)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B {
|
||||
override fun foo(a: G1<Int>?, b: G2<B, String>?)
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3(m0)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun foo(a: G1<out Any?>?, b: G2<Int, out Any?>?)
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2, m0)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
b?.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>(null, null)
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun foo(a: Int, b: String): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B {
|
||||
override fun foo(a: Int, b: String): B?
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun foo(a: Int, b: String, c: Int = 0): B?
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
b?.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>(1, "")
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun getParent(): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B {
|
||||
override fun getParent(): B?
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun getParent(): Int
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.getParent()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun String.getParent(): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public class C : B {
|
||||
override fun String.getParent(): B? = null
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun String.getParent(): B?
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun B.test() {
|
||||
if (this is C) {
|
||||
"".getParent()
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun <T> foo(a: T): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B {
|
||||
override fun <T> foo(a: T): B?
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun <T> foo(a: T): B?
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.foo<String>("")
|
||||
}
|
||||
}
|
||||
|
||||
fun test1(b: B?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.foo("")
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun <T> foo(a: T): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B {
|
||||
override fun <T> foo(a: T): B?
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait Tr
|
||||
|
||||
public trait B {
|
||||
public fun <T: Tr?> foo(a: T): B?
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
// hard to find parameters for an ambiguous call, so we rely on NONE_APPLICABLE here
|
||||
// as opposed to diagnostics for a single unmatched candidate
|
||||
b?.<!NONE_APPLICABLE!>foo<!>()
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun <T> foo(a: T): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B {
|
||||
override fun <T> foo(a: T): B?
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun <T> foo(a: T): B?
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b == null) return
|
||||
b?.foo<String>("")
|
||||
}
|
||||
|
||||
fun test1(b: B?) {
|
||||
if (b != null) {
|
||||
b?.foo<String>("")
|
||||
}
|
||||
}
|
||||
|
||||
fun test2(b: B?) {
|
||||
if (b == null) return
|
||||
b?.foo("")
|
||||
}
|
||||
|
||||
fun test3(b: B?) {
|
||||
if (b != null) {
|
||||
b?.foo("")
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun <T> foo(a: T): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B {
|
||||
override fun <T> foo(a: T): B?
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun <T> foo(a: T): B?
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b !is C) return
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.foo("")
|
||||
}
|
||||
|
||||
fun test1(b: B?) {
|
||||
if (b !is C) return
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.foo<String>("")
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun foo(a: Int, b: String): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B {
|
||||
override fun foo(a: Int, b: String): B?
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun foo(a: Int, b: String): B?
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.foo(1, "")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun getParent(): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public class C : B {
|
||||
override fun getParent(): B? = null
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun getParent(): B?
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.getParent()
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_SAFE_CALL
|
||||
|
||||
// MODULE: m0
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait G1<T>
|
||||
public trait G2<A, B>
|
||||
|
||||
// MODULE: m1(m0)
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun foo(a: G1<Int>, b: G2<B, String>): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1, m0)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B {
|
||||
override fun foo(a: G1<Int>, b: G2<B, String>): B?
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3(m0)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun foo(a: G1<Int>, b: G2<B, String>): B?
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2, m0)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?, a: G1<Int>, b1: G2<B, String>) {
|
||||
if (b is C) {
|
||||
<!DEBUG_INFO_AUTOCAST!>b<!>?.foo(a, b1)
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun getParent(): B?
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B {
|
||||
override fun getParent(): B?
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun getParent(): B?
|
||||
}
|
||||
|
||||
public trait D : B {
|
||||
override fun getParent(): B?
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C && b is D) {
|
||||
b?.<!OVERLOAD_RESOLUTION_AMBIGUITY!>getParent<!>()
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// MODULE: m1
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
public trait B<T> {
|
||||
public fun foo(a: T)
|
||||
}
|
||||
|
||||
// MODULE: m2(m1)
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait C : B<String> {
|
||||
override fun foo(a: String)
|
||||
|
||||
}
|
||||
|
||||
// MODULE: m3
|
||||
// FILE: b.kt
|
||||
package p
|
||||
|
||||
public trait B {
|
||||
public fun foo(a: String)
|
||||
}
|
||||
|
||||
// MODULE: m4(m3, m2)
|
||||
// FILE: c.kt
|
||||
import p.*
|
||||
|
||||
fun test(b: B?) {
|
||||
if (b is C) {
|
||||
b?.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>("")
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// MODULE: m1
|
||||
// FILE: x.kt
|
||||
package p
|
||||
|
||||
public trait Base {
|
||||
public fun foo() {}
|
||||
}
|
||||
|
||||
public trait A : Base {
|
||||
override fun foo() {}
|
||||
}
|
||||
|
||||
public trait C : A
|
||||
|
||||
|
||||
// MODULE: m2
|
||||
// FILE: x.kt
|
||||
package p
|
||||
|
||||
public trait Base {
|
||||
public fun foo() {}
|
||||
}
|
||||
|
||||
public trait B : Base
|
||||
|
||||
// MODULE: m3(m1, m2)
|
||||
// FILE: x.kt
|
||||
|
||||
import p.*
|
||||
|
||||
class Foo: C, B
|
||||
@@ -0,0 +1,26 @@
|
||||
// MODULE: m1
|
||||
// FILE: x.kt
|
||||
package p
|
||||
|
||||
public trait Base {
|
||||
public fun foo() {}
|
||||
}
|
||||
|
||||
public trait A : Base
|
||||
|
||||
// MODULE: m2
|
||||
// FILE: x.kt
|
||||
package p
|
||||
|
||||
public trait Base {
|
||||
public fun foo() {}
|
||||
}
|
||||
|
||||
public trait B : Base
|
||||
|
||||
// MODULE: m3(m1, m2)
|
||||
// FILE: x.kt
|
||||
|
||||
import p.*
|
||||
|
||||
class Foo: A, B
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// MODULE: m1
|
||||
// FILE: x.kt
|
||||
package p
|
||||
|
||||
public trait Base {
|
||||
public fun <T> foo(t: Array<T>) {}
|
||||
}
|
||||
|
||||
public trait A : Base
|
||||
|
||||
// MODULE: m2
|
||||
// FILE: x.kt
|
||||
package p
|
||||
|
||||
public trait Base {
|
||||
public fun <T: Base> foo(t: Array<T>) {}
|
||||
}
|
||||
|
||||
public trait B : Base
|
||||
|
||||
// MODULE: m3(m1, m2)
|
||||
// FILE: x.kt
|
||||
|
||||
import p.*
|
||||
|
||||
class Foo: A, B {
|
||||
override fun <T> foo(t: Array<T>) {}
|
||||
override fun <T: Base> foo(t: Array<T>) {}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// MODULE: m1
|
||||
// FILE: x.kt
|
||||
package p
|
||||
|
||||
public trait Base<T> {
|
||||
public fun foo(t: T) {}
|
||||
}
|
||||
|
||||
public trait A<T> : Base<T>
|
||||
|
||||
// MODULE: m2
|
||||
// FILE: x.kt
|
||||
package p
|
||||
|
||||
public trait Base<T> {
|
||||
public fun foo(t: T) {}
|
||||
}
|
||||
|
||||
public trait B : Base<String>
|
||||
|
||||
// MODULE: m3(m1, m2)
|
||||
// FILE: x.kt
|
||||
|
||||
import p.*
|
||||
|
||||
class Foo: A<String>, B
|
||||
@@ -4687,7 +4687,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multimodule")
|
||||
@InnerTestClasses({Multimodule.DuplicateClass.class})
|
||||
@InnerTestClasses({Multimodule.DuplicateClass.class, Multimodule.DuplicateMethod.class, Multimodule.DuplicateSuper.class})
|
||||
public static class Multimodule extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInMultimodule() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/multimodule"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
@@ -4771,10 +4771,143 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multimodule/duplicateMethod")
|
||||
public static class DuplicateMethod extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInDuplicateMethod() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/multimodule/duplicateMethod"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("classGenericsInParams.kt")
|
||||
public void testClassGenericsInParams() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParams.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classGenericsInParamsBoundMismatch.kt")
|
||||
public void testClassGenericsInParamsBoundMismatch() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsBoundMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classGenericsInParamsIndexMismatch.kt")
|
||||
public void testClassGenericsInParamsIndexMismatch() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsIndexMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classGenericsInParamsNameMismatch.kt")
|
||||
public void testClassGenericsInParamsNameMismatch() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsNameMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classVsFunctionGenericsInParamsMismatch.kt")
|
||||
public void testClassVsFunctionGenericsInParamsMismatch() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classVsFunctionGenericsInParamsMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("differenceInParamNames.kt")
|
||||
public void testDifferenceInParamNames() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/differenceInParamNames.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("differentGenericsInParams.kt")
|
||||
public void testDifferentGenericsInParams() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/differentGenericsInParams.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("differentNumberOfParams.kt")
|
||||
public void testDifferentNumberOfParams() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/differentNumberOfParams.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("differentReturnTypes.kt")
|
||||
public void testDifferentReturnTypes() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/differentReturnTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("extensionMatch.kt")
|
||||
public void testExtensionMatch() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/extensionMatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionGenericsInParams.kt")
|
||||
public void testFunctionGenericsInParams() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParams.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionGenericsInParamsBoundsMismatch.kt")
|
||||
public void testFunctionGenericsInParamsBoundsMismatch() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsBoundsMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionGenericsInParamsEqNull.kt")
|
||||
public void testFunctionGenericsInParamsEqNull() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsEqNull.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionGenericsInParamsNotIs.kt")
|
||||
public void testFunctionGenericsInParamsNotIs() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/functionGenericsInParamsNotIs.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noGenericsInParams.kt")
|
||||
public void testNoGenericsInParams() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/noGenericsInParams.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noParams.kt")
|
||||
public void testNoParams() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/noParams.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("sameGenericsInParams.kt")
|
||||
public void testSameGenericsInParams() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/sameGenericsInParams.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleWithInheritance.kt")
|
||||
public void testSimpleWithInheritance() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/simpleWithInheritance.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("substitutedGenericInParams.kt")
|
||||
public void testSubstitutedGenericInParams() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateMethod/substitutedGenericInParams.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multimodule/duplicateSuper")
|
||||
public static class DuplicateSuper extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInDuplicateSuper() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/multimodule/duplicateSuper"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("differentSuperTraits.kt")
|
||||
public void testDifferentSuperTraits() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateSuper/differentSuperTraits.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("sameSuperTrait.kt")
|
||||
public void testSameSuperTrait() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateSuper/sameSuperTrait.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("sameSuperTraitDifferentBounds.kt")
|
||||
public void testSameSuperTraitDifferentBounds() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateSuper/sameSuperTraitDifferentBounds.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("sameSuperTraitGenerics.kt")
|
||||
public void testSameSuperTraitGenerics() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/multimodule/duplicateSuper/sameSuperTraitGenerics.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Test innerSuite() {
|
||||
TestSuite suite = new TestSuite("Multimodule");
|
||||
suite.addTestSuite(Multimodule.class);
|
||||
suite.addTestSuite(DuplicateClass.class);
|
||||
suite.addTestSuite(DuplicateMethod.class);
|
||||
suite.addTestSuite(DuplicateSuper.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.utils;
|
||||
|
||||
import com.intellij.util.containers.hash.EqualityPolicy;
|
||||
import com.intellij.util.containers.hash.LinkedHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class HashSetUtil {
|
||||
@NotNull
|
||||
public static <T> Set<T> linkedHashSet(@NotNull Set<T> set, @NotNull EqualityPolicy<T> policy) {
|
||||
// this implementation of LinkedHashMap doesn't admit nulls as values
|
||||
Map<T, String> map = new LinkedHashMap<T, String>(policy);
|
||||
for (T t : set) {
|
||||
map.put(t, "");
|
||||
}
|
||||
return map.keySet();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user