Add a fix for prefer_single_quotes

Change-Id: Ifb59ec4c6822858e019adf780bfd7726b229542e
Reviewed-on: https://dart-review.googlesource.com/53824
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 3ba57d8..2a37c44 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -80,6 +80,7 @@
             errorCode.name == LintNames.prefer_collection_literals ||
             errorCode.name == LintNames.prefer_conditional_assignment ||
             errorCode.name == LintNames.prefer_const_declarations ||
+            errorCode.name == LintNames.prefer_single_quotes ||
             errorCode.name == LintNames.unnecessary_brace_in_string_interp ||
             errorCode.name == LintNames.unnecessary_lambdas ||
             errorCode.name == LintNames.unnecessary_this));
@@ -112,6 +113,8 @@
       50,
       "Add super constructor {0} invocation");
   static const CHANGE_TO = const FixKind('CHANGE_TO', 49, "Change to '{0}'");
+  static const CHANGE_TO_SINGLE_QUOTES = const FixKind(
+      'CHANGE_TO_SINGLE_QUOTES', 50, "Change string to single quotes");
   static const CHANGE_TO_STATIC_ACCESS = const FixKind(
       'CHANGE_TO_STATIC_ACCESS', 50, "Change access to static using '{0}'");
   static const CHANGE_TYPE_ANNOTATION = const FixKind(
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 5453c62..f5832a8 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -465,7 +465,7 @@
       if (name == LintNames.prefer_conditional_assignment) {
         await _addFix_replaceWithConditionalAssignment();
       }
-      if (errorCode.name == LintNames.prefer_const_declarations) {
+      if (name == LintNames.prefer_const_declarations) {
         await _addFix_replaceFinalWithConst();
       }
       if (name == LintNames.prefer_final_fields) {
@@ -477,6 +477,9 @@
       if (name == LintNames.prefer_is_not_empty) {
         await _addFix_isNotEmpty();
       }
+      if (name == LintNames.prefer_single_quotes) {
+        await _addFix_changeToSingleQuotes();
+      }
       if (name == LintNames.type_init_formals) {
         await _addFix_removeTypeAnnotation();
       }
@@ -869,6 +872,22 @@
     }
   }
 
+  Future<Null> _addFix_changeToSingleQuotes() async {
+    AstNode node = this.node;
+    if (node is SimpleStringLiteral && !node.isSingleQuoted) {
+      String end = node.isMultiline ? "'''" : "'";
+      String begin = node.isRaw ? 'r' + end : end;
+      DartChangeBuilder changeBuilder = new DartChangeBuilder(session);
+      await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+        builder.addSimpleReplacement(
+            new SourceRange(node.offset, begin.length), begin);
+        builder.addSimpleReplacement(
+            new SourceRange(node.end - end.length, end.length), end);
+      });
+      _addFixFromBuilder(changeBuilder, DartFixKind.CHANGE_TO_SINGLE_QUOTES);
+    }
+  }
+
   Future<Null> _addFix_convertFlutterChild() async {
     NamedExpression named = flutter.findNamedExpression(node, 'child');
     if (named == null) {
@@ -3693,6 +3712,7 @@
   static const String prefer_final_fields = 'prefer_final_fields';
   static const String prefer_final_locals = 'prefer_final_locals';
   static const String prefer_is_not_empty = 'prefer_is_not_empty';
+  static const String prefer_single_quotes = 'prefer_single_quotes';
   static const String type_init_formals = 'type_init_formals';
   static const String unnecessary_brace_in_string_interp =
       'unnecessary_brace_in_string_interp';
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index 0e949bf..12ab32e 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -6510,6 +6510,70 @@
 ''');
   }
 
+  test_changeToSingleQuotes() async {
+    String src = r'''
+main() {
+  print(/*LINT*/"Hello, world");
+}
+''';
+    await findLint(src, LintNames.prefer_single_quotes);
+    await applyFix(DartFixKind.CHANGE_TO_SINGLE_QUOTES);
+    verifyResult(r'''
+main() {
+  print('Hello, world');
+}
+''');
+  }
+
+  test_changeToSingleQuotes_multiline() async {
+    String src = r'''
+main() {
+  print(/*LINT*/"""Hello,
+  world""");
+}
+''';
+    await findLint(src, LintNames.prefer_single_quotes);
+    await applyFix(DartFixKind.CHANGE_TO_SINGLE_QUOTES);
+    verifyResult(r"""
+main() {
+  print('''Hello,
+  world''');
+}
+""");
+  }
+
+  test_changeToSingleQuotes_raw() async {
+    String src = r'''
+main() {
+  print(/*LINT*/r"Hello, world");
+}
+''';
+    await findLint(src, LintNames.prefer_single_quotes);
+    await applyFix(DartFixKind.CHANGE_TO_SINGLE_QUOTES);
+    verifyResult(r'''
+main() {
+  print(r'Hello, world');
+}
+''');
+  }
+
+  test_changeToSingleQuotes_multiline_raw() async {
+    String src = r'''
+main() {
+  print(/*LINT*/r"""Hello,
+  world""");
+}
+''';
+    await findLint(src, LintNames.prefer_single_quotes);
+    await applyFix(DartFixKind.CHANGE_TO_SINGLE_QUOTES);
+    verifyResult(r"""
+main() {
+  print(r'''Hello,
+  world''');
+}
+""");
+  }
+
   test_makeFieldFinal_type() async {
     String src = '''
 class C {