Side effects and countermeasures that may occur when running dcm analyze --fix.
1. Type Inference Pitfalls (avoid-inferrable-type-arguments)#
Problem#
--fix auto-removes "inferrable" type arguments, but in reality the types may be required.
Dangerous auto-fix Cases#
// Before (working correctly)
Tween<double>(begin: 0.0, end: 1.0)
closeOverlay<void>(context)
BlocProvider.value<MyBloc>(value: bloc, child: child)
context.read<MyBloc>().add(event)
// After --fix (compile error!)
Tween(begin: 0.0, end: 1.0) // num으로 추론 → double 불일치
closeOverlay(context) // 제네릭 누락 → 타입 에러
BlocProvider.value(value: bloc, child: child) // BLoC 타입 추론 실패
context.read().add(event) // 타입 추론 불가
Patterns Where Types Must Never Be Removed#
| Pattern | Reason |
|---|---|
Tween<double> | Incorrectly inferred as num |
closeOverlay<void> | Return type specification needed |
closeDrawer<void> | Return type specification needed |
BlocProvider.value<T> | BLoC type inference fails |
BlocProvider<T> (typed list) |
List context type inferred as base type -> runtime Provider not found |
context.read<T>() | Provider/BLoC type required |
context.watch<T>() | Provider/BLoC type required |
getIt<T>() | DI container type required |
⚠️ Actual Production Incident: BlocProvider in typed List#
This is an actual incident that occurred in commit e72306ef5.
// 리스트 타입이 BlocProvider<Bloc<Object?, Object?>>로 선언된 경우
final List<BlocProvider<Bloc<Object?, Object?>>> _providers = [
// ❌ After auto-fix: T is inferred as Bloc<Object?, Object?>
BlocProvider(create: (_) => getIt<AuthBloc>()),
BlocProvider(create: (_) => getIt<ThemeBloc>()),
// -> All Providers registered with the same type!
// -> ProviderNotFoundException on context.read<AuthBloc>()!
// ✅ Type specification required
// ignore: avoid-inferrable-type-arguments
BlocProvider<AuthBloc>(create: (_) => getIt<AuthBloc>()),
// ignore: avoid-inferrable-type-arguments
BlocProvider<ThemeBloc>(create: (_) => getIt<ThemeBloc>()),
];
Why it's dangerous:
- No compile errors (type compatible)
- Passes
flutter analyze - Runtime errors only in release builds
-
Error message is minified making root cause hard to identify:
Provider<minified:o2> not found
Countermeasure#
After running --fix, always verify compile errors with flutter analyze. Manually restore types if removed in above patterns.
Especially when BlocProvider is inside a typed list, always keep the type parameter.
2. Async Removal Cascading (avoid-redundant-async)#
Problem#
Removing the async keyword from BDD step functions causes use_of_void_result
errors at call sites with await.
Actual Occurrence (35 test files, 265 locations)#
// Step function: --fix removes async
// Before
Future<void> theKpiCardShouldBeDisplayed(WidgetTester tester) async {
expect(find.byType(KpiCard), findsOneWidget);
}
// After --fix (return type changed to void)
void theKpiCardShouldBeDisplayed(WidgetTester tester) {
expect(find.byType(KpiCard), findsOneWidget);
}
// Test file: await applied to void result causes error
testWidgets('KPI card test', (tester) async {
await bddSetUp(tester);
await theKpiCardShouldBeDisplayed(tester); // use_of_void_result!
});
Countermeasure Methods#
If async is removed from step function, the await at call sites must also be removed:
// ✅ CORRECT: Call synchronous functions without await
testWidgets('KPI card test', (tester) async {
await bddSetUp(tester);
theKpiCardShouldBeDisplayed(tester); // await 제거
});
Prevention#
Write step functions that only perform synchronous operations with void return from the start:
// ✅ Write as synchronous function from the start (recommended)
void theKpiCardShouldBeDisplayed(WidgetTester tester) {
expect(find.byType(KpiCard), findsOneWidget);
}
3. @Tags Format Error#
Problem#
Test filtering fails when space-separated tags are included in a single string in @Tags annotations.
// ❌ WRONG: Space-separated tags in a single string
@Tags(['smoke @sales_analysis'])
// ✅ CORRECT: Separate each tag into individual strings
@Tags(['smoke', 'sales_analysis'])
Verification Method#
grep -r " @Tags\[ ' " --include= " *.dart " | grep " @ "
Recommended Workflow#
Follow this order when applying DCM auto-fix:
1. dcm analyze --fix . # Run auto-fix
2. flutter analyze # Check compile errors
3. Manual fixes (restore types etc.) # Check above pitfall patterns
4. melos run test # Verify tests pass
5. dcm analyze . # Final DCM check
Quick Reference#
| Rule | Severity | auto-fix Side Effect | Countermeasure |
|---|---|---|---|
avoid-inferrable-type-arguments |
Critical | BlocProvider in typed list -> Runtime Provider not found (production incident) | Manual restore + ignore comment |
avoid-inferrable-type-arguments |
High | Tween, context.read type removal -> Compile error | Manual restore |
avoid-redundant-async |
High | Step function async removal -> call site await error (265 locations) | Remove await at call sites simultaneously |
@Tags format |
Low | Not auto-fix, manually discovered | Separate tag strings |
Related Documents#
- project-config.md - DCM configuration and execution guide
- bdd-test-patterns.md - BDD test patterns
- CLAUDE.md - Complete project guide