Version 2.18.0-166.0.dev

Merge commit 'f28a665c4ecf6a1e5a296e53251d9a1b481b0a60' into 'dev'
diff --git a/DEPS b/DEPS
index b6c119a..5756948 100644
--- a/DEPS
+++ b/DEPS
@@ -123,7 +123,7 @@
   "linter_rev": "a8529c6692922b45bc287543b355c90d7b1286d3", # 1.24.0
   "lints_rev": "8294e5648ab49474541527e2911e72e4c5aefe55",
   "logging_rev": "f6979e3bc3b6e1847a08335b7eb6304e18986195",
-  "markdown_rev": "5699cafa9ef004875fd7de8ae9ea00e5295e87a4", # 5.0.0
+  "markdown_rev": "e3f4bd28c9e61b522f75f291d4d6cfcfeccd83ee", # 5.0.0
   "markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
   "matcher_rev": "12cdc5fbafd666ed908359ae215d5d0306087969",
   "mime_rev": "c2c5ffd594674f32dc277521369da1557a1622d3",
diff --git a/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart b/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart
index 626004f..a744db5f 100644
--- a/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart
+++ b/pkg/analysis_server/lib/src/analytics/google_analytics_manager.dart
@@ -154,6 +154,7 @@
     analytics.sendEvent('language_server', 'session', parameters: {
       'flags': sessionData.commandLineArguments,
       'clientId': sessionData.clientId,
+      'clientVersion': sessionData.clientVersion,
       'sdkVersion': sessionData.sdkVersion,
       'duration': duration.toString(),
       'plugins': _pluginData.usageCountData,
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
index dc0822b..eab4042 100644
--- 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
@@ -4,7 +4,6 @@
 
 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';
 
@@ -26,22 +25,16 @@
     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);
+    var printInvocation = utils.findSimplePrintInvocation(node);
+    if (printInvocation != null) {
+      var indent = utils.getLinePrefix(printInvocation.offset);
       await builder.addDartFileEdit(file, (builder) {
-        builder.addInsertion(grandparent.offset, (builder) {
+        builder.addInsertion(printInvocation.offset, (builder) {
           builder.writeln('if (kDebugMode) {');
           builder.write(indent);
           builder.write(utils.getIndent(1));
         });
-        builder.addInsertion(grandparent.end, (builder) {
+        builder.addInsertion(printInvocation.end, (builder) {
           builder.writeln();
           builder.write(indent);
           builder.write('}');
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_print.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_print.dart
new file mode 100644
index 0000000..d079f60
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_print.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2022, 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/source/source_range.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+
+/// Generates corrections that remove print expression statements, but
+/// not other usages of print.
+class RemovePrint extends CorrectionProducer {
+  @override
+  bool get canBeAppliedToFile => true;
+
+  @override
+  FixKind get fixKind => DartFixKind.REMOVE_PRINT;
+
+  @override
+  List<Object> get multiFixArguments => [];
+
+  @override
+  FixKind get multiFixKind => DartFixKind.REMOVE_PRINT_MULTI;
+
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    final printInvocation = utils.findSimplePrintInvocation(node);
+    if (printInvocation != null) {
+      await builder.addDartFileEdit(file, (builder) {
+        var start = utils.getLineContentStart(printInvocation.offset);
+        var end = utils.getLineContentEnd(printInvocation.end);
+        final nextLine = utils.getLineNext(printInvocation.end);
+        if (nextLine != end) {
+          // Preserve indent if there is more on the line after the print.
+          start = printInvocation.offset;
+        } else if (start != utils.getLineThis(printInvocation.offset)) {
+          // Preserve newline if there is more on the line before the print.
+          end = end - utils.endOfLine.length;
+        }
+        builder.addDeletion(SourceRange(start, end - start));
+      });
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 9a729ee..e98c474 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -1063,6 +1063,16 @@
     DartFixKindPriority.DEFAULT,
     'Remove parentheses in getter invocation',
   );
+  static const REMOVE_PRINT = FixKind(
+    'dart.fix.remove.removePrint',
+    DartFixKindPriority.DEFAULT,
+    'Remove print statement',
+  );
+  static const REMOVE_PRINT_MULTI = FixKind(
+    'dart.fix.remove.removePrint.multi',
+    DartFixKindPriority.IN_FILE,
+    'Remove print statements in file',
+  );
   static const REMOVE_QUESTION_MARK = FixKind(
     'dart.fix.remove.questionMark',
     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 cc2890e..542b4eb 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -132,6 +132,7 @@
 import 'package:analysis_server/src/services/correction/dart/remove_operator.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_parameters_in_getter_declaration.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_parentheses_in_getter_invocation.dart';
+import 'package:analysis_server/src/services/correction/dart/remove_print.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_question_mark.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_returned_value.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_this_expression.dart';
@@ -388,6 +389,7 @@
     ],
     LintNames.avoid_print: [
       MakeConditionalOnDebugMode.new,
+      RemovePrint.new,
     ],
     LintNames.avoid_private_typedef_functions: [
       InlineTypedef.new,
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index be9d2c0..3f0281a7 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -573,6 +573,25 @@
     return conflicts;
   }
 
+  /// Returns the [ExpressionStatement] associated with [node] if [node] points
+  /// to the identifier for a simple `print`.  Returns `null`,
+  /// otherwise.
+  ExpressionStatement? findSimplePrintInvocation(AstNode node) {
+    var parent = node.parent;
+    var grandparent = parent?.parent;
+    if (node is SimpleIdentifier) {
+      var element = node.staticElement;
+      if (element is FunctionElement &&
+          element.name == 'print' &&
+          element.library.isDartCore &&
+          parent is MethodInvocation &&
+          grandparent is ExpressionStatement) {
+        return grandparent;
+      }
+    }
+    return null;
+  }
+
   /// Returns the indentation with the given level.
   String getIndent(int level) => repeat('  ', level);
 
diff --git a/pkg/analysis_server/test/services/correction/util_test.dart b/pkg/analysis_server/test/services/correction/util_test.dart
index 1734e00..4b5664a 100644
--- a/pkg/analysis_server/test/services/correction/util_test.dart
+++ b/pkg/analysis_server/test/services/correction/util_test.dart
@@ -272,6 +272,46 @@
 ''');
   }
 
+  Future<void> test_findSimplePrintInvocation() async {
+    await resolveTestCode('''
+void f() {
+  print('hi');
+}
+''');
+    var printIdentifier = findNode.simple('print');
+    var expected = findNode.expressionStatement('print');
+    var result = CorrectionUtils(testAnalysisResult)
+        .findSimplePrintInvocation(printIdentifier);
+    expect(result, expected);
+  }
+
+  Future<void> test_findSimplePrintInvocation_custom_print() async {
+    await resolveTestCode('''
+void print(String toPrint) {
+}
+
+void f() {
+  print('hi');
+}
+''');
+    var printIdentifier = findNode.simple('print(\'hi\'');
+    var result = CorrectionUtils(testAnalysisResult)
+        .findSimplePrintInvocation(printIdentifier);
+    expect(result, null);
+  }
+
+  Future<void> test_findSimplePrintInvocation_negative() async {
+    await resolveTestCode('''
+void f() {
+  true ? print('hi') : print('false');
+}
+''');
+    var printIdentifier = findNode.simple('print(\'false');
+    var result = CorrectionUtils(testAnalysisResult)
+        .findSimplePrintInvocation(printIdentifier);
+    expect(result, null);
+  }
+
   Future<void> test_invertCondition_binary_compare() async {
     await assert_invertCondition('0 < 1', '0 >= 1');
     await assert_invertCondition('0 > 1', '0 <= 1');
diff --git a/pkg/analysis_server/test/src/analytics/google_analytics_manager_test.dart b/pkg/analysis_server/test/src/analytics/google_analytics_manager_test.dart
new file mode 100644
index 0000000..129b7a0
--- /dev/null
+++ b/pkg/analysis_server/test/src/analytics/google_analytics_manager_test.dart
@@ -0,0 +1,321 @@
+// Copyright (c) 2022, 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/protocol/protocol.dart';
+import 'package:analysis_server/src/analytics/google_analytics_manager.dart';
+import 'package:analysis_server/src/analytics/percentile_calculator.dart';
+import 'package:analysis_server/src/plugin/plugin_manager.dart';
+import 'package:analyzer/dart/analysis/context_root.dart' as analyzer;
+import 'package:telemetry/telemetry.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(GoogleAnalyticsManagerTest);
+  });
+}
+
+@reflectiveTest
+class GoogleAnalyticsManagerTest {
+  final analytics = _MockAnalytics();
+  late final GoogleAnalyticsManager manager;
+
+  void setUp() {
+    manager = GoogleAnalyticsManager(analytics);
+  }
+
+  void test_plugin_request() {
+    _defaultStartup();
+    PluginManager.pluginResponseTimes[_MockPluginInfo('a')] = {
+      'analysis.getNavigation': PercentileCalculator(),
+    };
+    manager.shutdown();
+    analytics.assertEvents([
+      _ExpectedEvent.session(),
+      _ExpectedEvent.pluginRequest(parameters: {
+        'pluginId': 'a',
+        'method': 'analysis.getNavigation',
+        'duration': _IsPercentiles(),
+      }),
+    ]);
+    PluginManager.pluginResponseTimes.clear();
+  }
+
+  void test_server_request() {
+    _defaultStartup();
+    manager.startedRequest(
+        request: Request('1', 'server.shutdown'), startTime: _now());
+    manager.sentResponse(response: Response('1'));
+    manager.shutdown();
+    analytics.assertEvents([
+      _ExpectedEvent.session(),
+      _ExpectedEvent.request(parameters: {
+        'latency': _IsPercentiles(),
+        'method': 'server.shutdown',
+        'duration': _IsPercentiles(),
+      }),
+    ]);
+  }
+
+  void test_shutdownWithoutStartup() {
+    manager.shutdown();
+    analytics.assertNoEvents();
+  }
+
+  void test_startup_withoutVersion() {
+    var arguments = ['a', 'b'];
+    var clientId = 'clientId';
+    var sdkVersion = 'sdkVersion';
+    manager.startUp(
+        time: DateTime.now(),
+        arguments: arguments,
+        clientId: clientId,
+        clientVersion: null,
+        sdkVersion: sdkVersion);
+    manager.shutdown();
+    analytics.assertEvents([
+      _ExpectedEvent.session(parameters: {
+        'flags': arguments.join(' '),
+        'clientId': clientId,
+        'clientVersion': '',
+        'sdkVersion': sdkVersion,
+        'duration': _IsStringEncodedPositiveInt(),
+      }),
+    ]);
+  }
+
+  void test_startup_withPlugins() {
+    _defaultStartup();
+    manager.changedPlugins(_MockPluginManager(plugins: [
+      _MockPluginInfo('a'),
+      _MockPluginInfo('b'),
+    ]));
+    manager.shutdown();
+    analytics.assertEvents([
+      _ExpectedEvent.session(parameters: {
+        'plugins': '{"recordCount":1,"rootCounts":{"a":"1[0, 0, 0, 0, 0, 0, '
+            '0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]","b":"1[0, 0, 0, 0, 0, '
+            '0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]"}}'
+      }),
+    ]);
+  }
+
+  void test_startup_withVersion() {
+    var arguments = ['a', 'b'];
+    var clientId = 'clientId';
+    var clientVersion = 'clientVersion';
+    var sdkVersion = 'sdkVersion';
+    manager.startUp(
+        time: DateTime.now(),
+        arguments: arguments,
+        clientId: clientId,
+        clientVersion: clientVersion,
+        sdkVersion: sdkVersion);
+    manager.shutdown();
+    analytics.assertEvents([
+      _ExpectedEvent.session(parameters: {
+        'flags': arguments.join(' '),
+        'clientId': clientId,
+        'clientVersion': clientVersion,
+        '': isNull,
+        'sdkVersion': sdkVersion,
+        'duration': _IsStringEncodedPositiveInt(),
+      }),
+    ]);
+  }
+
+  void _defaultStartup() {
+    manager.startUp(
+        time: DateTime.now(),
+        arguments: [],
+        clientId: '',
+        clientVersion: null,
+        sdkVersion: '');
+  }
+
+  DateTime _now() => DateTime.now();
+}
+
+/// A record of an event that was reported to analytics.
+class _Event {
+  final String category;
+  final String action;
+  final String? label;
+  final int? value;
+  final Map<String, String>? parameters;
+
+  _Event(this.category, this.action, this.label, this.value, this.parameters);
+}
+
+/// A record of an event that was reported to analytics.
+class _ExpectedEvent {
+  final String category;
+  final String action;
+  final String? label;
+  final int? value;
+  final Map<String, Object>? parameters;
+
+  _ExpectedEvent(this.category, this.action,
+      {this.label, // ignore: unused_element
+      this.value, // ignore: unused_element
+      this.parameters});
+
+  _ExpectedEvent.pluginRequest({Map<String, Object>? parameters})
+      : this('language_server', 'pluginRequest', parameters: parameters);
+
+  _ExpectedEvent.request({Map<String, Object>? parameters})
+      : this('language_server', 'request', parameters: parameters);
+
+  _ExpectedEvent.session({Map<String, Object>? parameters})
+      : this('language_server', 'session', parameters: parameters);
+
+  /// Compare the expected event with the [actual] event, failing if the actual
+  /// doesn't match the expected.
+  void matches(_Event actual) {
+    expect(actual.category, category);
+    expect(actual.action, action);
+    if (label != null) {
+      expect(actual.label, label);
+    }
+    if (value != null) {
+      expect(actual.value, value);
+    }
+    final actualParameters = actual.parameters;
+    final expectedParameters = parameters;
+    if (expectedParameters != null) {
+      if (actualParameters == null) {
+        fail('Expected parameters but found none');
+      }
+      for (var expectedKey in expectedParameters.keys) {
+        var actualValue = actualParameters[expectedKey];
+        var expectedValue = expectedParameters[expectedKey];
+        expect(actualValue, expectedValue, reason: 'For key $expectedKey');
+      }
+    }
+  }
+}
+
+/// A matcher for strings containing positive integer values.
+class _IsPercentiles extends Matcher {
+  const _IsPercentiles();
+
+  @override
+  Description describe(Description description) =>
+      description.add('percentiles');
+
+  @override
+  bool matches(Object? item, Map matchState) {
+    if (item is! String || !item.endsWith(']')) {
+      return false;
+    }
+    var index = item.indexOf('[');
+    var count = item.substring(0, index);
+    if (!_isStringEncodedPositiveInt(count)) {
+      return false;
+    }
+    var percentiles = item.substring(index + 1, item.length - 1).split(', ');
+    if (percentiles.length != 20) {
+      return false;
+    }
+    for (var percentile in percentiles) {
+      if (!_isStringEncodedPositiveInt(percentile)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool _isStringEncodedPositiveInt(String item) {
+    try {
+      var value = int.parse(item);
+      return value >= 0;
+    } catch (exception) {
+      return false;
+    }
+  }
+}
+
+/// A matcher for strings containing positive integer values.
+class _IsStringEncodedPositiveInt extends Matcher {
+  const _IsStringEncodedPositiveInt();
+
+  @override
+  Description describe(Description description) =>
+      description.add('a string encoded positive integer');
+
+  @override
+  bool matches(Object? item, Map matchState) {
+    if (item is! String) {
+      return false;
+    }
+    try {
+      var value = int.parse(item);
+      return value >= 0;
+    } catch (exception) {
+      return false;
+    }
+  }
+}
+
+/// An implementation of [Analytics] specialized for testing.
+class _MockAnalytics implements Analytics {
+  List<_Event> events = [];
+
+  _MockAnalytics();
+
+  void assertEvents(List<_ExpectedEvent> expectedEvents) {
+    var expectedCount = expectedEvents.length;
+    expect(events, hasLength(expectedCount));
+    for (int i = 0; i < expectedCount; i++) {
+      expectedEvents[i].matches(events[i]);
+    }
+  }
+
+  void assertNoEvents() {
+    expect(events, isEmpty);
+  }
+
+  @override
+  void close() {
+    // ignored
+  }
+
+  @override
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+  @override
+  Future sendEvent(String category, String action,
+      {String? label, int? value, Map<String, String>? parameters}) async {
+    events.add(_Event(category, action, label, value, parameters));
+  }
+
+  @override
+  Future waitForLastPing({Duration? timeout}) async {
+    // ignored
+  }
+}
+
+class _MockPluginInfo implements PluginInfo {
+  @override
+  String pluginId;
+
+  _MockPluginInfo(this.pluginId);
+
+  @override
+  Set<analyzer.ContextRoot> get contextRoots => {};
+
+  @override
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class _MockPluginManager implements PluginManager {
+  @override
+  List<PluginInfo> plugins;
+
+  _MockPluginManager({this.plugins = const []});
+
+  @override
+  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analysis_server/test/src/analytics/test_all.dart b/pkg/analysis_server/test/src/analytics/test_all.dart
index b969877..d372a69 100644
--- a/pkg/analysis_server/test/src/analytics/test_all.dart
+++ b/pkg/analysis_server/test/src/analytics/test_all.dart
@@ -4,10 +4,12 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'google_analytics_manager_test.dart' as google_analytics_manager;
 import 'percentile_calculator_test.dart' as percentile_calculator;
 
 void main() {
   defineReflectiveSuite(() {
+    google_analytics_manager.main();
     percentile_calculator.main();
   });
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_print_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_print_test.dart
new file mode 100644
index 0000000..2622507
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_print_test.dart
@@ -0,0 +1,144 @@
+// Copyright (c) 2022, 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/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(RemovePrintTest);
+    defineReflectiveTests(RemovePrintMultiTest);
+  });
+}
+
+@reflectiveTest
+class RemovePrintMultiTest extends FixInFileProcessorTest {
+  @override
+  void setUp() {
+    super.setUp();
+    createAnalysisOptionsFile(
+      lints: [LintNames.avoid_print],
+    );
+  }
+
+  Future<void> test_multi_prints() async {
+    await resolveTestCode('''
+void f() {
+  print('');
+  1+2;
+  print('more');
+}
+''');
+    var fixes = await getFixesForFirstError();
+    expect(fixes, hasLength(1));
+    assertProduces(fixes.first, '''
+void f() {
+  1+2;
+}
+''');
+  }
+
+  Future<void> test_multi_prints_on_line() async {
+    await resolveTestCode('''
+void f() {
+  print('');  3+4;  print('even more');
+  1+2;
+  print('more');
+}
+''');
+    var fixes = await getFixesForFirstError();
+    expect(fixes, hasLength(1));
+    assertProduces(fixes.first, '''
+void f() {
+  3+4;
+  1+2;
+}
+''');
+  }
+
+  Future<void> test_multi_prints_stacked() async {
+    await resolveTestCode('''
+void f() {
+  print('');
+  print('more');
+}
+''');
+    var fixes = await getFixesForFirstError();
+    expect(fixes, hasLength(1));
+    assertProduces(fixes.first, '''
+void f() {
+}
+''');
+  }
+}
+
+@reflectiveTest
+class RemovePrintTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.REMOVE_PRINT;
+
+  @override
+  String get lintCode => LintNames.avoid_print;
+
+  @override
+  void setUp() {
+    super.setUp();
+    writeTestPackageConfig();
+  }
+
+  Future<void> test_multi_statement() async {
+    await resolveTestCode('''
+void f() {
+  print(''); 1+2;
+}
+''');
+    await assertHasFix('''
+void f() {
+  1+2;
+}
+''');
+  }
+
+  Future<void> test_multiline_but_still_simple() async {
+    await resolveTestCode('''
+void f() {
+  print('asdfasdf'
+    'sdfg'
+       'sdfgsdfgsdfg'
+           'sdfgsdfgsdfg'
+       '${3}');
+}
+''');
+    await assertHasFix('''
+void f() {
+}
+''');
+  }
+
+  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() {
+}
+''');
+  }
+}
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 d383acf..323361b 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
@@ -161,6 +161,7 @@
     as remove_parameters_in_getter_declaration;
 import 'remove_parentheses_in_getter_invocation_test.dart'
     as remove_parentheses_in_getter_invocation;
+import 'remove_print_test.dart' as remove_print;
 import 'remove_question_mark_test.dart' as remove_question_mark;
 import 'remove_returned_value_test.dart' as remove_returned_value;
 import 'remove_this_expression_test.dart' as remove_this_expression;
@@ -372,6 +373,7 @@
     remove_operator.main();
     remove_parameters_in_getter_declaration.main();
     remove_parentheses_in_getter_invocation.main();
+    remove_print.main();
     remove_question_mark.main();
     remove_returned_value.main();
     remove_this_expression.main();
diff --git a/tools/VERSION b/tools/VERSION
index 9d216f3..3548928 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 165
+PRERELEASE 166
 PRERELEASE_PATCH 0
\ No newline at end of file