Version 2.12.0-176.0.dev

Merge commit '35f9425b6de92c151c4cf195ca930c59d1208398' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_late.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_late.dart
index 93c14bd..5662724 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_late.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_late.dart
@@ -6,6 +6,8 @@
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 
@@ -18,27 +20,59 @@
     if (!libraryElement.isNonNullableByDefault) {
       return;
     }
-    if (node is SimpleIdentifier &&
-        node.parent is VariableDeclaration &&
-        node.parent.parent is VariableDeclarationList) {
-      var list = node.parent.parent as VariableDeclarationList;
-      if (!list.isLate) {
-        if (list.type == null) {
-          var keyword = list.keyword;
-          if (keyword == null) {
-            await _insertAt(builder, list.variables[0].offset);
-            // TODO(brianwilkerson) Consider converting this into an assist and
-            //  expand it to support converting `var` to `late` as well as
-            //  working anywhere a non-late local variable or field is selected.
+    var node = this.node;
+    if (node is SimpleIdentifier) {
+      if (node.parent is VariableDeclaration &&
+          node.parent.parent is VariableDeclarationList) {
+        var list = node.parent.parent as VariableDeclarationList;
+        if (!list.isLate) {
+          if (list.type == null) {
+            var keyword = list.keyword;
+            if (keyword == null) {
+              await _insertAt(builder, list.variables[0].offset);
+              // TODO(brianwilkerson) Consider converting this into an assist and
+              //  expand it to support converting `var` to `late` as well as
+              //  working anywhere a non-late local variable or field is selected.
 //          } else if (keyword.type == Keyword.VAR) {
 //            builder.addFileEdit(file, (builder) {
 //              builder.addSimpleReplacement(range.token(keyword), 'late');
 //            });
-          } else if (keyword.type != Keyword.CONST) {
-            await _insertAt(builder, list.variables[0].offset);
+            } else if (keyword.type != Keyword.CONST) {
+              await _insertAt(builder, list.variables[0].offset);
+            }
+          } else {
+            var keyword = list.keyword;
+            if (keyword != null) {
+              await _insertAt(builder, keyword.offset);
+            } else {
+              var type = list.type;
+              if (type != null) {
+                await _insertAt(builder, type.offset);
+              }
+            }
           }
-        } else {
-          await _insertAt(builder, list.type.offset);
+        }
+      } else {
+        var getter = node.writeOrReadElement;
+        if (getter is PropertyAccessorElement &&
+            getter.isGetter &&
+            getter.isSynthetic &&
+            !getter.variable.isSynthetic &&
+            getter.variable.setter == null &&
+            getter.enclosingElement is ClassElement) {
+          var declarationResult =
+              await sessionHelper.getElementDeclaration(getter.variable);
+          var variable = declarationResult.node;
+          if (variable is VariableDeclaration &&
+              variable.parent is VariableDeclarationList &&
+              variable.parent.parent is FieldDeclaration) {
+            VariableDeclarationList declarationList = variable.parent;
+            var keywordToken = declarationList.keyword;
+            if (declarationList.variables.length == 1 &&
+                keywordToken.keyword == Keyword.FINAL) {
+              await _insertAt(builder, keywordToken.offset);
+            }
+          }
         }
       }
     }
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 e0fed7e..5259ec0 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -632,6 +632,7 @@
   static const Map<ErrorCode, List<ProducerGenerator>> nonLintProducerMap = {
     CompileTimeErrorCode.ASSIGNMENT_TO_FINAL: [
       MakeFieldNotFinal.newInstance,
+      AddLate.newInstance,
     ],
     CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL: [
       MakeVariableNotFinal.newInstance,
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_late_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_late_test.dart
index 9558f70..e3a1c37 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_late_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_late_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -44,11 +45,76 @@
 ''');
     await assertHasFix('''
 class C {
-  final late String s;
+  late final String s;
 }
 ''');
   }
 
+  Future<void> test_withFinalAssignedInConstructor() async {
+    await resolveTestCode('''
+class C {
+  final String s;
+  C() {
+    s = '';
+  }
+}
+''');
+    await assertHasFix('''
+class C {
+  late final String s;
+  C() {
+    s = '';
+  }
+}
+''',
+        errorFilter: (error) =>
+            error.errorCode == CompileTimeErrorCode.ASSIGNMENT_TO_FINAL);
+  }
+
+  Future<void> test_withFinalAssignedInLibrary() async {
+    await resolveTestCode('''
+class C {
+  final String s;
+}
+
+void f(C c) {
+  c.s = '';
+}
+''');
+    await assertHasFix('''
+class C {
+  late final String s;
+}
+
+void f(C c) {
+  c.s = '';
+}
+''',
+        errorFilter: (error) =>
+            error.errorCode == CompileTimeErrorCode.ASSIGNMENT_TO_FINAL);
+  }
+
+  Future<void> test_withFinalStaticAssignedInConstructor() async {
+    await resolveTestCode('''
+class C {
+  static final String s;
+  C() {
+    s = '';
+  }
+}
+''');
+    await assertHasFix('''
+class C {
+  static late final String s;
+  C() {
+    s = '';
+  }
+}
+''',
+        errorFilter: (error) =>
+            error.errorCode == CompileTimeErrorCode.ASSIGNMENT_TO_FINAL);
+  }
+
   Future<void> test_withLate() async {
     await resolveTestCode('''
 class C {
diff --git a/tools/VERSION b/tools/VERSION
index 1bcadd3..e614057 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 175
+PRERELEASE 176
 PRERELEASE_PATCH 0
\ No newline at end of file