Revert "Revert "Cast method call args in CVF fix if they don't match expected types""
This reverts commit 02c9ddf66c3c2e309ef94ac3e7cf41b0e343bfb1.
Original change was aosp/2430534. It seems some of the test outputs were slightly different under the AGP updgrade for some reason (this version has some additional lines like "@@ -55 +66" in the fix diffs).
Test: Updated unit tests from original change
Reason for revert: This change was reverted as part of the AGP downgrade but was unrelated.
Change-Id: I281ca286f5a4715597989ab30d82908663fa239d
diff --git a/lint-checks/integration-tests/src/main/java/androidx/AutofixOnUnsafeCallWithImplicitVarArgsCast.java b/lint-checks/integration-tests/src/main/java/androidx/AutofixOnUnsafeCallWithImplicitVarArgsCast.java
new file mode 100644
index 0000000..2128027
--- /dev/null
+++ b/lint-checks/integration-tests/src/main/java/androidx/AutofixOnUnsafeCallWithImplicitVarArgsCast.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * 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 androidx;
+
+import android.widget.BaseAdapter;
+
+import androidx.annotation.RequiresApi;
+
+import java.nio.CharBuffer;
+
+/**
+ * Contains unsafe calls to a method with a variable number of arguments which are implicitly cast.
+ */
+@SuppressWarnings("unused")
+public class AutofixOnUnsafeCallWithImplicitVarArgsCast {
+ /**
+ * Calls the vararg method with no args.
+ */
+ @RequiresApi(27)
+ public void callVarArgsMethodNoArgs(BaseAdapter adapter) {
+ adapter.setAutofillOptions();
+ }
+
+ /**
+ *Calls the vararg method with one args.
+ */
+ @RequiresApi(27)
+ public void callVarArgsMethodOneArg(BaseAdapter adapter, CharBuffer vararg) {
+ adapter.setAutofillOptions(vararg);
+ }
+
+ /**
+ * Calls the vararg method with multiple args.
+ */
+ @RequiresApi(27)
+ public void callVarArgsMethodManyArgs(BaseAdapter adapter, CharBuffer vararg1,
+ CharBuffer vararg2, CharBuffer vararg3) {
+ adapter.setAutofillOptions(vararg1, vararg2, vararg3);
+ }
+}
diff --git a/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallWithImplicitParamCast.java b/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallWithImplicitParamCast.java
new file mode 100644
index 0000000..cc20718
--- /dev/null
+++ b/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallWithImplicitParamCast.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * 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 androidx;
+
+import android.app.Notification;
+
+import androidx.annotation.RequiresApi;
+
+/**
+ * Tests to ensure the generated lint fix does not leave in implicit casts from a new argument type.
+ */
+@SuppressWarnings("unused")
+public class AutofixUnsafeCallWithImplicitParamCast {
+ /**
+ * This uses the Notification.MessagingStyle type, but setBuilder is defined on
+ * Notification.Style, and the two classes were introduced in different API levels.
+ */
+ @RequiresApi(24)
+ public void castReceiver(Notification.MessagingStyle style, Notification.Builder builder) {
+ style.setBuilder(builder);
+ }
+
+ /**
+ * This uses Notification.CarExtender, but extend is defined with Notification.Extender as a
+ * parameter, and the two classes were introduced at different API levels.
+ */
+ @RequiresApi(23)
+ public void castParameter(Notification.Builder builder, Notification.CarExtender extender) {
+ builder.extend(extender);
+ }
+}
diff --git a/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallWithImplicitCast.java b/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallWithImplicitReturnCast.java
similarity index 95%
rename from lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallWithImplicitCast.java
rename to lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallWithImplicitReturnCast.java
index 0e074a7..0eed5cb 100644
--- a/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallWithImplicitCast.java
+++ b/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallWithImplicitReturnCast.java
@@ -24,10 +24,10 @@
import androidx.annotation.RequiresApi;
/**
- * Tests to ensure the generated lint fix does not leave in implicit casts from a new type.
+ * Tests to ensure the generated lint fix does not leave in implicit casts from a new return type.
*/
@SuppressWarnings("unused")
-public abstract class AutofixUnsafeCallWithImplicitCast {
+public abstract class AutofixUnsafeCallWithImplicitReturnCast {
/**
* This method creates an AdaptiveIconDrawable and implicitly casts it to Drawable.
*/
diff --git a/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt b/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt
index 62d19a0..f26db17 100644
--- a/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt
+++ b/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt
@@ -46,6 +46,7 @@
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiCompiledElement
import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiEllipsisType
import com.intellij.psi.PsiExpressionList
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiMethodCallExpression
@@ -67,6 +68,7 @@
import org.jetbrains.uast.UThisExpression
import org.jetbrains.uast.getContainingUClass
import org.jetbrains.uast.getContainingUMethod
+import org.jetbrains.uast.isNullLiteral
import org.jetbrains.uast.util.isConstructorCall
import org.jetbrains.uast.util.isMethodCall
@@ -532,7 +534,8 @@
call.receiver,
call.valueArguments,
wrapperClassName,
- wrapperMethodName
+ wrapperMethodName,
+ wrapperMethodParams
)
val fix = fix()
@@ -688,6 +691,7 @@
* @param callValueArguments Arguments of the call to the platform method
* @param wrapperClassName Name of the generated wrapper class
* @param wrapperMethodName Name of the generated wrapper method
+ * @param wrapperMethodParams Param types of the wrapper method
* @return Source code for a call to the static wrapper method
*/
private fun generateWrapperCall(
@@ -696,6 +700,7 @@
callValueArguments: List<UExpression>,
wrapperClassName: String,
wrapperMethodName: String,
+ wrapperMethodParams: List<PsiType>
): String {
val callReceiverStr = when {
// Static method
@@ -708,15 +713,34 @@
// it must be a call to an instance method using `this` implicitly.
callReceiver == null ->
"this"
- // Otherwise, use the original call receiver string (removing extra parens)
+ // Use the original call receiver string (removing extra parens), casting if needed
else ->
- unwrapExpression(callReceiver).asSourceString()
+ createArgumentString(unwrapExpression(callReceiver), wrapperMethodParams[0])
}
val callValues = if (callValueArguments.isNotEmpty()) {
- callValueArguments.joinToString(separator = ", ") { argument ->
- argument.asSourceString()
+ // The first element in the wrapperMethodParams is the receiver, so drop that.
+ // Also drop the last parameter, because it is special-cased later.
+ val paramTypesWithoutReceiverAndFinal = wrapperMethodParams.drop(1).dropLast(1)
+ // For varargs methods, what we care about for the last type is the type of each
+ // vararg, not the containing type.
+ val finalParamType = if (method.isVarArgs) {
+ (wrapperMethodParams.last() as PsiEllipsisType).componentType
+ } else {
+ wrapperMethodParams.last()
}
+
+ callValueArguments.mapIndexed { argIndex, arg ->
+ // The number of args might be greater than the number of param types due to
+ // varargs, repeat the final param type for all args after exhausting the
+ // paramTypesWithoutReceiverAndFinal list.
+ val expectedType = if (argIndex < paramTypesWithoutReceiverAndFinal.size) {
+ paramTypesWithoutReceiverAndFinal[argIndex]
+ } else {
+ finalParamType
+ }
+ createArgumentString(arg, expectedType)
+ }.joinToString(separator = ", ")
} else {
null
}
@@ -727,6 +751,24 @@
}
/**
+ * Creates the string representation of an argument in the wrapper call. If the type of the
+ * arg is not identical to the parameter type of the wrapper method, casts to that type.
+ */
+ private fun createArgumentString(arg: UExpression, expectedType: PsiType): String {
+ val argType = arg.getExpressionType()
+ val expectedTypeText = expectedType.canonicalText
+ // If the arg is the expected type, use as normal, otherwise, cast to expected type.
+ // Uses text-base equality instead of directly comparing types because certain types
+ // (eq. java.lang.Class<T>) are not necessarily equal to instances of the same type.
+ // There isn't really a point in casting if the arg is null.
+ return if (argType?.equalsToText(expectedTypeText) == true || arg.isNullLiteral()) {
+ arg.asSourceString()
+ } else {
+ "($expectedTypeText) ${arg.asSourceString()}"
+ }
+ }
+
+ /**
* Remove parentheses from the expression (unwrap the expression until it is no longer a
* UParenthesizedExpression).
*/
diff --git a/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt b/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt
index 55398d8..5cfe867 100644
--- a/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt
+++ b/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt
@@ -82,7 +82,7 @@
Fix for src/androidx/sample/core/widget/ListViewCompat.java line 39: Extract to static inner class:
@@ -39 +39
- listView.scrollListBy(y);
-+ Api19Impl.scrollListBy(listView, y);
++ Api19Impl.scrollListBy((android.widget.AbsListView) listView, y);
@@ -91 +91
+ @androidx.annotation.RequiresApi(19)
+ static class Api19Impl {
@@ -100,7 +100,7 @@
Fix for src/androidx/sample/core/widget/ListViewCompat.java line 69: Extract to static inner class:
@@ -69 +69
- return listView.canScrollList(direction);
-+ return Api19Impl.canScrollList(listView, direction);
++ return Api19Impl.canScrollList((android.widget.AbsListView) listView, direction);
@@ -91 +91
+ @androidx.annotation.RequiresApi(19)
+ static class Api19Impl {
@@ -530,7 +530,7 @@
Fix for src/androidx/AutofixUnsafeCallToThis.java line 48: Extract to static inner class:
@@ -48 +48
- this.getClipToPadding();
-+ Api21Impl.getClipToPadding(this);
++ Api21Impl.getClipToPadding((ViewGroup) this);
@@ -60 +60
+ @androidx.annotation.RequiresApi(21)
+ static class Api21Impl {
@@ -609,34 +609,34 @@
}
@Test
- fun `Auto-fix with implicit class cast from new type (issue 214389795)`() {
+ fun `Auto-fix with implicit class cast from new return type (issue 214389795)`() {
val input = arrayOf(
- javaSample("androidx.AutofixUnsafeCallWithImplicitCast"),
+ javaSample("androidx.AutofixUnsafeCallWithImplicitReturnCast"),
RequiresApi
)
/* ktlint-disable max-line-length */
val expected = """
-src/androidx/AutofixUnsafeCallWithImplicitCast.java:36: Error: This call references a method added in API level 26; however, the containing class androidx.AutofixUnsafeCallWithImplicitCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+src/androidx/AutofixUnsafeCallWithImplicitReturnCast.java:36: Error: This call references a method added in API level 26; however, the containing class androidx.AutofixUnsafeCallWithImplicitReturnCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
return new AdaptiveIconDrawable(null, null);
~~~~~~~~~~~~~~~~~~~~~~~~
-src/androidx/AutofixUnsafeCallWithImplicitCast.java:44: Error: This call references a method added in API level 26; however, the containing class androidx.AutofixUnsafeCallWithImplicitCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+src/androidx/AutofixUnsafeCallWithImplicitReturnCast.java:44: Error: This call references a method added in API level 26; however, the containing class androidx.AutofixUnsafeCallWithImplicitReturnCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
return new AdaptiveIconDrawable(null, null);
~~~~~~~~~~~~~~~~~~~~~~~~
-src/androidx/AutofixUnsafeCallWithImplicitCast.java:52: Error: This call references a method added in API level 26; however, the containing class androidx.AutofixUnsafeCallWithImplicitCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+src/androidx/AutofixUnsafeCallWithImplicitReturnCast.java:52: Error: This call references a method added in API level 26; however, the containing class androidx.AutofixUnsafeCallWithImplicitReturnCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
return Icon.createWithAdaptiveBitmap(null);
~~~~~~~~~~~~~~~~~~~~~~~~
-src/androidx/AutofixUnsafeCallWithImplicitCast.java:60: Error: This call references a method added in API level 26; however, the containing class androidx.AutofixUnsafeCallWithImplicitCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+src/androidx/AutofixUnsafeCallWithImplicitReturnCast.java:60: Error: This call references a method added in API level 26; however, the containing class androidx.AutofixUnsafeCallWithImplicitReturnCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
return Icon.createWithAdaptiveBitmap(null);
~~~~~~~~~~~~~~~~~~~~~~~~
-src/androidx/AutofixUnsafeCallWithImplicitCast.java:68: Error: This call references a method added in API level 24; however, the containing class androidx.AutofixUnsafeCallWithImplicitCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+src/androidx/AutofixUnsafeCallWithImplicitReturnCast.java:68: Error: This call references a method added in API level 24; however, the containing class androidx.AutofixUnsafeCallWithImplicitReturnCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
useStyle(new Notification.DecoratedCustomViewStyle());
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 errors, 0 warnings
"""
val expectedFix = """
-Fix for src/androidx/AutofixUnsafeCallWithImplicitCast.java line 36: Extract to static inner class:
+Fix for src/androidx/AutofixUnsafeCallWithImplicitReturnCast.java line 36: Extract to static inner class:
@@ -36 +36
- return new AdaptiveIconDrawable(null, null);
+ return Api26Impl.createAdaptiveIconDrawableReturnsDrawable(null, null);
@@ -654,7 +654,7 @@
+
@@ -78 +89
+ }
-Fix for src/androidx/AutofixUnsafeCallWithImplicitCast.java line 44: Extract to static inner class:
+Fix for src/androidx/AutofixUnsafeCallWithImplicitReturnCast.java line 44: Extract to static inner class:
@@ -44 +44
- return new AdaptiveIconDrawable(null, null);
+ return Api26Impl.createAdaptiveIconDrawable(null, null);
@@ -672,7 +672,7 @@
+
@@ -78 +89
+ }
-Fix for src/androidx/AutofixUnsafeCallWithImplicitCast.java line 52: Extract to static inner class:
+Fix for src/androidx/AutofixUnsafeCallWithImplicitReturnCast.java line 52: Extract to static inner class:
@@ -52 +52
- return Icon.createWithAdaptiveBitmap(null);
+ return Api26Impl.createWithAdaptiveBitmapReturnsObject(null);
@@ -690,7 +690,7 @@
+
@@ -78 +89
+ }
-Fix for src/androidx/AutofixUnsafeCallWithImplicitCast.java line 60: Extract to static inner class:
+Fix for src/androidx/AutofixUnsafeCallWithImplicitReturnCast.java line 60: Extract to static inner class:
@@ -60 +60
- return Icon.createWithAdaptiveBitmap(null);
+ return Api26Impl.createWithAdaptiveBitmap(null);
@@ -708,7 +708,7 @@
+
@@ -78 +89
+ }
-Fix for src/androidx/AutofixUnsafeCallWithImplicitCast.java line 68: Extract to static inner class:
+Fix for src/androidx/AutofixUnsafeCallWithImplicitReturnCast.java line 68: Extract to static inner class:
@@ -68 +68
- useStyle(new Notification.DecoratedCustomViewStyle());
+ useStyle(Api24Impl.createDecoratedCustomViewStyleReturnsStyle());
@@ -769,4 +769,147 @@
check(*input).expect(expected).expectFixDiffs(expectedFix)
}
+
+ @Test
+ fun `Auto-fix with implicit class cast from new parameter type (issue 266845827)`() {
+ val input = arrayOf(
+ javaSample("androidx.AutofixUnsafeCallWithImplicitParamCast"),
+ RequiresApi
+ )
+
+ /* ktlint-disable max-line-length */
+ val expected = """
+src/androidx/AutofixUnsafeCallWithImplicitParamCast.java:34: Error: This call references a method added in API level 16; however, the containing class androidx.AutofixUnsafeCallWithImplicitParamCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+ style.setBuilder(builder);
+ ~~~~~~~~~~
+src/androidx/AutofixUnsafeCallWithImplicitParamCast.java:43: Error: This call references a method added in API level 20; however, the containing class androidx.AutofixUnsafeCallWithImplicitParamCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+ builder.extend(extender);
+ ~~~~~~
+2 errors, 0 warnings
+ """
+
+ val expectedFix = """
+Fix for src/androidx/AutofixUnsafeCallWithImplicitParamCast.java line 34: Extract to static inner class:
+@@ -34 +34
+- style.setBuilder(builder);
++ Api16Impl.setBuilder((Notification.Style) style, builder);
+@@ -45 +45
++ @RequiresApi(16)
++ static class Api16Impl {
++ private Api16Impl() {
++ // This class is not instantiable.
++ }
++
++ @DoNotInline
++ static void setBuilder(Notification.Style style, Notification.Builder builder) {
++ style.setBuilder(builder);
++ }
++
+@@ -46 +57
++ }
+Fix for src/androidx/AutofixUnsafeCallWithImplicitParamCast.java line 43: Extract to static inner class:
+@@ -43 +43
+- builder.extend(extender);
++ Api20Impl.extend(builder, (Notification.Extender) extender);
+@@ -45 +45
++ @RequiresApi(20)
++ static class Api20Impl {
++ private Api20Impl() {
++ // This class is not instantiable.
++ }
++
++ @DoNotInline
++ static Notification.Builder extend(Notification.Builder builder, Notification.Extender extender) {
++ return builder.extend(extender);
++ }
++
+@@ -46 +57
++ }
+ """
+ /* ktlint-enable max-line-length */
+
+ check(*input).expect(expected).expectFixDiffs(expectedFix)
+ }
+
+ @Test
+ fun `Auto-fix for method with varargs that are implicitly cast (issue 266845827)`() {
+ val input = arrayOf(
+ javaSample("androidx.AutofixOnUnsafeCallWithImplicitVarArgsCast"),
+ RequiresApi
+ )
+
+ /* ktlint-disable max-line-length */
+ val expected = """
+src/androidx/AutofixOnUnsafeCallWithImplicitVarArgsCast.java:35: Error: This call references a method added in API level 27; however, the containing class androidx.AutofixOnUnsafeCallWithImplicitVarArgsCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+ adapter.setAutofillOptions();
+ ~~~~~~~~~~~~~~~~~~
+src/androidx/AutofixOnUnsafeCallWithImplicitVarArgsCast.java:43: Error: This call references a method added in API level 27; however, the containing class androidx.AutofixOnUnsafeCallWithImplicitVarArgsCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+ adapter.setAutofillOptions(vararg);
+ ~~~~~~~~~~~~~~~~~~
+src/androidx/AutofixOnUnsafeCallWithImplicitVarArgsCast.java:52: Error: This call references a method added in API level 27; however, the containing class androidx.AutofixOnUnsafeCallWithImplicitVarArgsCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+ adapter.setAutofillOptions(vararg1, vararg2, vararg3);
+ ~~~~~~~~~~~~~~~~~~
+3 errors, 0 warnings
+ """
+
+ val expectedFix = """
+Fix for src/androidx/AutofixOnUnsafeCallWithImplicitVarArgsCast.java line 35: Extract to static inner class:
+@@ -35 +35
+- adapter.setAutofillOptions();
++ Api27Impl.setAutofillOptions(adapter);
+@@ -54 +54
++ @RequiresApi(27)
++ static class Api27Impl {
++ private Api27Impl() {
++ // This class is not instantiable.
++ }
++
++ @DoNotInline
++ static void setAutofillOptions(BaseAdapter baseAdapter, java.lang.CharSequence... options) {
++ baseAdapter.setAutofillOptions(options);
++ }
++
+@@ -55 +66
++ }
+Fix for src/androidx/AutofixOnUnsafeCallWithImplicitVarArgsCast.java line 43: Extract to static inner class:
+@@ -43 +43
+- adapter.setAutofillOptions(vararg);
++ Api27Impl.setAutofillOptions(adapter, (java.lang.CharSequence) vararg);
+@@ -54 +54
++ @RequiresApi(27)
++ static class Api27Impl {
++ private Api27Impl() {
++ // This class is not instantiable.
++ }
++
++ @DoNotInline
++ static void setAutofillOptions(BaseAdapter baseAdapter, java.lang.CharSequence... options) {
++ baseAdapter.setAutofillOptions(options);
++ }
++
+@@ -55 +66
++ }
+Fix for src/androidx/AutofixOnUnsafeCallWithImplicitVarArgsCast.java line 52: Extract to static inner class:
+@@ -52 +52
+- adapter.setAutofillOptions(vararg1, vararg2, vararg3);
++ Api27Impl.setAutofillOptions(adapter, (java.lang.CharSequence) vararg1, (java.lang.CharSequence) vararg2, (java.lang.CharSequence) vararg3);
+@@ -54 +54
++ @RequiresApi(27)
++ static class Api27Impl {
++ private Api27Impl() {
++ // This class is not instantiable.
++ }
++
++ @DoNotInline
++ static void setAutofillOptions(BaseAdapter baseAdapter, java.lang.CharSequence... options) {
++ baseAdapter.setAutofillOptions(options);
++ }
++
+@@ -55 +66
++ }
+ """
+ /* ktlint-enable max-line-length */
+
+ check(*input).expect(expected).expectFixDiffs(expectedFix)
+ }
}