Analyzer/FE integration for writes to read-only variables.

Previously, when the user attempted to write to a read-only variable,
the front end creates a SyntheticExpressionJudgment to represent the
write.  This CL changes it to a new class,
InvalidVariableWriteJudgment, whose `infer` method sends the
appropriate resolution information to the analyzer.  Also, it ensures
that inference is performed on the RHS of the assignment, so that it
gets resolved too.

Partially addresses #33694.

Change-Id: I56b12e5082434ca8569d15df1b01e5aaad8f0a7d
Reviewed-on: https://dart-review.googlesource.com/63160
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
index a025360..6c1ab27 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
@@ -2333,34 +2333,6 @@
 
   @override
   @failingTest
-  test_prefix_assignment_compound_in_method() async {
-    // Bad state: No reference information for p at 46
-    await super.test_prefix_assignment_compound_in_method();
-  }
-
-  @override
-  @failingTest
-  test_prefix_assignment_compound_not_in_method() async {
-    // Bad state: No reference information for p at 32
-    await super.test_prefix_assignment_compound_not_in_method();
-  }
-
-  @override
-  @failingTest
-  test_prefix_assignment_in_method() async {
-    // Bad state: No reference information for p at 46
-    await super.test_prefix_assignment_in_method();
-  }
-
-  @override
-  @failingTest
-  test_prefix_assignment_not_in_method() async {
-    // Bad state: No reference information for p at 32
-    await super.test_prefix_assignment_not_in_method();
-  }
-
-  @override
-  @failingTest
   test_prefix_conditionalPropertyAccess_call() async {
     // Bad state: Expected element reference for analyzer offset 32; got one for kernel offset 35
     await super.test_prefix_conditionalPropertyAccess_call();
@@ -2445,13 +2417,6 @@
 
   @override
   @failingTest
-  test_prefixNotFollowedByDot_compoundAssignment() async {
-    // Bad state: No reference information for p at 32
-    await super.test_prefixNotFollowedByDot_compoundAssignment();
-  }
-
-  @override
-  @failingTest
   test_prefixNotFollowedByDot_conditionalMethodInvocation() async {
     // Bad state: Expected element reference for analyzer offset 32; got one for kernel offset 35
     await super.test_prefixNotFollowedByDot_conditionalMethodInvocation();
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
index f7f2ce2..883c655 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
@@ -637,6 +637,27 @@
     }
   }
 
+  test_assignment_to_final_variable_local() async {
+    var content = '''
+main() {
+  final x = 1;
+  x += 2;
+}
+''';
+    addTestFile(content);
+    AnalysisResult result = await driver.getResult(testFile);
+    expect(result.errors, isNotEmpty);
+
+    var xDeclaration = new NodeLocator(content.indexOf('x ='))
+        .searchWithin(result.unit) as SimpleIdentifier;
+    var xElement = xDeclaration.staticElement;
+    expect(xElement, isNotNull);
+    var xReference = new NodeLocator(content.indexOf('x +='))
+        .searchWithin(result.unit) as SimpleIdentifier;
+    expect(xReference.staticElement, same(xElement));
+    expect(xReference.staticType.toString(), 'int');
+  }
+
   test_assignmentExpression_compound_indexExpression() async {
     String content = r'''
 main() {
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index 24590c7..175791d 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -5612,6 +5612,7 @@
 const Code<Message Function(String name)> codeSetterNotFound =
     const Code<Message Function(String name)>(
         "SetterNotFound", templateSetterNotFound,
+        analyzerCode: "UNDEFINED_SETTER",
         severity: Severity.errorLegacyWarning);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 40571ac..394dfb6 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -297,8 +297,8 @@
     } else if (node is Expression) {
       return node;
     } else if (node is SuperInitializer) {
-      return buildCompileTimeError(
-          fasta.messageSuperAsExpression, node.fileOffset, noLength);
+      return new SyntheticExpressionJudgment(buildCompileTimeError(
+          fasta.messageSuperAsExpression, node.fileOffset, noLength));
     } else if (node is ProblemBuilder) {
       return buildProblemExpression(node, -1, noLength);
     } else {
@@ -376,9 +376,9 @@
     int offset = variable.fileOffset;
     Message message = template.withArguments(name);
     if (variable.initializer == null) {
-      variable.initializer =
-          buildCompileTimeError(message, offset, name.length, context: context)
-            ..parent = variable;
+      variable.initializer = new SyntheticExpressionJudgment(
+          buildCompileTimeError(message, offset, name.length, context: context))
+        ..parent = variable;
     } else {
       variable.initializer = wrapInLocatedCompileTimeError(
           variable.initializer, message.withLocation(uri, offset, name.length),
@@ -1094,8 +1094,8 @@
       pop();
       token = token.next;
       Message message = fasta.templateExpectedIdentifier.withArguments(token);
-      push(buildCompileTimeError(
-          message, offsetForToken(token), lengthForToken(token)));
+      push(new SyntheticExpressionJudgment(buildCompileTimeError(
+          message, offsetForToken(token), lengthForToken(token))));
     }
   }
 
@@ -1108,8 +1108,8 @@
       pop();
       token = token.next;
       Message message = fasta.templateExpectedIdentifier.withArguments(token);
-      push(buildCompileTimeError(
-          message, offsetForToken(token), lengthForToken(token)));
+      push(new SyntheticExpressionJudgment(buildCompileTimeError(
+          message, offsetForToken(token), lengthForToken(token))));
     }
   }
 
@@ -1183,7 +1183,7 @@
           isSetter: isSetter,
           isStatic: isStatic,
           isTopLevel: !isStatic && !isSuper);
-      return new SyntheticExpressionJudgment(new Throw(error));
+      return new Throw(error);
     }
   }
 
@@ -1803,8 +1803,10 @@
     Expression value = popForValue();
     Object generator = pop();
     if (generator is! Generator) {
-      push(buildCompileTimeError(fasta.messageNotAnLvalue,
-          offsetForToken(token), lengthForToken(token)));
+      push(new SyntheticExpressionJudgment(buildCompileTimeError(
+          fasta.messageNotAnLvalue,
+          offsetForToken(token),
+          lengthForToken(token))));
     } else {
       push(new DelayedAssignment(
           this, token, generator, value, token.stringValue));
@@ -2610,13 +2612,13 @@
     LocatedMessage argMessage = checkArgumentsForFunction(
         target.function, arguments, charOffset, typeParameters);
     if (argMessage != null) {
-      return throwNoSuchMethodError(
+      return new SyntheticExpressionJudgment(throwNoSuchMethodError(
           forest.literalNull(null)..fileOffset = charOffset,
           target.name.name,
           arguments,
           charOffset,
           candidate: target,
-          argMessage: argMessage);
+          argMessage: argMessage));
     }
     if (target is Constructor) {
       isConst =
@@ -2788,8 +2790,11 @@
       push(type.invokeConstructor(
           typeArguments, name, arguments, nameToken, constness));
     } else {
-      push(throwNoSuchMethodError(forest.literalNull(null)..fileOffset = offset,
-          debugName(getNodeName(type), name), arguments, nameToken.charOffset));
+      push(new SyntheticExpressionJudgment(throwNoSuchMethodError(
+          forest.literalNull(null)..fileOffset = offset,
+          debugName(getNodeName(type), name),
+          arguments,
+          nameToken.charOffset)));
     }
     constantContext = savedConstantContext;
   }
@@ -2894,11 +2899,11 @@
       nameToken = nameToken.next.next;
     }
 
-    return throwNoSuchMethodError(
+    return new SyntheticExpressionJudgment(throwNoSuchMethodError(
         forest.literalNull(null)..fileOffset = charOffset,
         errorName,
         arguments,
-        nameToken.charOffset);
+        nameToken.charOffset));
   }
 
   @override
@@ -3206,8 +3211,9 @@
           ? fasta.messageForInLoopExactlyOneVariable
           : fasta.messageForInLoopNotAssignable;
       Token token = forToken.next.next;
-      variable = new VariableDeclaration.forValue(buildCompileTimeError(
-          message, offsetForToken(token), lengthForToken(token)));
+      variable = new VariableDeclaration.forValue(
+          new SyntheticExpressionJudgment(buildCompileTimeError(
+              message, offsetForToken(token), lengthForToken(token))));
     }
     Statement result = new ForInJudgment(
         awaitToken,
@@ -3752,8 +3758,8 @@
   @override
   Expression deprecated_buildCompileTimeError(String error,
       [int charOffset = -1]) {
-    return buildCompileTimeError(
-        fasta.templateUnspecified.withArguments(error), charOffset, noLength);
+    return new SyntheticExpressionJudgment(buildCompileTimeError(
+        fasta.templateUnspecified.withArguments(error), charOffset, noLength));
   }
 
   @override
@@ -3761,9 +3767,8 @@
       {List<LocatedMessage> context}) {
     library.addCompileTimeError(message, charOffset, length, uri,
         wasHandled: true, context: context);
-    return new SyntheticExpressionJudgment(library.loader
-        .throwCompileConstantError(library.loader
-            .buildCompileTimeError(message, charOffset, length, uri)));
+    return library.loader.throwCompileConstantError(
+        library.loader.buildCompileTimeError(message, charOffset, length, uri));
   }
 
   Expression wrapInCompileTimeError(Expression expression, Message message,
@@ -3780,9 +3785,10 @@
     // TODO(askesc): Produce explicit error expression wrapping the original.
     // See [issue 29717](https://github.com/dart-lang/sdk/issues/29717)
     return new SyntheticExpressionJudgment(new Let(
-        new VariableDeclaration.forValue(buildCompileTimeError(
-            message.messageObject, message.charOffset, message.length,
-            context: context))
+        new VariableDeclaration.forValue(new SyntheticExpressionJudgment(
+            buildCompileTimeError(
+                message.messageObject, message.charOffset, message.length,
+                context: context)))
           ..fileOffset = forest.readOffset(expression),
         new Let(
             new VariableDeclaration.forValue(expression)
@@ -3835,7 +3841,9 @@
   Statement buildCompileTimeErrorStatement(Message message, int charOffset,
       {List<LocatedMessage> context}) {
     return new ExpressionStatementJudgment(
-        buildCompileTimeError(message, charOffset, noLength, context: context),
+        new SyntheticExpressionJudgment(buildCompileTimeError(
+            message, charOffset, noLength,
+            context: context)),
         null);
   }
 
@@ -3978,7 +3986,8 @@
   @override
   Expression buildProblemExpression(
       ProblemBuilder builder, int charOffset, int length) {
-    return buildCompileTimeError(builder.message, charOffset, length);
+    return new SyntheticExpressionJudgment(
+        buildCompileTimeError(builder.message, charOffset, length));
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index 6fb53a5..4a700dc 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -68,6 +68,7 @@
         Member,
         Name,
         Procedure,
+        SyntheticExpressionJudgment,
         TypeParameterType,
         VariableDeclaration;
 
@@ -181,8 +182,8 @@
   Initializer buildFieldInitializer(Map<String, int> initializedFields) {
     int offset = offsetForToken(token);
     return helper.buildInvalidInitializer(
-        helper.buildCompileTimeError(
-            messageInvalidInitializer, offset, lengthForToken(token)),
+        new SyntheticExpressionJudgment(helper.buildCompileTimeError(
+            messageInvalidInitializer, offset, lengthForToken(token))),
         offset);
   }
 
@@ -226,11 +227,11 @@
       assert(forest.argumentsTypeArguments(arguments).isEmpty);
       forest.argumentsSetTypeArguments(arguments, typeArguments);
     }
-    return helper.throwNoSuchMethodError(
+    return new SyntheticExpressionJudgment(helper.throwNoSuchMethodError(
         forest.literalNull(token),
         name == "" ? plainNameForRead : "${plainNameForRead}.$name",
         arguments,
-        nameToken.charOffset);
+        nameToken.charOffset));
   }
 
   bool get isThisPropertyAccess => false;
@@ -640,10 +641,10 @@
   String get debugName => "LargeIntAccessGenerator";
 
   Expression buildError() {
-    return helper.buildCompileTimeError(
+    return new SyntheticExpressionJudgment(helper.buildCompileTimeError(
         templateIntegerLiteralIsOutOfRange.withArguments(token),
         offsetForToken(token),
-        lengthForToken(token));
+        lengthForToken(token)));
   }
 
   @override
@@ -781,13 +782,13 @@
   Expression buildError(Arguments arguments,
       {bool isGetter: false, bool isSetter: false, int offset}) {
     offset ??= offsetForToken(this.token);
-    return helper.throwNoSuchMethodError(
+    return new SyntheticExpressionJudgment(helper.throwNoSuchMethodError(
         forest.literalNull(null)..fileOffset = offset,
         plainNameForRead,
         arguments,
         offset,
         isGetter: isGetter,
-        isSetter: isSetter);
+        isSetter: isSetter));
   }
 
   @override
@@ -1075,8 +1076,10 @@
 
   @override
   Expression makeInvalidRead() {
-    return helper.buildCompileTimeError(messageCantUsePrefixAsExpression,
-        offsetForToken(token), lengthForToken(token));
+    return new SyntheticExpressionJudgment(helper.buildCompileTimeError(
+        messageCantUsePrefixAsExpression,
+        offsetForToken(token),
+        lengthForToken(token)));
   }
 
   @override
@@ -1115,11 +1118,11 @@
 
   @override
   Expression doInvocation(int offset, Arguments arguments) {
-    return helper.throwNoSuchMethodError(
+    return new SyntheticExpressionJudgment(helper.throwNoSuchMethodError(
         forest.literalNull(null)..fileOffset = offset,
         plainNameForRead,
         arguments,
-        offsetForToken(token));
+        offsetForToken(token)));
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart
index 1798ae5..084bc9f 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart
@@ -107,6 +107,8 @@
         PrefixBuilder,
         TypeDeclarationBuilder;
 
+import 'kernel_shadow_ast.dart' show InvalidVariableWriteJudgment;
+
 part 'kernel_expression_generator_impl.dart';
 
 abstract class KernelExpressionGenerator implements ExpressionGenerator {
@@ -214,22 +216,26 @@
 
   @override
   Expression makeInvalidRead() {
-    return helper.throwNoSuchMethodError(
+    return new SyntheticExpressionJudgment(helper.throwNoSuchMethodError(
         forest.literalNull(token),
         plainNameForRead,
         forest.argumentsEmpty(noLocation),
         offsetForToken(token),
-        isGetter: true);
+        isGetter: true));
   }
 
   @override
   Expression makeInvalidWrite(Expression value) {
-    return helper.throwNoSuchMethodError(
+    return buildInvalidWriteJudgment(helper.throwNoSuchMethodError(
         forest.literalNull(token),
         plainNameForRead,
         forest.arguments(<Expression>[value], noLocation),
         offsetForToken(token),
-        isSetter: true);
+        isSetter: true));
+  }
+
+  Expression buildInvalidWriteJudgment(Expression desugared) {
+    return new SyntheticExpressionJudgment(desugared);
   }
 
   Expression _makeSimpleRead() => _makeRead(null);
@@ -1231,13 +1237,13 @@
 
   @override
   Expression makeInvalidWrite(Expression value) {
-    return helper.throwNoSuchMethodError(
+    return new SyntheticExpressionJudgment(helper.throwNoSuchMethodError(
         forest.literalNull(token),
         plainNameForRead,
         forest.arguments(<Expression>[value], null)
           ..fileOffset = value.fileOffset,
         offsetForToken(token),
-        isSetter: true);
+        isSetter: true));
   }
 
   @override
@@ -1324,6 +1330,18 @@
       super._finish(makeLet(value, body), complexAssignment);
 
   @override
+  Expression buildInvalidWriteJudgment(Expression desugared) {
+    var expression = this.expression;
+    if (expression is VariableGet) {
+      return new InvalidVariableWriteJudgment(desugared, expression.variable)
+        ..fileOffset = token.charOffset;
+    } else {
+      // TODO(paulberry): handle other cases
+      return super.buildInvalidWriteJudgment(desugared);
+    }
+  }
+
+  @override
   Expression doInvocation(int offset, Arguments arguments) {
     return helper.buildMethodInvocation(buildSimpleRead(), callName, arguments,
         adjustForImplicitCall(plainNameForRead, offset),
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart
index d777162..7f5a3dc 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart
@@ -36,8 +36,10 @@
     if (!isSuper) {
       return forest.thisExpression(token);
     } else {
-      return helper.buildCompileTimeError(messageSuperAsExpression,
-          offsetForToken(token), lengthForToken(token));
+      return new SyntheticExpressionJudgment(helper.buildCompileTimeError(
+          messageSuperAsExpression,
+          offsetForToken(token),
+          lengthForToken(token)));
     }
   }
 
@@ -91,8 +93,8 @@
     if (isInitializer) {
       return buildConstructorInitializer(offset, new Name(""), arguments);
     } else if (isSuper) {
-      return helper.buildCompileTimeError(
-          messageSuperAsExpression, offset, noLength);
+      return new SyntheticExpressionJudgment(helper.buildCompileTimeError(
+          messageSuperAsExpression, offset, noLength));
     } else {
       return helper.buildMethodInvocation(
           forest.thisExpression(null), callName, arguments, offset,
@@ -109,13 +111,14 @@
           constructor.function, arguments, offset, <TypeParameter>[]);
     }
     if (constructor == null || argMessage != null) {
-      return helper.buildInvalidInitializer(helper.throwNoSuchMethodError(
-          forest.literalNull(null)..fileOffset = offset,
-          name.name,
-          arguments,
-          offset,
-          isSuper: isSuper,
-          argMessage: argMessage));
+      return helper.buildInvalidInitializer(new SyntheticExpressionJudgment(
+          helper.throwNoSuchMethodError(
+              forest.literalNull(null)..fileOffset = offset,
+              name.name,
+              arguments,
+              offset,
+              isSuper: isSuper,
+              argMessage: argMessage)));
     } else if (isSuper) {
       return helper.buildSuperInitializer(
           false, constructor, arguments, offset);
@@ -208,7 +211,8 @@
       offset = offsetForToken(token);
       length = lengthForToken(token);
     }
-    return helper.buildCompileTimeError(message, offset, length);
+    return new SyntheticExpressionJudgment(
+        helper.buildCompileTimeError(message, offset, length));
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index afac249..4f8ff56 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -1637,7 +1637,9 @@
 /// Concrete shadow object representing an assignment to a target for which
 /// assignment is not allowed.
 class IllegalAssignmentJudgment extends ComplexAssignmentJudgment {
-  IllegalAssignmentJudgment(ExpressionJudgment rhs) : super(rhs);
+  IllegalAssignmentJudgment(ExpressionJudgment rhs) : super(rhs) {
+    rhs.parent = this;
+  }
 
   @override
   DartType _getWriteType(ShadowTypeInferrer inferrer) {
@@ -1652,6 +1654,7 @@
     if (write != null) {
       inferrer.inferExpression(factory, write, const UnknownType(), false);
     }
+    inferrer.inferExpression(factory, rhs, const UnknownType(), false);
     _replaceWithDesugared();
     inferredType = const DynamicType();
     return null;
@@ -2906,6 +2909,26 @@
   }
 }
 
+/// Synthetic judgment class representing an attempt to write to a read-only
+/// local variable.
+class InvalidVariableWriteJudgment extends SyntheticExpressionJudgment {
+  /// Note: private to avoid colliding with Let.variable.
+  final VariableDeclaration _variable;
+
+  InvalidVariableWriteJudgment(kernel.Expression desugared, this._variable)
+      : super(desugared);
+
+  @override
+  Expression infer<Expression, Statement, Initializer, Type>(
+      ShadowTypeInferrer inferrer,
+      Factory<Expression, Statement, Initializer, Type> factory,
+      DartType typeContext) {
+    inferrer.listener.variableAssign(this, fileOffset, _variable.type,
+        _variable.fileOffset, null, _variable.type);
+    return super.infer(inferrer, factory, typeContext);
+  }
+}
+
 /// Shadow object for expressions that are introduced by the front end as part
 /// of desugaring or the handling of error conditions.
 ///
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index acb161a..2a7dc9e 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -76,12 +76,13 @@
 import '../kernel/kernel_shadow_ast.dart'
     show
         ArgumentsJudgment,
+        ConstructorInvocationJudgment,
         ExpressionJudgment,
         NullJudgment,
         ShadowClass,
-        ConstructorInvocationJudgment,
         ShadowField,
         ShadowMember,
+        SyntheticExpressionJudgment,
         VariableDeclarationJudgment,
         getExplicitTypeArguments;
 
@@ -657,10 +658,10 @@
           new Let(
               new VariableDeclaration.forValue(receiver)
                 ..fileOffset = receiver.fileOffset,
-              helper.buildCompileTimeError(
+              new SyntheticExpressionJudgment(helper.buildCompileTimeError(
                   errorTemplate.withArguments(name.name, receiverType),
                   fileOffset,
-                  noLength))
+                  noLength)))
             ..fileOffset = fileOffset);
     }
     return interfaceMember;
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 7dd456c..772abe1 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -331,7 +331,7 @@
 SdkSpecificationNotFound/example: Fail
 SdkSummaryNotFound/analyzerCode: Fail
 SdkSummaryNotFound/example: Fail
-SetterNotFound/analyzerCode: Fail
+SetterNotFound/dart2jsCode: Fail
 SetterNotFound/example: Fail
 SetterNotSync/example: Fail
 SetterWithWrongNumberOfFormals/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index dbbf02a..4a022c8 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -1136,6 +1136,7 @@
 
 SetterNotFound:
   template: "Setter not found: '#name'."
+  analyzerCode: UNDEFINED_SETTER
   severity: ERROR_LEGACY_WARNING
 
 MethodNotFound: