diff --git a/mobile/analysis_options.yaml b/mobile/analysis_options.yaml index bef051bff2..c26e1c6649 100644 --- a/mobile/analysis_options.yaml +++ b/mobile/analysis_options.yaml @@ -134,6 +134,13 @@ custom_lint: dart_code_metrics: rules: + - banned-usage: + entries: + - name: debugPrint + description: Use dPrint instead of debugPrint for proper tree-shaking in release builds. + exclude-paths: + - 'lib/utils/debug_print.dart' + severity: perf # All rules from "recommended" preset # Show potential errors # - avoid-cascade-after-if-null diff --git a/mobile/immich_lint/lib/immich_mobile_immich_lint.dart b/mobile/immich_lint/lib/immich_mobile_immich_lint.dart index 0b6d28b5a8..1ef1f50649 100644 --- a/mobile/immich_lint/lib/immich_mobile_immich_lint.dart +++ b/mobile/immich_lint/lib/immich_mobile_immich_lint.dart @@ -1,8 +1,5 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/element/element2.dart'; -import 'package:analyzer/error/error.dart' show ErrorSeverity, AnalysisError; +import 'package:analyzer/error/error.dart' show ErrorSeverity; import 'package:analyzer/error/listener.dart'; -import 'package:analyzer/source/source_range.dart'; import 'package:custom_lint_builder/custom_lint_builder.dart'; // ignore: depend_on_referenced_packages import 'package:glob/glob.dart'; @@ -24,9 +21,6 @@ class ImmichLinter extends PluginBase { } } - if (configs.rules[NoDebugPrintRule.name]?.enabled ?? true) { - rules.add(NoDebugPrintRule()); - } return rules; } @@ -94,150 +88,3 @@ class ImportRule extends DartLintRule { }); } } - -class NoDebugPrintRule extends DartLintRule { - static const name = 'no_debug_print'; - static const importPath = 'package:flutter/src/foundation/print.dart'; - static const _code = LintCode( - name: name, - problemMessage: - 'Use dPrint instead of debugPrint for proper tree-shaking in release builds.', - correctionMessage: 'Replace debugPrint with dPrint', - errorSeverity: ErrorSeverity.WARNING, - ); - - NoDebugPrintRule() : super(code: _code); - - @pragma('vm:prefer-inline') - static bool isDebugPrint(Element2? element) { - return element is PropertyAccessorElement2 && - element.variable3?.getter2?.name3 == 'debugPrint' && - element.library2.identifier == importPath; - } - - @pragma('vm:prefer-inline') - static bool isWrapped(AstNode node) { - AstNode? parent = node.parent; - while (parent != null) { - if (parent case IfStatement(:SimpleIdentifier expression) - when expression.name == 'kDebugMode') { - return true; - } - parent = parent.parent; - } - - return false; - } - - @override - void run( - CustomLintResolver resolver, - ErrorReporter reporter, - CustomLintContext context, - ) { - context.registry.addFunctionExpressionInvocation((node) { - final function = node.function; - if (function case SimpleIdentifier(:final element) - when isDebugPrint(element) && !isWrapped(node)) { - reporter.atNode(function, code); - } - }); - - context.registry.addMethodInvocation((node) { - final methodName = node.methodName; - if (isDebugPrint(methodName.element) && !isWrapped(node)) { - reporter.atNode(methodName, code); - } - }); - } - - @override - List getFixes() => [ReplaceDebugPrintFix()]; -} - -class ReplaceDebugPrintFix extends DartFix { - static const dPrintImportPath = - "import 'package:immich_mobile/utils/debug_print.dart';"; - - @override - void run( - CustomLintResolver resolver, - ChangeReporter reporter, - CustomLintContext context, - AnalysisError error, - List allErrors, - ) { - context.registry.addFunctionExpressionInvocation((node) { - final function = node.function; - if (error.sourceRange == function.sourceRange && - function is SimpleIdentifier && - NoDebugPrintRule.isDebugPrint(function.element)) { - _createFix(reporter, resolver, function, node); - } - }); - - context.registry.addMethodInvocation((node) { - final methodName = node.methodName; - if (error.sourceRange == methodName.sourceRange && - NoDebugPrintRule.isDebugPrint(methodName.element)) { - _createFix(reporter, resolver, methodName, node); - } - }); - } - - void _createFix( - ChangeReporter reporter, - CustomLintResolver resolver, - SimpleIdentifier identifier, - AstNode node, - ) { - final arguments = switch (node) { - MethodInvocation(:final argumentList) => argumentList, - FunctionExpressionInvocation(:final argumentList) => argumentList, - _ => null, - }; - if (arguments == null) { - return; - } - - final changeBuilder = reporter.createChangeBuilder( - message: 'Replace with dPrint', - priority: 1, - ); - - changeBuilder.addDartFileEdit((builder) { - builder.addSimpleReplacement(identifier.sourceRange, 'dPrint'); - final firstArg = arguments.arguments.firstOrNull; - if (firstArg != null) { - final argSource = resolver.source.contents.data.substring( - firstArg.offset, - firstArg.end, - ); - - builder.addSimpleReplacement( - SourceRange(firstArg.offset, firstArg.length), - '() => $argSource', - ); - } - - if (resolver.source.contents.data.contains(dPrintImportPath)) { - return; - } - - final unit = node.root; - if (unit is CompilationUnit) { - final lastImport = - unit.directives.whereType().lastOrNull; - - if (lastImport != null) { - builder.addSimpleInsertion(lastImport.end, '\n$dPrintImportPath'); - } else if (unit.directives.isNotEmpty) { - builder.addSimpleInsertion( - unit.directives.last.end, '\n\n$dPrintImportPath'); - } else { - builder.addSimpleInsertion(0, '$dPrintImportPath\n\n'); - } - } - }); - } -}