Version 2.12.0-3.0.dev

Merge commit '2d4a3bd913c1f61da00ee96cfef2f90361f15271' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/ast/extensions.dart b/pkg/analyzer/lib/src/dart/ast/extensions.dart
index b683c91..2063cd9 100644
--- a/pkg/analyzer/lib/src/dart/ast/extensions.dart
+++ b/pkg/analyzer/lib/src/dart/ast/extensions.dart
@@ -8,6 +8,29 @@
 import 'package:analyzer/src/dart/ast/ast.dart';
 
 /// TODO(scheglov) https://github.com/dart-lang/sdk/issues/43608
+Element _readElement(AstNode node) {
+  var parent = node.parent;
+
+  if (parent is AssignmentExpression && parent.leftHandSide == node) {
+    return parent.readElement;
+  }
+  if (parent is PostfixExpression && parent.operand == node) {
+    return parent.readElement;
+  }
+  if (parent is PrefixExpression && parent.operand == node) {
+    return parent.readElement;
+  }
+
+  if (parent is PrefixedIdentifier && parent.identifier == node) {
+    return _readElement(parent);
+  }
+  if (parent is PropertyAccess && parent.propertyName == node) {
+    return _readElement(parent);
+  }
+  return null;
+}
+
+/// TODO(scheglov) https://github.com/dart-lang/sdk/issues/43608
 Element _writeElement(AstNode node) {
   var parent = node.parent;
 
@@ -73,6 +96,14 @@
 
 /// TODO(scheglov) https://github.com/dart-lang/sdk/issues/43608
 extension IdentifierExtension on Identifier {
+  Element get writeElement {
+    return _writeElement(this);
+  }
+
+  Element get readElement {
+    return _readElement(this);
+  }
+
   Element get writeOrReadElement {
     return _writeElement(this) ?? staticElement;
   }
diff --git a/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart b/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart
index ad20eab..c4368cf 100644
--- a/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart
+++ b/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart
@@ -161,7 +161,9 @@
         usedElements.addElement(element);
       }
     } else {
-      _useIdentifierElement(node);
+      _useIdentifierElement(node, node.readElement);
+      _useIdentifierElement(node, node.writeElement);
+      _useIdentifierElement(node, node.staticElement);
       var parent = node.parent;
       // If [node] is a method tear-off, assume all parameters are used.
       var functionReferenceIsCall =
@@ -216,9 +218,8 @@
     }
   }
 
-  /// Marks an [Element] of [node] as used in the library.
-  void _useIdentifierElement(Identifier node) {
-    Element element = node.staticElement;
+  /// Marks the [element] of [node] as used in the library.
+  void _useIdentifierElement(Identifier node, Element element) {
     if (element == null) {
       return;
     }
diff --git a/pkg/analyzer/test/src/diagnostics/unused_element_test.dart b/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
index 3850c62..fc48249 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
@@ -155,6 +155,31 @@
     ]);
   }
 
+  test_classGetterSetter_isUsed_assignmentExpression_compound() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  int get _foo => 0;
+  set _foo(int _) {}
+
+  void f() {
+    _foo += 2;
+  }
+}
+''');
+  }
+
+  test_classSetter_isUsed_assignmentExpression_simple() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  set _foo(int _) {}
+
+  void f() {
+    _foo = 0;
+  }
+}
+''');
+  }
+
   test_constructor_isUsed_asRedirectee() async {
     await assertNoErrorsInCode(r'''
 class A {
@@ -818,8 +843,8 @@
     ]);
   }
 
-  // Postfix operators can only be called, not defined. The "notUsed" sibling to
-  // this test is the test on a binary operator.
+  /// Postfix operators can only be called, not defined. The "notUsed" sibling to
+  /// this test is the test on a binary operator.
   test_method_notUsed_privateExtension_indexEqOperator() async {
     await assertErrorsInCode(r'''
 extension _A on bool {
@@ -840,8 +865,8 @@
     ]);
   }
 
-  // Assignment operators can only be called, not defined. The "notUsed" sibling
-  // to this test is the test on a binary operator.
+  /// Assignment operators can only be called, not defined. The "notUsed" sibling
+  /// to this test is the test on a binary operator.
   test_method_notUsed_privateExtension_operator() async {
     await assertErrorsInCode(r'''
 extension _A on String {
@@ -1383,6 +1408,57 @@
     ]);
   }
 
+  test_topLevelGetterSetter_isUsed_assignmentExpression_compound() async {
+    await assertNoErrorsInCode(r'''
+int get _foo => 0;
+set _foo(int _) {}
+
+void f() {
+  _foo += 2;
+}
+''');
+  }
+
+  test_topLevelGetterSetter_isUsed_postfixExpression_increment() async {
+    await assertNoErrorsInCode(r'''
+int get _foo => 0;
+set _foo(int _) {}
+
+void f() {
+  _foo++;
+}
+''');
+  }
+
+  test_topLevelGetterSetter_isUsed_prefixExpression_increment() async {
+    await assertNoErrorsInCode(r'''
+int get _foo => 0;
+set _foo(int _) {}
+
+void f() {
+  ++_foo;
+}
+''');
+  }
+
+  test_topLevelSetter_isUsed_assignmentExpression_simple() async {
+    await assertNoErrorsInCode(r'''
+set _foo(int _) {}
+
+void f() {
+  _foo = 0;
+}
+''');
+  }
+
+  test_topLevelSetter_notUsed() async {
+    await assertErrorsInCode(r'''
+set _foo(int _) {}
+''', [
+      error(HintCode.UNUSED_ELEMENT, 4, 4),
+    ]);
+  }
+
   test_topLevelVariable_isUsed() async {
     await assertNoErrorsInCode(r'''
 int _a = 1;
diff --git a/tools/VERSION b/tools/VERSION
index 269151e..535cc4c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 2
+PRERELEASE 3
 PRERELEASE_PATCH 0
\ No newline at end of file