Report resolution ambiguity on '+=' by taking into account full resolution result including post type checking for '+'
^KT-45503 Fixed
This commit is contained in:
+24
@@ -19429,6 +19429,24 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.kt");
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt45503_1.kt")
|
||||||
|
public void testKt45503_1() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt45503_1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt45503_2.kt")
|
||||||
|
public void testKt45503_2() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt45503_2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt45503_3.kt")
|
||||||
|
public void testKt45503_3() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt45503_3.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("plusAssignOnArray.kt")
|
@TestMetadata("plusAssignOnArray.kt")
|
||||||
public void testPlusAssignOnArray() throws Exception {
|
public void testPlusAssignOnArray() throws Exception {
|
||||||
@@ -19446,6 +19464,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
public void testPlusAssignOnProperty() throws Exception {
|
public void testPlusAssignOnProperty() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnProperty.kt");
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnProperty.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("plusAssignOnVarAndCollections.kt")
|
||||||
|
public void testPlusAssignOnVarAndCollections() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnVarAndCollections.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
|
|||||||
+66
-26
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.types.expressions;
|
package org.jetbrains.kotlin.types.expressions;
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.Ref;
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import kotlin.Pair;
|
import kotlin.Pair;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -243,22 +244,23 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
|
|||||||
TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create(
|
TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create(
|
||||||
context, "trace to check binary operation like '+' for", expression);
|
context, "trace to check binary operation like '+' for", expression);
|
||||||
TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(context.trace, "Trace for checking assignability");
|
TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(context.trace, "Trace for checking assignability");
|
||||||
|
ExpressionTypingContext contextForBinaryOperation = null;
|
||||||
|
|
||||||
boolean lhsAssignable = basic.checkLValue(ignoreReportsTrace, context, left, right, expression, false);
|
boolean lhsAssignable = basic.checkLValue(ignoreReportsTrace, context, left, right, expression, false);
|
||||||
|
|
||||||
if (assignmentOperationType == null || lhsAssignable) {
|
if (assignmentOperationType == null || lhsAssignable) {
|
||||||
|
contextForBinaryOperation = context.replaceTraceAndCache(temporaryForBinaryOperation).replaceScope(scope);
|
||||||
// Check for '+'
|
// Check for '+'
|
||||||
// We should clear calls info for coroutine inference within right side as here we analyze it a second time in another context
|
// We should clear calls info for coroutine inference within right side as here we analyze it a second time in another context
|
||||||
if (context.inferenceSession instanceof BuilderInferenceSession) {
|
if (context.inferenceSession instanceof BuilderInferenceSession) {
|
||||||
((BuilderInferenceSession) context.inferenceSession).clearCallsInfoByContainingElement(right);
|
((BuilderInferenceSession) context.inferenceSession).clearCallsInfoByContainingElement(right);
|
||||||
}
|
}
|
||||||
Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
|
Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
|
||||||
binaryOperationDescriptors = components.callResolver.resolveBinaryCall(
|
binaryOperationDescriptors =
|
||||||
context.replaceTraceAndCache(temporaryForBinaryOperation).replaceScope(scope),
|
components.callResolver.resolveBinaryCall(contextForBinaryOperation, receiver, expression, counterpartName);
|
||||||
receiver, expression, counterpartName
|
|
||||||
);
|
|
||||||
|
|
||||||
binaryOperationType = OverloadResolutionResultsUtil.getResultingType(binaryOperationDescriptors, context);
|
binaryOperationType = OverloadResolutionResultsUtil.getResultingType(binaryOperationDescriptors, context);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
binaryOperationDescriptors = OverloadResolutionResultsImpl.nameNotFound();
|
binaryOperationDescriptors = OverloadResolutionResultsImpl.nameNotFound();
|
||||||
binaryOperationType = null;
|
binaryOperationType = null;
|
||||||
}
|
}
|
||||||
@@ -270,7 +272,22 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
|
|||||||
boolean hasRemBinaryOperation = atLeastOneOperation(binaryOperationDescriptors.getResultingCalls(), OperatorNameConventions.REM);
|
boolean hasRemBinaryOperation = atLeastOneOperation(binaryOperationDescriptors.getResultingCalls(), OperatorNameConventions.REM);
|
||||||
|
|
||||||
boolean oneTypeOfModRemOperations = hasRemAssignOperation == hasRemBinaryOperation;
|
boolean oneTypeOfModRemOperations = hasRemAssignOperation == hasRemBinaryOperation;
|
||||||
if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess() && oneTypeOfModRemOperations) {
|
|
||||||
|
boolean maybeAmbiguity = assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess() && oneTypeOfModRemOperations;
|
||||||
|
boolean isResolvedToPlusAssign = assignmentOperationType != null &&
|
||||||
|
(assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess()) &&
|
||||||
|
(!hasRemBinaryOperation || !binaryOperationDescriptors.isSuccess());
|
||||||
|
|
||||||
|
KotlinTypeInfo rhsResolutionResult;
|
||||||
|
// We complete resolution for 'plus' only if there may be ambiguity (in this case we can disambiguate it),
|
||||||
|
// or it definitely won't be resolved to plus assign (in this case we would analyse right side twice)
|
||||||
|
if (maybeAmbiguity || !isResolvedToPlusAssign) {
|
||||||
|
rhsResolutionResult = completePlusResolution(contextForBinaryOperation, expression, binaryOperationType, left, leftInfo);
|
||||||
|
} else {
|
||||||
|
rhsResolutionResult = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maybeAmbiguity && rhsResolutionResult != null) {
|
||||||
// Both 'plus()' and 'plusAssign()' available => ambiguity
|
// Both 'plus()' and 'plusAssign()' available => ambiguity
|
||||||
OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
|
OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
|
||||||
context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
|
context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
|
||||||
@@ -278,39 +295,62 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
|
|||||||
for (ResolvedCall<?> resolvedCall : ambiguityResolutionResults.getResultingCalls()) {
|
for (ResolvedCall<?> resolvedCall : ambiguityResolutionResults.getResultingCalls()) {
|
||||||
descriptors.add(resolvedCall.getResultingDescriptor());
|
descriptors.add(resolvedCall.getResultingDescriptor());
|
||||||
}
|
}
|
||||||
rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
|
rightInfo = rhsResolutionResult;
|
||||||
context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
|
context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
|
||||||
}
|
} else if (isResolvedToPlusAssign) {
|
||||||
else if (assignmentOperationType != null &&
|
|
||||||
(assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess()) &&
|
|
||||||
(!hasRemBinaryOperation || !binaryOperationDescriptors.isSuccess())) {
|
|
||||||
// There's 'plusAssign()', so we do a.plusAssign(b)
|
// There's 'plusAssign()', so we do a.plusAssign(b)
|
||||||
temporaryForAssignmentOperation.commit();
|
temporaryForAssignmentOperation.commit();
|
||||||
if (!KotlinTypeChecker.DEFAULT.equalTypes(components.builtIns.getUnitType(), assignmentOperationType)) {
|
if (!KotlinTypeChecker.DEFAULT.equalTypes(components.builtIns.getUnitType(), assignmentOperationType)) {
|
||||||
context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
|
context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
if (rhsResolutionResult != null) {
|
||||||
|
rightInfo = rhsResolutionResult;
|
||||||
|
}
|
||||||
// There's only 'plus()', so we try 'a = a + b'
|
// There's only 'plus()', so we try 'a = a + b'
|
||||||
temporaryForBinaryOperation.commit();
|
temporaryForBinaryOperation.commit();
|
||||||
context.trace.record(VARIABLE_REASSIGNMENT, expression);
|
context.trace.record(VARIABLE_REASSIGNMENT, expression);
|
||||||
if (left instanceof KtArrayAccessExpression) {
|
|
||||||
ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(
|
|
||||||
context.trace, "trace to resolve array set method for assignment", expression));
|
|
||||||
basic.resolveImplicitArrayAccessSetMethod((KtArrayAccessExpression) left, right, contextForResolve, context.trace);
|
|
||||||
}
|
|
||||||
rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
|
|
||||||
|
|
||||||
KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftType);
|
|
||||||
|
|
||||||
components.dataFlowAnalyzer.checkType(binaryOperationType, expression, context.replaceExpectedType(expectedType)
|
|
||||||
.replaceDataFlowInfo(rightInfo.getDataFlowInfo()).replaceCallPosition(new CallPosition.PropertyAssignment(left, false)));
|
|
||||||
basic.checkLValue(context.trace, context, leftOperand, right, expression, false);
|
|
||||||
}
|
}
|
||||||
temporary.commit();
|
temporary.commit();
|
||||||
return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType));
|
return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private KotlinTypeInfo completePlusResolution(
|
||||||
|
ExpressionTypingContext context,
|
||||||
|
KtBinaryExpression expression,
|
||||||
|
KotlinType binaryOperationType,
|
||||||
|
KtExpression leftDeparentized,
|
||||||
|
KotlinTypeInfo leftInfo
|
||||||
|
) {
|
||||||
|
KtExpression leftOperand = expression.getLeft();
|
||||||
|
KtExpression rightOperand = expression.getRight();
|
||||||
|
|
||||||
|
if (leftOperand == null || rightOperand == null) return null;
|
||||||
|
|
||||||
|
if (leftDeparentized instanceof KtArrayAccessExpression) {
|
||||||
|
ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(
|
||||||
|
context.trace, "trace to resolve array set method for assignment", expression));
|
||||||
|
basic.resolveImplicitArrayAccessSetMethod((KtArrayAccessExpression) leftDeparentized, rightOperand, contextForResolve, context.trace);
|
||||||
|
}
|
||||||
|
KotlinTypeInfo rightInfo = facade.getTypeInfo(rightOperand, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
|
||||||
|
|
||||||
|
KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftInfo.getType());
|
||||||
|
|
||||||
|
Ref<Boolean> hasErrorsOnTypeChecking = Ref.create(false);
|
||||||
|
components.dataFlowAnalyzer.checkType(
|
||||||
|
binaryOperationType,
|
||||||
|
expression,
|
||||||
|
context.replaceExpectedType(expectedType)
|
||||||
|
.replaceDataFlowInfo(rightInfo.getDataFlowInfo())
|
||||||
|
.replaceCallPosition(new CallPosition.PropertyAssignment(leftDeparentized, false)),
|
||||||
|
hasErrorsOnTypeChecking,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
basic.checkLValue(context.trace, context, leftOperand, rightOperand, expression, false);
|
||||||
|
|
||||||
|
return !hasErrorsOnTypeChecking.get() ? rightInfo : null;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean atLeastOneOperation(Collection<? extends ResolvedCall<FunctionDescriptor>> calls, Name operationName) {
|
private static boolean atLeastOneOperation(Collection<? extends ResolvedCall<FunctionDescriptor>> calls, Name operationName) {
|
||||||
for (ResolvedCall<FunctionDescriptor> call : calls) {
|
for (ResolvedCall<FunctionDescriptor> call : calls) {
|
||||||
if (call.getCandidateDescriptor().getName().equals(operationName)) {
|
if (call.getCandidateDescriptor().getName().equals(operationName)) {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
class A<T>
|
||||||
|
class B<T>(val x: MutableList<T>) : MutableList<T> by x
|
||||||
|
|
||||||
|
class C {
|
||||||
|
operator fun <T> get(k: A<T>): T = TODO()
|
||||||
|
operator fun <T> set(k: A<T>, v: T): Unit = TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
C()[A<B<Int>>()] += 2
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
class A<T>
|
||||||
|
class B<T>(val x: MutableList<T>) : MutableList<T> by x
|
||||||
|
|
||||||
|
class C {
|
||||||
|
operator fun <T> get(k: A<T>): T = TODO()
|
||||||
|
operator fun <T> set(k: A<T>, v: T): Unit = TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
C()[A<B<Int>>()] += 2
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
class A<T>(var x: T)
|
||||||
|
|
||||||
|
interface I
|
||||||
|
|
||||||
|
class C {
|
||||||
|
operator fun <T> get(k: A<T>): T = k.x
|
||||||
|
operator fun <T : I> set(k: A<T>, v: T) { k.x = v }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
C()[A(mutableListOf(1))] += 2
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
class A<T>(var x: T)
|
||||||
|
|
||||||
|
interface I
|
||||||
|
|
||||||
|
class C {
|
||||||
|
operator fun <T> get(k: A<T>): T = k.x
|
||||||
|
operator fun <T : I> set(k: A<T>, v: T) { k.x = v }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
C()[A(mutableListOf(1))] += 2
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
class A<T>
|
||||||
|
class C
|
||||||
|
interface I
|
||||||
|
|
||||||
|
class E {
|
||||||
|
operator fun <T> get(k: A<T>): T = TODO()
|
||||||
|
operator fun <T : I> set(k: A<T>, v: T) { TODO() }
|
||||||
|
operator fun set(k: A<C>, v: C) { TODO() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
E()[A<MutableList<Int>>()] += 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
class A<T>
|
||||||
|
class C
|
||||||
|
interface I
|
||||||
|
|
||||||
|
class E {
|
||||||
|
operator fun <T> get(k: A<T>): T = TODO()
|
||||||
|
operator fun <T : I> set(k: A<T>, v: T) { TODO() }
|
||||||
|
operator fun set(k: A<C>, v: C) { TODO() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
E()[A<MutableList<Int>>()] += 1
|
||||||
|
}
|
||||||
Vendored
+31
@@ -0,0 +1,31 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun test1() {
|
||||||
|
var list = ArrayList<Int>()
|
||||||
|
<!ASSIGN_OPERATOR_AMBIGUITY!>list -= 2<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test2() {
|
||||||
|
var set = HashMap<Int, Int>()
|
||||||
|
<!ASSIGN_OPERATOR_AMBIGUITY!>set += 2 to 2<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test3() {
|
||||||
|
var set = HashSet<Int>()
|
||||||
|
<!ASSIGN_OPERATOR_AMBIGUITY!>set -= 2<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test4() {
|
||||||
|
var list = mutableListOf(1)
|
||||||
|
<!ASSIGN_OPERATOR_AMBIGUITY!>list += 2<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test5() {
|
||||||
|
var map = mutableMapOf(1 to 1)
|
||||||
|
<!ASSIGN_OPERATOR_AMBIGUITY!>map += 2 to 2<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test6() {
|
||||||
|
var set = mutableSetOf(1)
|
||||||
|
<!ASSIGN_OPERATOR_AMBIGUITY!>set += 2<!>
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun test1() {
|
||||||
|
var list = ArrayList<Int>()
|
||||||
|
list -= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test2() {
|
||||||
|
var set = HashMap<Int, Int>()
|
||||||
|
set += 2 to 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test3() {
|
||||||
|
var set = HashSet<Int>()
|
||||||
|
set -= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test4() {
|
||||||
|
var list = mutableListOf(1)
|
||||||
|
list += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test5() {
|
||||||
|
var map = mutableMapOf(1 to 1)
|
||||||
|
map += 2 to 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test6() {
|
||||||
|
var set = mutableSetOf(1)
|
||||||
|
set += 2
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun test1(): kotlin.Unit
|
||||||
|
public fun test2(): kotlin.Unit
|
||||||
|
public fun test3(): kotlin.Unit
|
||||||
|
public fun test4(): kotlin.Unit
|
||||||
|
public fun test5(): kotlin.Unit
|
||||||
|
public fun test6(): kotlin.Unit
|
||||||
|
|
||||||
Generated
+24
@@ -19435,6 +19435,24 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.kt");
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt3450.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt45503_1.kt")
|
||||||
|
public void testKt45503_1() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt45503_1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt45503_2.kt")
|
||||||
|
public void testKt45503_2() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt45503_2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("kt45503_3.kt")
|
||||||
|
public void testKt45503_3() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/kt45503_3.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("plusAssignOnArray.kt")
|
@TestMetadata("plusAssignOnArray.kt")
|
||||||
public void testPlusAssignOnArray() throws Exception {
|
public void testPlusAssignOnArray() throws Exception {
|
||||||
@@ -19452,6 +19470,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
public void testPlusAssignOnProperty() throws Exception {
|
public void testPlusAssignOnProperty() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnProperty.kt");
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnProperty.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("plusAssignOnVarAndCollections.kt")
|
||||||
|
public void testPlusAssignOnVarAndCollections() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnVarAndCollections.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// PROBLEM: none
|
// PROBLEM: none
|
||||||
// ERROR: Assignment operators ambiguity: <br>public operator fun <T> Collection<Int>.plus(element: Int): List<Int> defined in kotlin.collections<br>public inline operator fun <T> MutableCollection<in Int>.plusAssign(element: Int): Unit defined in kotlin.collections
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
fun test() {
|
fun test() {
|
||||||
var list = mutableListOf(1)
|
var list = mutableListOf(1)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// PROBLEM: none
|
// PROBLEM: none
|
||||||
// ERROR: Assignment operators ambiguity: <br>public operator fun <K, V> Map<out Int, Int>.plus(pair: Pair<Int, Int>): Map<Int, Int> defined in kotlin.collections<br>public inline operator fun <K, V> MutableMap<in Int, in Int>.plusAssign(pair: Pair<Int, Int>): Unit defined in kotlin.collections
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
fun test() {
|
fun test() {
|
||||||
var map = mutableMapOf(1 to 2)
|
var map = mutableMapOf(1 to 2)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// PROBLEM: none
|
// PROBLEM: none
|
||||||
// ERROR: Assignment operators ambiguity: <br>public operator fun <T> Set<Int>.plus(element: Int): Set<Int> defined in kotlin.collections<br>public inline operator fun <T> MutableCollection<in Int>.plusAssign(element: Int): Unit defined in kotlin.collections
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
fun test() {
|
fun test() {
|
||||||
var set = mutableSetOf(1)
|
var set = mutableSetOf(1)
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'list' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var list = ArrayList<Int>()
|
|
||||||
list <caret>-= 2
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'list' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
val list = ArrayList<Int>()
|
|
||||||
list <caret>-= 2
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
// "Change 'list' to val" "false"
|
|
||||||
// ACTION: Replace overloaded operator with function call
|
|
||||||
// ACTION: Replace with 'plusAssign()' call
|
|
||||||
// ACTION: Replace with ordinary assignment
|
|
||||||
// ERROR: Assignment operators ambiguity: <br>public operator fun <T> Collection<Int>.plus(element: Int): List<Int> defined in kotlin.collections<br>public inline operator fun <T> MutableCollection<in Int>.plusAssign(element: Int): Unit defined in kotlin.collections
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
class Test {
|
|
||||||
var list = mutableListOf(1)
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
list <caret>+= 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'set' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var set = HashMap<Int, Int>()
|
|
||||||
set <caret>+= 2 to 2
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'set' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
val set = HashMap<Int, Int>()
|
|
||||||
set <caret>+= 2 to 2
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'set' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var set = HashSet<Int>()
|
|
||||||
set <caret>-= 2
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'set' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
val set = HashSet<Int>()
|
|
||||||
set <caret>-= 2
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'list' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var list = mutableListOf(1)
|
|
||||||
list <caret>+= 2
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'list' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
val list = mutableListOf(1)
|
|
||||||
list <caret>+= 2
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'map' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var map = mutableMapOf(1 to 1)
|
|
||||||
map <caret>+= 2 to 2
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'map' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
val map = mutableMapOf(1 to 1)
|
|
||||||
map <caret>+= 2 to 2
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'set' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var set = mutableSetOf(1)
|
|
||||||
set <caret>+= 2
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Change 'set' to val" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
val set = mutableSetOf(1)
|
|
||||||
set <caret>+= 2
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'minusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var list = ArrayList<Int>()
|
|
||||||
list <caret>-= 2
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'minusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var list = ArrayList<Int>()
|
|
||||||
list.minusAssign(2)<caret>
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'plusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var set = HashMap<Int, Int>()
|
|
||||||
set <caret>+= 2 to 2
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'plusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var set = HashMap<Int, Int>()
|
|
||||||
set.plusAssign(2 to 2)
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'minusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var set = HashSet<Int>()
|
|
||||||
set <caret>-= 2
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'minusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var set = HashSet<Int>()
|
|
||||||
set.minusAssign(2)<caret>
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'plusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var list = mutableListOf(1)
|
|
||||||
list <caret>+= 2
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'plusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var list = mutableListOf(1)
|
|
||||||
list.plusAssign(2)<caret>
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'plusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var map = mutableMapOf(1 to 1)
|
|
||||||
map <caret>+= 2 to 2
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'plusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var map = mutableMapOf(1 to 1)
|
|
||||||
map.plusAssign(2 to 2)<caret>
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'plusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var set = mutableSetOf(1)
|
|
||||||
set <caret>+= 2
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
// "Replace with 'plusAssign()' call" "true"
|
|
||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
var set = mutableSetOf(1)
|
|
||||||
set.plusAssign(2)<caret>
|
|
||||||
}
|
|
||||||
-39
@@ -496,45 +496,6 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/assignOperatorAmbiguity")
|
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
|
||||||
public static class AssignOperatorAmbiguity extends AbstractQuickFixMultiFileTest {
|
|
||||||
private void runTest(String testDataFilePath) throws Exception {
|
|
||||||
KotlinTestUtils.runTest(this::doTestWithExtraFile, this, testDataFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAllFilesPresentInAssignOperatorAmbiguity() throws Exception {
|
|
||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/assignOperatorAmbiguity"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/assignOperatorAmbiguity/changeToVal")
|
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
|
||||||
public static class ChangeToVal extends AbstractQuickFixMultiFileTest {
|
|
||||||
private void runTest(String testDataFilePath) throws Exception {
|
|
||||||
KotlinTestUtils.runTest(this::doTestWithExtraFile, this, testDataFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAllFilesPresentInChangeToVal() throws Exception {
|
|
||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/assignOperatorAmbiguity/changeToVal"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), null, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/assignOperatorAmbiguity/replaceWithAssignCall")
|
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
|
||||||
public static class ReplaceWithAssignCall extends AbstractQuickFixMultiFileTest {
|
|
||||||
private void runTest(String testDataFilePath) throws Exception {
|
|
||||||
KotlinTestUtils.runTest(this::doTestWithExtraFile, this, testDataFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAllFilesPresentInReplaceWithAssignCall() throws Exception {
|
|
||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/assignOperatorAmbiguity/replaceWithAssignCall"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), null, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/assignToProperty")
|
@TestMetadata("idea/testData/quickfix/assignToProperty")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -1761,110 +1761,6 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/assignOperatorAmbiguity")
|
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
|
||||||
public static class AssignOperatorAmbiguity extends AbstractQuickFixTest {
|
|
||||||
private void runTest(String testDataFilePath) throws Exception {
|
|
||||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAllFilesPresentInAssignOperatorAmbiguity() throws Exception {
|
|
||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/assignOperatorAmbiguity"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/assignOperatorAmbiguity/changeToVal")
|
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
|
||||||
public static class ChangeToVal extends AbstractQuickFixTest {
|
|
||||||
private void runTest(String testDataFilePath) throws Exception {
|
|
||||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAllFilesPresentInChangeToVal() throws Exception {
|
|
||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/assignOperatorAmbiguity/changeToVal"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("arrayList.kt")
|
|
||||||
public void testArrayList() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/changeToVal/arrayList.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("classVariable.kt")
|
|
||||||
public void testClassVariable() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/changeToVal/classVariable.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("hashMap.kt")
|
|
||||||
public void testHashMap() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/changeToVal/hashMap.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("hashSet.kt")
|
|
||||||
public void testHashSet() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/changeToVal/hashSet.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("mutableList.kt")
|
|
||||||
public void testMutableList() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/changeToVal/mutableList.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("mutableMap.kt")
|
|
||||||
public void testMutableMap() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/changeToVal/mutableMap.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("mutableSet.kt")
|
|
||||||
public void testMutableSet() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/changeToVal/mutableSet.kt");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/assignOperatorAmbiguity/replaceWithAssignCall")
|
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
|
||||||
public static class ReplaceWithAssignCall extends AbstractQuickFixTest {
|
|
||||||
private void runTest(String testDataFilePath) throws Exception {
|
|
||||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAllFilesPresentInReplaceWithAssignCall() throws Exception {
|
|
||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/assignOperatorAmbiguity/replaceWithAssignCall"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("arrayList.kt")
|
|
||||||
public void testArrayList() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/replaceWithAssignCall/arrayList.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("hashMap.kt")
|
|
||||||
public void testHashMap() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/replaceWithAssignCall/hashMap.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("hashSet.kt")
|
|
||||||
public void testHashSet() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/replaceWithAssignCall/hashSet.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("mutableList.kt")
|
|
||||||
public void testMutableList() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/replaceWithAssignCall/mutableList.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("mutableMap.kt")
|
|
||||||
public void testMutableMap() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/replaceWithAssignCall/mutableMap.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("mutableSet.kt")
|
|
||||||
public void testMutableSet() throws Exception {
|
|
||||||
runTest("idea/testData/quickfix/assignOperatorAmbiguity/replaceWithAssignCall/mutableSet.kt");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/assignToProperty")
|
@TestMetadata("idea/testData/quickfix/assignToProperty")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user