Version 2.11.0-268.0.dev

Merge commit 'c45d52b62aacb073bb3d8d6b433649dd672fac6e' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_fragment_parser.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_fragment_parser.dart
new file mode 100644
index 0000000..773eab0
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_fragment_parser.dart
@@ -0,0 +1,311 @@
+// Copyright (c) 2020, 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/data_driven/accessor.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/parameter_reference.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:analyzer/error/listener.dart';
+
+/// A parser for the textual representation of a code fragment.
+class CodeFragmentParser {
+  /// The error reporter to which diagnostics will be reported.
+  final ErrorReporter errorReporter;
+
+  /// The amount to be added to translate from offsets within the content to
+  /// offsets within the file.
+  int delta;
+
+  /// The tokens being parsed.
+  List<_Token> tokens;
+
+  /// The accessors that have been parsed.
+  List<Accessor> accessors = [];
+
+  /// Initialize a newly created parser to report errors to the [errorReporter].
+  CodeFragmentParser(this.errorReporter);
+
+  /// Parse the [content] into a list of accessors. Add the [delta] to translate
+  /// from offsets within the content to offsets within the file.
+  ///
+  /// <content> ::=
+  ///   <accessor> ('.' <accessor>)*
+  List<Accessor> parse(String content, int delta) {
+    this.delta = delta;
+    tokens = _CodeFragmentScanner(content, delta, errorReporter).scan();
+    if (tokens == null) {
+      // The error has already been reported.
+      return null;
+    }
+    var index = _parseAccessor(0);
+    while (index < tokens.length) {
+      var token = tokens[index];
+      if (token.kind == _TokenKind.period) {
+        index = _parseAccessor(index + 1);
+      } else {
+        errorReporter.reportErrorForOffset(TransformSetErrorCode.wrongToken,
+            token.offset + delta, token.length, ['.', token.kind.displayName]);
+        return null;
+      }
+    }
+    return accessors;
+  }
+
+  /// Return the token at the given [index] if it exists and if it has one of
+  /// the [validKinds]. Report an error and return `null` if those conditions
+  /// aren't met.
+  _Token _expect(int index, List<_TokenKind> validKinds) {
+    String validKindsDisplayString() {
+      var buffer = StringBuffer();
+      for (var i = 0; i < validKinds.length; i++) {
+        if (i > 0) {
+          if (i == validKinds.length - 1) {
+            buffer.write(' or ');
+          } else {
+            buffer.write(', ');
+          }
+        }
+        buffer.write(validKinds[i].displayName);
+      }
+      return buffer.toString();
+    }
+
+    if (index >= tokens.length) {
+      var offset = 0;
+      var length = 0;
+      if (tokens.isNotEmpty) {
+        var last = tokens.last;
+        offset = last.offset;
+        length = last.length;
+      }
+      errorReporter.reportErrorForOffset(TransformSetErrorCode.missingToken,
+          offset + delta, length, [validKindsDisplayString()]);
+      return null;
+    }
+    var token = tokens[index];
+    if (!validKinds.contains(token.kind)) {
+      errorReporter.reportErrorForOffset(
+          TransformSetErrorCode.wrongToken,
+          token.offset + delta,
+          token.length,
+          [validKindsDisplayString(), token.kind.displayName]);
+      return null;
+    }
+    return token;
+  }
+
+  /// Parse an accessor.
+  ///
+  /// <accessor> ::=
+  ///   <identifier> '[' (<integer> | <identifier>) ']'
+  int _parseAccessor(int index) {
+    var token = _expect(index, const [_TokenKind.identifier]);
+    if (token == null) {
+      // The error has already been reported.
+      return tokens.length;
+    }
+    var identifier = token.lexeme;
+    if (identifier == 'arguments') {
+      token = _expect(index + 1, const [_TokenKind.openSquareBracket]);
+      if (token == null) {
+        // The error has already been reported.
+        return tokens.length;
+      }
+      token = _expect(index + 2, [_TokenKind.identifier, _TokenKind.integer]);
+      if (token == null) {
+        // The error has already been reported.
+        return tokens.length;
+      }
+      ParameterReference reference;
+      if (token.kind == _TokenKind.identifier) {
+        reference = NamedParameterReference(token.lexeme);
+      } else {
+        var argumentIndex = int.parse(token.lexeme);
+        reference = PositionalParameterReference(argumentIndex);
+      }
+      token = _expect(index + 3, [_TokenKind.closeSquareBracket]);
+      if (token == null) {
+        // The error has already been reported.
+        return tokens.length;
+      }
+      accessors.add(ArgumentAccessor(reference));
+      return index + 4;
+    } else if (identifier == 'typeArguments') {
+      token = _expect(index + 1, const [_TokenKind.openSquareBracket]);
+      if (token == null) {
+        // The error has already been reported.
+        return tokens.length;
+      }
+      token = _expect(index + 2, [_TokenKind.integer]);
+      if (token == null) {
+        // The error has already been reported.
+        return tokens.length;
+      }
+      var argumentIndex = int.parse(token.lexeme);
+      var reference = PositionalParameterReference(argumentIndex);
+      token = _expect(index + 3, [_TokenKind.closeSquareBracket]);
+      if (token == null) {
+        // The error has already been reported.
+        return tokens.length;
+      }
+      accessors.add(ArgumentAccessor(reference));
+      return index + 4;
+    } else {
+      errorReporter.reportErrorForOffset(TransformSetErrorCode.unknownAccessor,
+          token.offset, token.length, [identifier]);
+      return tokens.length;
+    }
+  }
+}
+
+/// A scanner for the textual representation of a code fragment.
+class _CodeFragmentScanner {
+  static final int $0 = '0'.codeUnitAt(0);
+
+  static final int $9 = '9'.codeUnitAt(0);
+
+  static final int $a = 'a'.codeUnitAt(0);
+
+  static final int $z = 'z'.codeUnitAt(0);
+
+  static final int $A = 'A'.codeUnitAt(0);
+  static final int $Z = 'Z'.codeUnitAt(0);
+  static final int closeSquareBracket = ']'.codeUnitAt(0);
+  static final int carriageReturn = '\r'.codeUnitAt(0);
+  static final int newline = '\n'.codeUnitAt(0);
+  static final int openSquareBracket = '['.codeUnitAt(0);
+  static final int period = '.'.codeUnitAt(0);
+  static final int space = ' '.codeUnitAt(0);
+
+  /// The string being scanned.
+  final String content;
+
+  /// The length of the string being scanned.
+  final int length;
+
+  /// The offset in the file of the first character in the string being scanned.
+  final int delta;
+
+  /// The error reporter to which diagnostics will be reported.
+  final ErrorReporter errorReporter;
+
+  /// Initialize a newly created scanner to scan the given [content].
+  _CodeFragmentScanner(this.content, this.delta, this.errorReporter)
+      : length = content.length;
+
+  /// Return the tokens in the content, or `null` if there is an error in the
+  /// content that prevents it from being scanned.
+  List<_Token> scan() {
+    if (content.isEmpty) {}
+    var length = content.length;
+    var offset = _skipWhitespace(0);
+    var tokens = <_Token>[];
+    while (offset < length) {
+      var char = content.codeUnitAt(offset);
+      if (char == closeSquareBracket) {
+        tokens.add(_Token(offset, _TokenKind.closeSquareBracket, ']'));
+        offset++;
+      } else if (char == openSquareBracket) {
+        tokens.add(_Token(offset, _TokenKind.openSquareBracket, '['));
+        offset++;
+      } else if (char == period) {
+        tokens.add(_Token(offset, _TokenKind.period, '.'));
+        offset++;
+      } else if (_isLetter(char)) {
+        var start = offset;
+        offset++;
+        while (offset < length && _isLetter(content.codeUnitAt(offset))) {
+          offset++;
+        }
+        tokens.add(_Token(
+            start, _TokenKind.identifier, content.substring(start, offset)));
+      } else if (_isDigit(char)) {
+        var start = offset;
+        offset++;
+        while (offset < length && _isDigit(content.codeUnitAt(offset))) {
+          offset++;
+        }
+        tokens.add(_Token(
+            start, _TokenKind.integer, content.substring(start, offset)));
+      } else {
+        errorReporter.reportErrorForOffset(
+            TransformSetErrorCode.invalidCharacter,
+            offset + delta,
+            1,
+            [content.substring(offset, offset + 1)]);
+        return null;
+      }
+      offset = _skipWhitespace(offset);
+    }
+    return tokens;
+  }
+
+  /// Return `true` if the [char] is a digit.
+  bool _isDigit(int char) => (char >= $0 && char <= $9);
+
+  /// Return `true` if the [char] is a letter.
+  bool _isLetter(int char) =>
+      (char >= $a && char <= $z) || (char >= $A && char <= $Z);
+
+  /// Return `true` if the [char] is a whitespace character.
+  bool _isWhitespace(int char) =>
+      char == space || char == newline || char == carriageReturn;
+
+  /// Return the index of the first character at or after the given [offset]
+  /// that isn't a whitespace character.
+  int _skipWhitespace(int offset) {
+    while (offset < length) {
+      var char = content.codeUnitAt(offset);
+      if (!_isWhitespace(char)) {
+        return offset;
+      }
+      offset++;
+    }
+    return offset;
+  }
+}
+
+/// A token in a code fragment's string representation.
+class _Token {
+  /// The offset of the token.
+  final int offset;
+
+  /// The kind of the token.
+  final _TokenKind kind;
+
+  /// The lexeme of the token.
+  final String lexeme;
+
+  /// Initialize a newly created token.
+  _Token(this.offset, this.kind, this.lexeme);
+
+  /// Return the length of this token.
+  int get length => lexeme.length;
+}
+
+/// An indication of the kind of a token.
+enum _TokenKind {
+  closeSquareBracket,
+  identifier,
+  integer,
+  openSquareBracket,
+  period,
+}
+
+extension on _TokenKind {
+  String get displayName {
+    switch (this) {
+      case _TokenKind.closeSquareBracket:
+        return "']'";
+      case _TokenKind.identifier:
+        return 'an identifier';
+      case _TokenKind.integer:
+        return 'an integer';
+      case _TokenKind.openSquareBracket:
+        return "'['";
+      case _TokenKind.period:
+        return "'.'";
+    }
+    return '';
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
index 8394acd..2788422 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
@@ -10,6 +10,13 @@
 class TransformSetErrorCode extends ErrorCode {
   /**
    * Parameters:
+   * 0: the character that is invalid
+   */
+  static const TransformSetErrorCode invalidCharacter =
+      TransformSetErrorCode('invalid_character', "Invalid character '{0}'.");
+
+  /**
+   * Parameters:
    * 0: the key with which the value is associated
    * 1: the expected type of the value
    * 0: the actual type of the value
@@ -42,6 +49,13 @@
 
   /**
    * Parameters:
+   * 0: a description of the expected kinds of tokens
+   */
+  static const TransformSetErrorCode missingToken =
+      TransformSetErrorCode('missing_token', "Expected to find {0}.");
+
+  /**
+   * Parameters:
    * 0: the missing key
    */
   static const TransformSetErrorCode undefinedVariable = TransformSetErrorCode(
@@ -49,6 +63,13 @@
 
   /**
    * Parameters:
+   * 0: a description of the expected kind of token
+   */
+  static const TransformSetErrorCode unknownAccessor = TransformSetErrorCode(
+      'unknown_accessor', "The accessor '{0}' is invalid.");
+
+  /**
+   * Parameters:
    * 0: the unsupported key
    */
   static const TransformSetErrorCode unsupportedKey = TransformSetErrorCode(
@@ -56,6 +77,14 @@
 
   /**
    * Parameters:
+   * 0: a description of the expected kind of token
+   * 1: a description of the actial kind of token
+   */
+  static const TransformSetErrorCode wrongToken = TransformSetErrorCode(
+      'wrong_token', "Expected to find {0}, but found {1}.");
+
+  /**
+   * Parameters:
    * 0: the message produced by the YAML parser
    */
   static const TransformSetErrorCode yamlSyntaxError =
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
index 86ea95b..bad163e 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
@@ -2,9 +2,9 @@
 // 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/data_driven/accessor.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/add_type_parameter.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/change.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/code_fragment_parser.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/code_template.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/element_descriptor.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/element_kind.dart';
@@ -68,6 +68,7 @@
   static const String _transformsKey = 'transforms';
   static const String _typedefKey = 'typedef';
   static const String _urisKey = 'uris';
+  static const String _valueKey = 'value';
   static const String _variableKey = 'variable';
   static const String _variablesKey = 'variables';
   static const String _versionKey = 'version';
@@ -85,7 +86,7 @@
 
   static const String _addParameterKind = 'addParameter';
   static const String _addTypeParameterKind = 'addTypeParameter';
-  static const String _argumentKind = 'argument';
+  static const String _fragmentKind = 'fragment';
   static const String _importKind = 'import';
   static const String _removeParameterKind = 'removeParameter';
   static const String _renameKind = 'rename';
@@ -192,6 +193,15 @@
     return node.runtimeType.toString();
   }
 
+  /// Return the offset of the first character in the [string], exclusive of any
+  /// surrounding quotes.
+  int _offsetOfString(YamlScalar string) {
+    // TODO(brianwilkerson) We add 1 to account for the quotes around the
+    //  string, but quotes aren't required, so we need to use the style of the
+    //  [string] is to get the right offset.
+    return string.span.start.offset + 1;
+  }
+
   /// Return the result of parsing the file [content] into a YAML node.
   YamlNode _parseYaml(String content) {
     try {
@@ -349,37 +359,6 @@
         argumentValue: argumentValue);
   }
 
-  /// Translate the [node] into a value extractor. Return the resulting
-  /// extractor, or `null` if the [node] does not represent a valid value
-  /// extractor.
-  ValueGenerator _translateArgumentExtractor(YamlMap node) {
-    var indexNode = node.valueAt(_indexKey);
-    if (indexNode != null) {
-      _reportUnsupportedKeys(node, const {_indexKey, _kindKey});
-      var index = _translateInteger(
-          indexNode, ErrorContext(key: _indexKey, parentNode: node));
-      if (index == null) {
-        // The error has already been reported.
-        return null;
-      }
-      return CodeFragment(
-          [ArgumentAccessor(PositionalParameterReference(index))]);
-    }
-    var nameNode = node.valueAt(_nameKey);
-    if (nameNode != null) {
-      _reportUnsupportedKeys(node, const {_nameKey, _kindKey});
-      var name = _translateString(
-          nameNode, ErrorContext(key: _nameKey, parentNode: node));
-      if (name == null) {
-        // The error has already been reported.
-        return null;
-      }
-      return CodeFragment([ArgumentAccessor(NamedParameterReference(name))]);
-    }
-    // TODO(brianwilkerson) Report the missing YAML.
-    return null;
-  }
-
   /// Translate the [node] into a bool. Return the resulting bool, or `null`
   /// if the [node] does not represent a valid bool. If the [node] is not
   /// valid, use the [context] to report the error.
@@ -433,6 +412,27 @@
     }
   }
 
+  /// Translate the [node] into a value generator. Return the resulting
+  /// generator, or `null` if the [node] does not represent a valid value
+  /// extractor.
+  ValueGenerator _translateCodeFragment(YamlMap node) {
+    _reportUnsupportedKeys(node, const {_kindKey, _valueKey});
+    var valueNode = node.valueAt(_valueKey);
+    var value = _translateString(
+        valueNode, ErrorContext(key: _valueKey, parentNode: node));
+    if (value == null) {
+      // The error has already been reported.
+      return null;
+    }
+    var accessors = CodeFragmentParser(errorReporter)
+        .parse(value, _offsetOfString(valueNode));
+    if (accessors == null) {
+      // The error has already been reported.
+      return null;
+    }
+    return CodeFragment(accessors);
+  }
+
   /// Translate the [node] into a code template. Return the resulting template,
   /// or `null` if the [node] does not represent a valid code template. If the
   /// [node] is not valid, use the [context] to report the error.
@@ -446,10 +446,7 @@
       if (expressionNode != null) {
         _reportUnsupportedKeys(node, const {_expressionKey, _variablesKey});
         kind = CodeTemplateKind.expression;
-        // TODO(brianwilkerson) We add 1 to account for the quotes around the
-        //  string, but quotes aren't required, so we need to find out what
-        //  style of node [expressionNode] is to get the right offset.
-        templateOffset = expressionNode.span.start.offset + 1;
+        templateOffset = _offsetOfString(expressionNode);
         template = _translateString(expressionNode,
             ErrorContext(key: _expressionKey, parentNode: node));
       } else {
@@ -457,10 +454,7 @@
         if (statementsNode != null) {
           _reportUnsupportedKeys(node, const {_statementsKey, _variablesKey});
           kind = CodeTemplateKind.statements;
-          // TODO(brianwilkerson) We add 1 to account for the quotes around the
-          //  string, but quotes aren't required, so we need to find out what
-          //  style of node [expressionNode] is to get the right offset.
-          templateOffset = statementsNode.span.start.offset + 1;
+          templateOffset = _offsetOfString(statementsNode);
           template = _translateString(statementsNode,
               ErrorContext(key: _statementsKey, parentNode: node));
         } else {
@@ -569,8 +563,8 @@
     }
   }
 
-  /// Translate the [node] into a value extractor. Return the resulting
-  /// extractor, or `null` if the [node] does not represent a valid value
+  /// Translate the [node] into a value generator. Return the resulting
+  /// generator, or `null` if the [node] does not represent a valid value
   /// extractor.
   ValueGenerator _translateImportValue(YamlMap node) {
     _reportUnsupportedKeys(node, const {_kindKey, _nameKey, _urisKey});
@@ -843,13 +837,13 @@
           ErrorContext(key: _kindKey, parentNode: node));
       if (kind == null) {
         return null;
-      } else if (kind == _argumentKind) {
-        return _translateArgumentExtractor(node);
+      } else if (kind == _fragmentKind) {
+        return _translateCodeFragment(node);
       } else if (kind == _importKind) {
         return _translateImportValue(node);
       }
       return _reportInvalidValueOneOf(node, context, [
-        _argumentKind,
+        _fragmentKind,
         _importKind,
       ]);
     } else if (node == null) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_fragment_parser_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_fragment_parser_test.dart
new file mode 100644
index 0000000..719eb33
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_fragment_parser_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2020, 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:_fe_analyzer_shared/src/base/errors.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/accessor.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/code_fragment_parser.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:matcher/matcher.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../../../mocks.dart';
+import '../../../../../utils/test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(CodeFragmentParserTest);
+  });
+}
+
+abstract class AbstractCodeFragmentParserTest {
+  List<Accessor> assertErrors(
+      String content, List<ExpectedError> expectedErrors) {
+    var errorListener = GatheringErrorListener();
+    var errorReporter = ErrorReporter(errorListener, MockSource());
+    var accessors = CodeFragmentParser(errorReporter).parse(content, 0);
+    errorListener.assertErrors(expectedErrors);
+    return accessors;
+  }
+
+  List<Accessor> assertNoErrors(String content) {
+    var errorListener = GatheringErrorListener();
+    var errorReporter = ErrorReporter(errorListener, MockSource());
+    var accessors = CodeFragmentParser(errorReporter).parse(content, 0);
+    errorListener.assertNoErrors();
+    return accessors;
+  }
+
+  ExpectedError error(ErrorCode code, int offset, int length,
+          {String message,
+          Pattern messageContains,
+          List<ExpectedContextMessage> contextMessages =
+              const <ExpectedContextMessage>[]}) =>
+      ExpectedError(code, offset, length,
+          message: message,
+          messageContains: messageContains,
+          expectedContextMessages: contextMessages);
+}
+
+@reflectiveTest
+class CodeFragmentParserTest extends AbstractCodeFragmentParserTest {
+  void test_arguments_arguments_arguments() {
+    var accessors = assertNoErrors('arguments[0].arguments[1].arguments[2]');
+    expect(accessors, hasLength(3));
+  }
+
+  void test_arguments_named() {
+    var accessors = assertNoErrors('arguments[foo]');
+    expect(accessors, hasLength(1));
+  }
+
+  void test_arguments_positional() {
+    var accessors = assertNoErrors('arguments[0]');
+    expect(accessors, hasLength(1));
+  }
+
+  void test_arguments_typeArguments() {
+    var accessors = assertNoErrors('arguments[0].typeArguments[0]');
+    expect(accessors, hasLength(2));
+  }
+
+  void test_typeArguments() {
+    var accessors = assertNoErrors('typeArguments[0]');
+    expect(accessors, hasLength(1));
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_character_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_character_test.dart
new file mode 100644
index 0000000..ab3ece6
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/invalid_character_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2020, 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/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../code_fragment_parser_test.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InvalidCharacterTest);
+  });
+}
+
+@reflectiveTest
+class InvalidCharacterTest extends AbstractCodeFragmentParserTest {
+  void test_final() {
+    assertErrors('arguments;', [
+      error(TransformSetErrorCode.invalidCharacter, 9, 1),
+    ]);
+  }
+
+  void test_initial() {
+    assertErrors('{ some', [
+      error(TransformSetErrorCode.invalidCharacter, 0, 1),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_token_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_token_test.dart
new file mode 100644
index 0000000..ec8ac42
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_token_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2020, 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/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../code_fragment_parser_test.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MissingTokenTest);
+  });
+}
+
+@reflectiveTest
+class MissingTokenTest extends AbstractCodeFragmentParserTest {
+  void test_closeBracket() {
+    assertErrors('arguments[2', [
+      error(TransformSetErrorCode.missingToken, 10, 1),
+    ]);
+  }
+
+  void test_identifier_afterPeriod() {
+    assertErrors('arguments[2].', [
+      error(TransformSetErrorCode.missingToken, 12, 1),
+    ]);
+  }
+
+  void test_identifier_initial() {
+    assertErrors('', [
+      error(TransformSetErrorCode.missingToken, 0, 0),
+    ]);
+  }
+
+  void test_index() {
+    assertErrors('arguments[', [
+      error(TransformSetErrorCode.missingToken, 9, 1),
+    ]);
+  }
+
+  void test_openBracket() {
+    assertErrors('arguments', [
+      error(TransformSetErrorCode.missingToken, 0, 9),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
index e8bbf94..d8b87c6 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
@@ -4,22 +4,30 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'invalid_character_test.dart' as invalid_character;
 import 'invalid_value_one_of_test.dart' as invalid_value_one_of;
 import 'invalid_value_test.dart' as invalid_value;
 import 'missing_key_test.dart' as missing_key;
 import 'missing_template_end_test.dart' as missing_template_end;
+import 'missing_token_test.dart' as missing_token;
 import 'undefined_variable_test.dart' as undefined_variable;
+import 'unknown_accessor_test.dart' as unknown_accessor;
 import 'unsupported_key_test.dart' as unsupported_key;
+import 'wrong_token_test.dart' as wrong_token;
 import 'yaml_syntax_error_test.dart' as yaml_syntax_error;
 
 void main() {
   defineReflectiveSuite(() {
+    invalid_character.main();
     invalid_value_one_of.main();
     invalid_value.main();
     missing_key.main();
     missing_template_end.main();
+    missing_token.main();
     undefined_variable.main();
+    unknown_accessor.main();
     unsupported_key.main();
+    wrong_token.main();
     yaml_syntax_error.main();
   });
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/undefined_variable_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/undefined_variable_test.dart
index 19334c8..db854a5 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/undefined_variable_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/undefined_variable_test.dart
@@ -33,8 +33,8 @@
         expression: '{%xyz%}'
         variables:
           zyx:
-            kind: 'argument'
-            index: 0
+            kind: 'fragment'
+            value: 'arguments[0]'
 ''', [
       error(TransformSetErrorCode.undefinedVariable, 253, 3),
     ]);
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unknown_accessor_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unknown_accessor_test.dart
new file mode 100644
index 0000000..205ad42
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unknown_accessor_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2020, 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/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../code_fragment_parser_test.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UnknownAccessorTest);
+  });
+}
+
+@reflectiveTest
+class UnknownAccessorTest extends AbstractCodeFragmentParserTest {
+  void test_afterPeriod() {
+    assertErrors('arguments[0].argument[1]', [
+      error(TransformSetErrorCode.unknownAccessor, 13, 8),
+    ]);
+  }
+
+  void test_initial() {
+    assertErrors('argument[0]', [
+      error(TransformSetErrorCode.unknownAccessor, 0, 8),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/wrong_token_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/wrong_token_test.dart
new file mode 100644
index 0000000..a047759
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/wrong_token_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2020, 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/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../code_fragment_parser_test.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MissingTokenTest);
+  });
+}
+
+@reflectiveTest
+class MissingTokenTest extends AbstractCodeFragmentParserTest {
+  void test_closeBracket() {
+    assertErrors('arguments[2 3', [
+      error(TransformSetErrorCode.wrongToken, 12, 1),
+    ]);
+  }
+
+  void test_identifier_afterPeriod() {
+    assertErrors('arguments[2].1', [
+      error(TransformSetErrorCode.wrongToken, 13, 1),
+    ]);
+  }
+
+  void test_identifier_initial() {
+    assertErrors('1', [
+      error(TransformSetErrorCode.wrongToken, 0, 1),
+    ]);
+  }
+
+  void test_index() {
+    assertErrors('arguments[.', [
+      error(TransformSetErrorCode.wrongToken, 10, 1),
+    ]);
+  }
+
+  void test_openBracket() {
+    assertErrors('arguments.', [
+      error(TransformSetErrorCode.wrongToken, 9, 1),
+    ]);
+  }
+
+  void test_period() {
+    assertErrors('arguments[2] typeArguments', [
+      error(TransformSetErrorCode.wrongToken, 13, 13),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/end_to_end_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/end_to_end_test.dart
index aad57fa..df98271 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/end_to_end_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/end_to_end_test.dart
@@ -38,8 +38,8 @@
         expression: '{% y %}'
         variables:
           y:
-            kind: 'argument'
-            index: 0
+            kind: 'fragment'
+            value: 'arguments[0]'
 ''');
     await resolveTestUnit('''
 import '$importUri';
@@ -81,8 +81,8 @@
         expression: '{% t %}'
         variables:
           t:
-            kind: 'argument'
-            index: 0
+            kind: 'fragment'
+            value: 'arguments[0]'
 ''');
     await resolveTestUnit('''
 import '$importUri';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
index c26ea18..074330b 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
@@ -847,8 +847,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
@@ -894,8 +894,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
@@ -943,8 +943,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
@@ -990,8 +990,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
@@ -1111,8 +1111,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
@@ -1158,8 +1158,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
@@ -1207,8 +1207,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
@@ -1254,8 +1254,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
@@ -1303,8 +1303,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
@@ -1349,8 +1349,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
@@ -1470,8 +1470,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
@@ -1517,8 +1517,8 @@
           expression: '{% type %}'
           variables:
             type:
-              kind: 'argument'
-              index: 0
+              kind: 'fragment'
+              value: 'arguments[0]'
       - kind: 'removeParameter'
         index: 0
 ''');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
index 5f2419e..28ee44c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
@@ -5,6 +5,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'add_type_parameter_test.dart' as add_type_parameter_change;
+import 'code_fragment_parser_test.dart' as code_fragment_parser;
 import 'code_template_test.dart' as code_template;
 import 'diagnostics/test_all.dart' as diagnostics;
 import 'end_to_end_test.dart' as end_to_end;
@@ -17,6 +18,7 @@
 void main() {
   defineReflectiveSuite(() {
     add_type_parameter_change.main();
+    code_fragment_parser.main();
     code_template.main();
     diagnostics.main();
     end_to_end.main();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
index 0e526cb..e28220e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
@@ -46,8 +46,8 @@
         expression: '{% p %}'
         variables:
           p:
-            kind: 'argument'
-            index: 1
+            kind: 'fragment'
+            value: 'arguments[1]'
 ''');
     var transforms = _transforms('f');
     expect(transforms, hasLength(1));
@@ -117,8 +117,8 @@
         expression: '{% p %}'
         variables:
           p:
-            kind: 'argument'
-            index: 1
+            kind: 'fragment'
+            value: 'arguments[1]'
 ''');
     var transforms = _transforms('f');
     expect(transforms, hasLength(1));
@@ -158,8 +158,8 @@
         expression: '{% p %}'
         variables:
           p:
-            kind: 'argument'
-            index: 1
+            kind: 'fragment'
+            value: 'arguments[1]'
 ''');
     var transforms = _transforms('f');
     expect(transforms, hasLength(1));
@@ -199,11 +199,11 @@
         expression: '{% a %}({% b %})'
         variables:
           a:
-            kind: 'argument'
-            index: 1
+            kind: 'fragment'
+            value: 'arguments[1]'
           b:
-            kind: 'argument'
-            index: 2
+            kind: 'fragment'
+            value: 'arguments[2]'
 ''');
     var transforms = _transforms('f');
     expect(transforms, hasLength(1));
@@ -285,8 +285,8 @@
         expression: '{% t %}'
         variables:
           t:
-            kind: 'argument'
-            name: 'p'
+            kind: 'fragment'
+            value: 'arguments[p]'
 ''');
     var transforms = _transforms('A');
     expect(transforms, hasLength(1));
@@ -325,8 +325,8 @@
         expression: '{% t %}'
         variables:
           t:
-            kind: 'argument'
-            index: 2
+            kind: 'fragment'
+            value: 'arguments[2]'
 ''');
     var transforms = _transforms('A');
     expect(transforms, hasLength(1));
diff --git a/tools/VERSION b/tools/VERSION
index 392009d..958db32 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 11
 PATCH 0
-PRERELEASE 267
+PRERELEASE 268
 PRERELEASE_PATCH 0
\ No newline at end of file