Compute unlinked API signatures without unlinked summaries.

R=brianwilkerson@google.com, paulberry@google.com

Change-Id: I21c87f60d88716eb9c6b1d5e558bb17156daa598
Reviewed-on: https://dart-review.googlesource.com/74925
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 278996c..c032de3 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -92,7 +92,7 @@
   /**
    * The version of data format, should be incremented on every format change.
    */
-  static const int DATA_VERSION = 65;
+  static const int DATA_VERSION = 66;
 
   /**
    * The number of exception contexts allowed to write. Once this field is
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index 8e90b2d..8264349 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/src/dart/analysis/one_phase_summaries_selector.dart';
 import 'package:analyzer/src/dart/analysis/referenced_names.dart';
 import 'package:analyzer/src/dart/analysis/top_level_declaration.dart';
+import 'package:analyzer/src/dart/analysis/unlinked_api_signature.dart';
 import 'package:analyzer/src/dart/scanner/reader.dart';
 import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -126,7 +127,6 @@
   Set<String> _definedTopLevelNames;
   Set<String> _referencedNames;
   Set<String> _subtypedNames;
-  String _unlinkedKey;
   AnalysisDriverUnlinkedUnit _driverUnlinkedUnit;
   UnlinkedUnit _unlinked;
   List<int> _apiSignature;
@@ -419,27 +419,38 @@
       _contentHash = rawFileState.contentHash;
     }
 
-    // Prepare the unlinked bundle key.
+    // Prepare keys of unlinked data.
+    String apiSignatureKey;
+    String unlinkedKey;
     {
-      ApiSignature signature = new ApiSignature();
+      var signature = new ApiSignature();
       signature.addUint32List(_fsState._salt);
       signature.addString(_contentHash);
-      _unlinkedKey = '${signature.toHex()}.unlinked';
+
+      var signatureHex = signature.toHex();
+      apiSignatureKey = '$signatureHex.api_signature';
+      unlinkedKey = '$signatureHex.unlinked';
     }
 
-    // Prepare bytes of the unlinked bundle - existing or new.
-    List<int> bytes;
-    {
-      bytes = _fsState._byteStore.get(_unlinkedKey);
-      if (bytes == null || bytes.isEmpty) {
-        CompilationUnit unit = parse();
-        _fsState._logger.run('Create unlinked for $path', () {
-          UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit,
+    // Try to get bytes of unlinked data.
+    var apiSignatureBytes = _fsState._byteStore.get(apiSignatureKey);
+    var unlinkedUnitBytes = _fsState._byteStore.get(unlinkedKey);
+
+    // Compute unlinked data that we are missing.
+    if (apiSignatureBytes == null || unlinkedUnitBytes == null) {
+      CompilationUnit unit = parse(AnalysisErrorListener.NULL_LISTENER);
+      _fsState._logger.run('Create unlinked for $path', () {
+        if (apiSignatureBytes == null) {
+          apiSignatureBytes = computeUnlinkedApiSignature(unit);
+          _fsState._byteStore.put(apiSignatureKey, apiSignatureBytes);
+        }
+        if (unlinkedUnitBytes == null) {
+          var unlinkedUnit = serializeAstUnlinked(unit,
               serializeInferrableFields: !enableOnePhaseSummaries);
-          DefinedNames definedNames = computeDefinedNames(unit);
-          List<String> referencedNames = computeReferencedNames(unit).toList();
-          List<String> subtypedNames = computeSubtypedNames(unit).toList();
-          bytes = new AnalysisDriverUnlinkedUnitBuilder(
+          var definedNames = computeDefinedNames(unit);
+          var referencedNames = computeReferencedNames(unit).toList();
+          var subtypedNames = computeSubtypedNames(unit).toList();
+          unlinkedUnitBytes = new AnalysisDriverUnlinkedUnitBuilder(
                   unit: unlinkedUnit,
                   definedTopLevelNames: definedNames.topLevelNames.toList(),
                   definedClassMemberNames:
@@ -447,13 +458,14 @@
                   referencedNames: referencedNames,
                   subtypedNames: subtypedNames)
               .toBuffer();
-          _fsState._byteStore.put(_unlinkedKey, bytes);
-        });
-      }
+          _fsState._byteStore.put(unlinkedKey, unlinkedUnitBytes);
+        }
+      });
     }
 
     // Read the unlinked bundle.
-    _driverUnlinkedUnit = new AnalysisDriverUnlinkedUnit.fromBuffer(bytes);
+    _driverUnlinkedUnit =
+        new AnalysisDriverUnlinkedUnit.fromBuffer(unlinkedUnitBytes);
     _unlinked = _driverUnlinkedUnit.unit;
     _lineInfo = new LineInfo(_unlinked.lineStarts);
 
@@ -465,10 +477,9 @@
     _topLevelDeclarations = null;
 
     // Prepare API signature.
-    List<int> newApiSignature = new Uint8List.fromList(_unlinked.apiSignature);
     bool apiSignatureChanged = _apiSignature != null &&
-        !_equalByteLists(_apiSignature, newApiSignature);
-    _apiSignature = newApiSignature;
+        !_equalByteLists(_apiSignature, apiSignatureBytes);
+    _apiSignature = apiSignatureBytes;
 
     // The API signature changed.
     //   Flush transitive signatures of affected files.
@@ -684,8 +695,6 @@
   final FileState file;
 
   FileStateTestView(this.file);
-
-  String get unlinkedKey => file._unlinkedKey;
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart b/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart
new file mode 100644
index 0000000..e9b3c93
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2018, 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/summary/api_signature.dart';
+
+/// Return the bytes of the unlinked API signature of the given [unit].
+///
+/// If API signatures of two units are different, they may have different APIs.
+List<int> computeUnlinkedApiSignature(CompilationUnit unit) {
+  var computer = new _UnitApiSignatureComputer();
+  computer.compute(unit);
+  return computer.signature.toByteList();
+}
+
+class _UnitApiSignatureComputer {
+  final signature = new ApiSignature();
+
+  void addClassOrMixin(ClassOrMixinDeclaration node) {
+    addTokens(node.beginToken, node.leftBracket);
+
+    bool hasConstConstructor = node.members
+        .any((m) => m is ConstructorDeclaration && m.constKeyword != null);
+
+    signature.addInt(node.members.length);
+    for (var member in node.members) {
+      if (member is ConstructorDeclaration) {
+        var lastInitializer = member.constKeyword != null &&
+                member.initializers != null &&
+                member.initializers.isNotEmpty
+            ? member.initializers.last
+            : null;
+        addTokens(
+          member.beginToken,
+          (lastInitializer ?? member.parameters ?? member.name).endToken,
+        );
+      } else if (member is FieldDeclaration) {
+        addVariables(member, member.fields, hasConstConstructor);
+      } else if (member is MethodDeclaration) {
+        addTokens(
+          member.beginToken,
+          (member.parameters ?? member.name).endToken,
+        );
+      } else {
+        addNode(member);
+      }
+    }
+
+    addToken(node.rightBracket);
+  }
+
+  void addNode(AstNode node) {
+    addTokens(node.beginToken, node.endToken);
+  }
+
+  void addToken(Token token) {
+    signature.addString(token.lexeme);
+  }
+
+  /// Appends tokens from [begin] (including), to [end] (also including).
+  void addTokens(Token begin, Token end) {
+    if (begin is CommentToken) {
+      begin = (begin as CommentToken).parent;
+    }
+    Token token = begin;
+    while (token != null) {
+      addToken(token);
+      if (token == end) {
+        break;
+      }
+      token = token.next;
+    }
+  }
+
+  void addVariables(
+    AstNode node,
+    VariableDeclarationList variableList,
+    bool includeFinalInitializers,
+  ) {
+    if (variableList.type == null ||
+        variableList.isConst ||
+        variableList.isFinal && includeFinalInitializers) {
+      addTokens(node.beginToken, node.endToken);
+    } else {
+      addTokens(node.beginToken, variableList.type.endToken);
+
+      signature.addInt(variableList.variables.length);
+      for (var variable in variableList.variables) {
+        addTokens(variable.beginToken, variable.name.endToken);
+        addToken(variable.endToken.next); // `,` or `;`
+      }
+    }
+  }
+
+  void compute(CompilationUnit unit) {
+    signature.addInt(unit.directives.length);
+    unit.directives.forEach(addNode);
+
+    signature.addInt(unit.declarations.length);
+    for (var declaration in unit.declarations) {
+      if (declaration is ClassOrMixinDeclaration) {
+        addClassOrMixin(declaration);
+      } else if (declaration is FunctionDeclaration) {
+        var parameters = declaration.functionExpression.parameters;
+        addTokens(
+          declaration.beginToken,
+          (parameters ?? declaration.name).endToken,
+        );
+      } else if (declaration is TopLevelVariableDeclaration) {
+        addVariables(declaration, declaration.variables, false);
+      } else {
+        addNode(declaration);
+      }
+    }
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index 6ec4d00..f83688a 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -654,22 +654,6 @@
     expect(file.apiSignature, signature);
   }
 
-  test_store_zeroLengthUnlinked() {
-    String path = _p('/test.dart');
-    provider.newFile(path, 'class A {}');
-
-    // Get the file, prepare unlinked.
-    FileState file = fileSystemState.getFileForPath(path);
-    expect(file.unlinked, isNotNull);
-
-    // Make the unlinked unit in the byte store zero-length, damaged.
-    byteStore.put(file.test.unlinkedKey, <int>[]);
-
-    // Refresh should not fail, zero bytes in the store are ignored.
-    file.refresh();
-    expect(file.unlinked, isNotNull);
-  }
-
   test_subtypedNames() {
     String path = _p('/test.dart');
     provider.newFile(path, r'''
diff --git a/pkg/analyzer/test/src/dart/analysis/test_all.dart b/pkg/analyzer/test/src/dart/analysis/test_all.dart
index 7c74b6b..f4f9c49 100644
--- a/pkg/analyzer/test/src/dart/analysis/test_all.dart
+++ b/pkg/analyzer/test/src/dart/analysis/test_all.dart
@@ -18,6 +18,7 @@
 import 'search_test.dart' as search;
 import 'session_helper_test.dart' as session_helper;
 import 'session_test.dart' as session;
+import 'unlinked_api_signature_test.dart' as unlinked_api_signature;
 import 'uri_converter_test.dart' as uri_converter;
 
 main() {
@@ -36,6 +37,7 @@
     search.main();
     session_helper.main();
     session.main();
+    unlinked_api_signature.main();
     uri_converter.main();
   }, name: 'analysis');
 }
diff --git a/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart b/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart
new file mode 100644
index 0000000..0686064
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart
@@ -0,0 +1,832 @@
+// Copyright (c) 2018, 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 'dart:typed_data';
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/file_system/file_system.dart';
+import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/source/package_map_resolver.dart';
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:front_end/src/api_prototype/byte_store.dart';
+import 'package:front_end/src/base/performance_logger.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../context/mock_sdk.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UnitApiSignatureTest);
+  });
+}
+
+@reflectiveTest
+class UnitApiSignatureTest extends Object with ResourceProviderMixin {
+  FileSystemState fileSystemState;
+
+  Future<Null> assertNotSameSignature(String oldCode, String newCode) async {
+    assertSignature(oldCode, newCode, same: false);
+  }
+
+  Future<Null> assertSameSignature(String oldCode, String newCode) async {
+    assertSignature(oldCode, newCode, same: true);
+  }
+
+  Future<Null> assertSignature(String oldCode, String newCode,
+      {bool same}) async {
+    var path = convertPath('/test.dart');
+
+    newFile(path, content: oldCode);
+    var file = fileSystemState.getFileForPath(path);
+    var lastSignature = file.apiSignature;
+
+    newFile(path, content: newCode);
+    await file.refresh();
+
+    var newSignature = file.apiSignature;
+    if (same) {
+      expect(newSignature, lastSignature);
+    } else {
+      expect(newSignature, isNot(lastSignature));
+    }
+  }
+
+  void setUp() {
+    var sdk = new MockSdk(resourceProvider: resourceProvider);
+    var sourceFactory = new SourceFactory([
+      new DartUriResolver(sdk),
+      new PackageMapUriResolver(resourceProvider, <String, List<Folder>>{
+        'aaa': [getFolder('/aaa/lib')],
+        'bbb': [getFolder('/bbb/lib')],
+      }),
+      new ResourceUriResolver(resourceProvider)
+    ], null, resourceProvider);
+    fileSystemState = new FileSystemState(
+        new PerformanceLog(new StringBuffer()),
+        new MemoryByteStore(),
+        new FileContentOverlay(),
+        resourceProvider,
+        sourceFactory,
+        new AnalysisOptionsImpl(),
+        new Uint32List(0));
+  }
+
+  test_class_annotation() async {
+    await assertNotSameSignature(r'''
+const a = 0;
+
+class C {}
+''', r'''
+const a = 0;
+
+@a
+class C {}
+''');
+  }
+
+  test_class_constructor_block_to_empty() async {
+    await assertSameSignature(r'''
+class C {
+  C() {
+    var v = 1;
+  }
+}
+''', r'''
+class C {
+  C();
+}
+''');
+  }
+
+  test_class_constructor_body() async {
+    await assertSameSignature(r'''
+class C {
+  C() {
+    var v = 1;
+  }
+}
+''', r'''
+class C {
+  C() {
+    var v = 2;
+  }
+}
+''');
+  }
+
+  test_class_constructor_empty_to_block() async {
+    await assertSameSignature(r'''
+class C {
+  C();
+}
+''', r'''
+class C {
+  C() {
+    var v = 1;
+  }
+}
+''');
+  }
+
+  test_class_constructor_initializer_const() async {
+    await assertNotSameSignature(r'''
+class C {
+  final int f;
+  const C() : f = 1;
+}
+''', r'''
+class C {
+  final int f;
+  const C() : f = 2;
+}
+''');
+  }
+
+  test_class_constructor_initializer_empty() async {
+    await assertSameSignature(r'''
+class C {
+  C.foo() : ;
+}
+''', r'''
+class C {
+  C.foo() : f;
+}
+''');
+  }
+
+  test_class_constructor_initializer_notConst() async {
+    await assertSameSignature(r'''
+class C {
+  final int f;
+  C.foo() : f = 1;
+  const C.bar();
+}
+''', r'''
+class C {
+  final int f;
+  C.foo() : f = 2;
+  const C.bar();
+}
+''');
+  }
+
+  test_class_constructor_parameters_add() async {
+    await assertNotSameSignature(r'''
+class C {
+  C(int a);
+}
+''', r'''
+class C {
+  C(int a, int b);
+}
+''');
+  }
+
+  test_class_constructor_parameters_remove() async {
+    await assertNotSameSignature(r'''
+class C {
+  C(int a, int b);
+}
+''', r'''
+class C {
+  C(int a);
+}
+''');
+  }
+
+  test_class_constructor_parameters_rename() async {
+    await assertNotSameSignature(r'''
+class C {
+  C(int a);
+}
+''', r'''
+class C {
+  C(int b);
+}
+''');
+  }
+
+  test_class_constructor_parameters_type() async {
+    await assertNotSameSignature(r'''
+class C {
+  C(int p);
+}
+''', r'''
+class C {
+  C(double p);
+}
+''');
+  }
+
+  test_class_extends() async {
+    await assertNotSameSignature(r'''
+class A {}
+class B {}
+''', r'''
+class A {}
+class B extends A {}
+''');
+  }
+
+  test_class_field_withoutType() async {
+    await assertNotSameSignature(r'''
+class C {
+  var a = 1;
+}
+''', r'''
+class C {
+  var a = 2;
+}
+''');
+  }
+
+  test_class_field_withoutType2() async {
+    await assertNotSameSignature(r'''
+class C {
+  var a = 1, b = 2, c, d = 4;
+}
+''', r'''
+class C {
+  var a = 1, b, c = 3, d = 4;
+}
+''');
+  }
+
+  test_class_field_withType() async {
+    await assertSameSignature(r'''
+class C {
+  int a = 1, b, c = 3;
+}
+''', r'''
+class C {
+  int a = 0, b = 2, c;
+}
+''');
+  }
+
+  test_class_field_withType_const() async {
+    await assertNotSameSignature(r'''
+class C {
+  static const int a = 1;
+}
+''', r'''
+class C {
+  static const int a = 2;
+}
+''');
+  }
+
+  test_class_field_withType_final_hasConstConstructor() async {
+    await assertNotSameSignature(r'''
+class C {
+  final int a = 1;
+  const C();
+}
+''', r'''
+class C {
+  final int a = 2;
+  const C();
+}
+''');
+  }
+
+  test_class_field_withType_final_noConstConstructor() async {
+    await assertSameSignature(r'''
+class C {
+  final int a = 1;
+}
+''', r'''
+class C {
+  final int a = 2;
+}
+''');
+  }
+
+  test_class_implements() async {
+    await assertNotSameSignature(r'''
+class A {}
+class B {}
+''', r'''
+class A {}
+class B implements A {}
+''');
+  }
+
+  test_class_method_annotation() async {
+    await assertNotSameSignature(r'''
+const a = 0;
+
+class C {
+  void foo() {}
+}
+''', r'''
+const a = 0;
+
+class C {
+  @a
+  void foo() {}
+}
+''');
+  }
+
+  test_class_method_body_async_to_sync() async {
+    await assertSameSignature(r'''
+class C {
+  Future foo() async {}
+}
+''', r'''
+class C {
+  Future foo() {}
+}
+''');
+  }
+
+  test_class_method_body_block() async {
+    await assertSameSignature(r'''
+class C {
+  int foo() {
+    return 1;
+  }
+}
+''', r'''
+class C {
+  int foo() {
+    return 2;
+  }
+}
+''');
+  }
+
+  test_class_method_body_block_to_expression() async {
+    await assertSameSignature(r'''
+class C {
+  int foo() {
+    return 1;
+  }
+}
+''', r'''
+class C {
+  int foo() => 2;
+}
+''');
+  }
+
+  test_class_method_body_empty_to_block() async {
+    await assertSameSignature(r'''
+class C {
+  int foo();
+}
+''', r'''
+class C {
+  int foo() {
+    var v = 0;
+  }
+}
+''');
+  }
+
+  test_class_method_body_expression() async {
+    await assertSameSignature(r'''
+class C {
+  int foo() => 1;
+}
+''', r'''
+class C {
+  int foo() => 2;
+}
+''');
+  }
+
+  test_class_method_body_sync_to_async() async {
+    await assertSameSignature(r'''
+class C {
+  Future foo() {}
+}
+''', r'''
+class C {
+  Future foo() async {}
+}
+''');
+  }
+
+  test_class_method_getter_body_block_to_expression() async {
+    await assertSameSignature(r'''
+class C {
+  int get foo {
+    return 1;
+  }
+}
+''', r'''
+class C {
+  int get foo => 2;
+}
+''');
+  }
+
+  test_class_method_getter_body_empty_to_expression() async {
+    await assertSameSignature(r'''
+class C {
+  int get foo;
+}
+''', r'''
+class C {
+  int get foo => 2;
+}
+''');
+  }
+
+  test_class_method_parameters_add() async {
+    await assertNotSameSignature(r'''
+class C {
+  foo(int a) {}
+}
+''', r'''
+class C {
+  foo(int a, int b) {}
+}
+''');
+  }
+
+  test_class_method_parameters_remove() async {
+    await assertNotSameSignature(r'''
+class C {
+  foo(int a, int b) {}
+}
+''', r'''
+class C {
+  foo(int a) {}
+}
+''');
+  }
+
+  test_class_method_parameters_rename() async {
+    await assertNotSameSignature(r'''
+class C {
+  void foo(int a) {}
+}
+''', r'''
+class C {
+  void foo(int b) {}
+}
+''');
+  }
+
+  test_class_method_parameters_type() async {
+    await assertNotSameSignature(r'''
+class C {
+  void foo(int p) {}
+}
+''', r'''
+class C {
+  void foo(double p) {}
+}
+''');
+  }
+
+  test_class_method_returnType() async {
+    await assertNotSameSignature(r'''
+class C {
+  int foo() => 0;
+}
+''', r'''
+class C {
+  num foo() => 0;
+}
+''');
+  }
+
+  test_class_method_typeParameters_add() async {
+    await assertNotSameSignature(r'''
+class C {
+  void foo() {}
+}
+''', r'''
+class C {
+  void foo<T>() {}
+}
+''');
+  }
+
+  test_class_method_typeParameters_remove() async {
+    await assertNotSameSignature(r'''
+class C {
+  void foo<T>() {}
+}
+''', r'''
+class C {
+  void foo() {}
+}
+''');
+  }
+
+  test_class_method_typeParameters_rename() async {
+    await assertNotSameSignature(r'''
+class C {
+  void foo<T>() {}
+}
+''', r'''
+class C {
+  void foo<U>() {}
+}
+''');
+  }
+
+  test_class_modifier() async {
+    await assertNotSameSignature(r'''
+class C {}
+''', r'''
+abstract class C {}
+''');
+  }
+
+  test_class_with() async {
+    await assertNotSameSignature(r'''
+class A {}
+class B {}
+class C extends A {}
+''', r'''
+class A {}
+class B {}
+class C extends A with B {}
+''');
+  }
+
+  test_commentAdd() async {
+    await assertSameSignature(r'''
+var a = 1;
+var b = 2;
+var c = 3;
+''', r'''
+var a = 1; // comment
+
+/// comment 1
+/// comment 2
+var b = 2;
+
+/**
+ *  Comment
+ */
+var c = 3;
+''');
+  }
+
+  test_commentRemove() async {
+    await assertSameSignature(r'''
+var a = 1; // comment
+
+/// comment 1
+/// comment 2
+var b = 2;
+
+/**
+ *  Comment
+ */
+var c = 3;
+''', r'''
+var a = 1;
+var b = 2;
+var c = 3;
+''');
+  }
+
+  test_function_annotation() async {
+    await assertNotSameSignature(r'''
+const a = 0;
+
+void foo() {}
+''', r'''
+const a = 0;
+
+@a
+void foo() {}
+''');
+  }
+
+  test_function_body_async_to_sync() async {
+    await assertSameSignature(r'''
+Future foo() async {}
+''', r'''
+Future foo() {}
+''');
+  }
+
+  test_function_body_block() async {
+    await assertSameSignature(r'''
+int foo() {
+  return 1;
+}
+''', r'''
+int foo() {
+  return 2;
+}
+''');
+  }
+
+  test_function_body_block_to_expression() async {
+    await assertSameSignature(r'''
+int foo() {
+  return 1;
+}
+''', r'''
+int foo() => 2;
+''');
+  }
+
+  test_function_body_expression() async {
+    await assertSameSignature(r'''
+int foo() => 1;
+''', r'''
+int foo() => 2;
+''');
+  }
+
+  test_function_body_sync_to_async() async {
+    await assertSameSignature(r'''
+Future foo() {}
+''', r'''
+Future foo() async {}
+''');
+  }
+
+  test_function_getter_block_to_expression() async {
+    await assertSameSignature(r'''
+int get foo {
+  return 1;
+}
+''', r'''
+int get foo => 2;
+''');
+  }
+
+  test_function_parameters_rename() async {
+    await assertNotSameSignature(r'''
+void foo(int a) {}
+''', r'''
+void foo(int b) {}
+''');
+  }
+
+  test_function_parameters_type() async {
+    await assertNotSameSignature(r'''
+void foo(int p) {}
+''', r'''
+void foo(double p) {}
+''');
+  }
+
+  test_function_returnType() async {
+    await assertNotSameSignature(r'''
+int foo() => 0;
+''', r'''
+num foo() => 0;
+''');
+  }
+
+  test_function_typeParameters_add() async {
+    await assertNotSameSignature(r'''
+void foo() {}
+''', r'''
+void foo<T>() {}
+''');
+  }
+
+  test_function_typeParameters_remove() async {
+    await assertNotSameSignature(r'''
+void foo<T>() {}
+''', r'''
+void foo() {}
+''');
+  }
+
+  test_function_typeParameters_rename() async {
+    await assertNotSameSignature(r'''
+void foo<T>() {}
+''', r'''
+void foo<U>() {}
+''');
+  }
+
+  test_mixin_field_withoutType() async {
+    await assertNotSameSignature(r'''
+mixin M {
+  var a = 1;
+}
+''', r'''
+mixin M {
+  var a = 2;
+}
+''');
+  }
+
+  test_mixin_field_withType() async {
+    await assertSameSignature(r'''
+mixin M {
+  int a = 1, b, c = 3;
+}
+''', r'''
+mixin M {
+  int a = 0, b = 2, c;
+}
+''');
+  }
+
+  test_mixin_implements() async {
+    await assertNotSameSignature(r'''
+class A {}
+mixin M {}
+''', r'''
+class A {}
+mixin M implements A {}
+''');
+  }
+
+  test_mixin_method_body_block() async {
+    await assertSameSignature(r'''
+mixin M {
+  int foo() {
+    return 1;
+  }
+}
+''', r'''
+mixin M {
+  int foo() {
+    return 2;
+  }
+}
+''');
+  }
+
+  test_mixin_method_body_expression() async {
+    await assertSameSignature(r'''
+mixin M {
+  int foo() => 1;
+}
+''', r'''
+mixin M {
+  int foo() => 2;
+}
+''');
+  }
+
+  test_mixin_on() async {
+    await assertNotSameSignature(r'''
+class A {}
+mixin M {}
+''', r'''
+class A {}
+mixin M on A {}
+''');
+  }
+
+  test_topLevelVariable_withoutType() async {
+    await assertNotSameSignature(r'''
+var a = 1;
+''', r'''
+var a = 2;
+''');
+  }
+
+  test_topLevelVariable_withoutType2() async {
+    await assertNotSameSignature(r'''
+var a = 1, b = 2, c, d = 4;;
+''', r'''
+var a = 1, b, c = 3, d = 4;;
+''');
+  }
+
+  test_topLevelVariable_withType() async {
+    await assertSameSignature(r'''
+int a = 1, b, c = 3;
+''', r'''
+int a = 0, b = 2, c;
+''');
+  }
+
+  test_topLevelVariable_withType_const() async {
+    await assertNotSameSignature(r'''
+const int a = 1;
+''', r'''
+const int a = 2;
+''');
+  }
+
+  test_topLevelVariable_withType_final() async {
+    await assertSameSignature(r'''
+final int a = 1;
+''', r'''
+final int a = 2;
+''');
+  }
+
+  test_typedef_generic_parameters_type() async {
+    await assertNotSameSignature(r'''
+typedef F = void Function(int);
+''', r'''
+typedef F = void Function(double);
+''');
+  }
+}