Version 2.15.0-123.0.dev

Merge commit 'b1d878fc8f68df01944e1c3d2cfcb7c7104b02d0' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/make_conditional_on_debug_mode.dart b/pkg/analysis_server/lib/src/services/correction/dart/make_conditional_on_debug_mode.dart
new file mode 100644
index 0000000..af6ad99
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/make_conditional_on_debug_mode.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+
+class MakeConditionalOnDebugMode extends CorrectionProducer {
+  /// The URI of the library in which kDebugMode is declared.
+  static final Uri _foundationUri =
+      Uri.parse('package:flutter/foundation.dart');
+
+  @override
+  // This fix isn't enabled for fix-all or bulk fix because it doesn't currently
+  // account for having multiple `print` invocations in sequence.
+  bool get canBeAppliedToFile => false;
+
+  @override
+  FixKind get fixKind => DartFixKind.MAKE_CONDITIONAL_ON_DEBUG_MODE;
+
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    if (resolvedResult.session.uriConverter.uriToPath(_foundationUri) == null) {
+      return;
+    }
+    final node = this.node;
+    var parent = node.parent;
+    var grandparent = parent?.parent;
+    if (node is SimpleIdentifier &&
+        parent is MethodInvocation &&
+        parent.methodName == node &&
+        node.name == 'print' &&
+        grandparent is ExpressionStatement) {
+      var indent = utils.getLinePrefix(grandparent.offset);
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addInsertion(grandparent.offset, (builder) {
+          builder.writeln('if (kDebugMode) {');
+          builder.write(indent);
+          builder.write(utils.getIndent(1));
+        });
+        builder.addInsertion(grandparent.end, (builder) {
+          builder.writeln();
+          builder.write(indent);
+          builder.write('}');
+        });
+      });
+    }
+  }
+
+  /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
+  static MakeConditionalOnDebugMode newInstance() =>
+      MakeConditionalOnDebugMode();
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 1c03c65..10b07ef 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -693,6 +693,11 @@
     DartFixKindPriority.DEFAULT,
     'Move type arguments to after class name',
   );
+  static const MAKE_CONDITIONAL_ON_DEBUG_MODE = FixKind(
+    'dart.fix.flutter.makeConditionalOnDebugMode',
+    DartFixKindPriority.DEFAULT,
+    "Make conditional on 'kDebugMode'",
+  );
   static const MAKE_VARIABLE_NOT_FINAL = FixKind(
     'dart.fix.makeVariableNotFinal',
     DartFixKindPriority.DEFAULT,
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 3633b99..2964ba0 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -84,6 +84,7 @@
 import 'package:analysis_server/src/services/correction/dart/inline_typedef.dart';
 import 'package:analysis_server/src/services/correction/dart/insert_semicolon.dart';
 import 'package:analysis_server/src/services/correction/dart/make_class_abstract.dart';
+import 'package:analysis_server/src/services/correction/dart/make_conditional_on_debug_mode.dart';
 import 'package:analysis_server/src/services/correction/dart/make_field_not_final.dart';
 import 'package:analysis_server/src/services/correction/dart/make_final.dart';
 import 'package:analysis_server/src/services/correction/dart/make_return_type_nullable.dart';
@@ -351,6 +352,9 @@
     LintNames.avoid_null_checks_in_equality_operators: [
       RemoveComparison.newInstanceBulkFixable,
     ],
+    LintNames.avoid_print: [
+      MakeConditionalOnDebugMode.newInstance,
+    ],
     LintNames.avoid_private_typedef_functions: [
       InlineTypedef.newInstance,
     ],
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index af54793..3e82fa6 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -18,6 +18,7 @@
   static const String avoid_init_to_null = 'avoid_init_to_null';
   static const String avoid_null_checks_in_equality_operators =
       'avoid_null_checks_in_equality_operators';
+  static const String avoid_print = 'avoid_print';
   static const String avoid_private_typedef_functions =
       'avoid_private_typedef_functions';
   static const String avoid_redundant_argument_values =
diff --git a/pkg/analysis_server/test/src/services/correction/fix/make_conditional_on_debug_mode_test.dart b/pkg/analysis_server/test/src/services/correction/fix/make_conditional_on_debug_mode_test.dart
new file mode 100644
index 0000000..8efa0ef
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/make_conditional_on_debug_mode_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MakeConditionalOnDebugModeTest);
+    defineReflectiveTests(MakeConditionalOnDebugModeWithoutFlutterTest);
+  });
+}
+
+@reflectiveTest
+class MakeConditionalOnDebugModeTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.MAKE_CONDITIONAL_ON_DEBUG_MODE;
+
+  @override
+  String get lintCode => LintNames.avoid_print;
+
+  @override
+  void setUp() {
+    super.setUp();
+    writeTestPackageConfig(
+      flutter: true,
+    );
+  }
+
+  Future<void> test_nested() async {
+    await resolveTestCode('''
+void f(bool b) {
+  b ? print('') : f(true);
+}
+''');
+    await assertNoFix();
+  }
+
+  Future<void> test_statement() async {
+    await resolveTestCode('''
+void f() {
+  print('');
+}
+''');
+    await assertHasFix('''
+void f() {
+  if (kDebugMode) {
+    print('');
+  }
+}
+''');
+  }
+}
+
+@reflectiveTest
+class MakeConditionalOnDebugModeWithoutFlutterTest
+    extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.MAKE_CONDITIONAL_ON_DEBUG_MODE;
+
+  @override
+  String get lintCode => LintNames.avoid_print;
+
+  Future<void> test_statement() async {
+    await resolveTestCode('''
+void f() {
+  print('');
+}
+''');
+    await assertNoFix();
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index bd0d10c..7dad5f2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -103,6 +103,8 @@
 import 'inline_typedef_test.dart' as inline_typedef;
 import 'insert_semicolon_test.dart' as insert_semicolon;
 import 'make_class_abstract_test.dart' as make_class_abstract;
+import 'make_conditional_on_debug_mode_test.dart'
+    as make_conditional_on_debug_mode;
 import 'make_field_not_final_test.dart' as make_field_not_final;
 import 'make_final_test.dart' as make_final;
 import 'make_return_type_nullable_test.dart' as make_return_type_nullable;
@@ -288,6 +290,7 @@
     inline_typedef.main();
     insert_semicolon.main();
     make_class_abstract.main();
+    make_conditional_on_debug_mode.main();
     make_field_not_final.main();
     make_final.main();
     make_return_type_nullable.main();
diff --git a/tools/VERSION b/tools/VERSION
index f1fb2e6..8d8bbba 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 122
+PRERELEASE 123
 PRERELEASE_PATCH 0
\ No newline at end of file