Version 2.17.0-199.0.dev

Merge commit 'e48e85c87ff0ad071417d4da9454c788532bb2bb' into 'dev'
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index cd882d6..0f02e2e 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -284,7 +284,6 @@
 
       // Figure out what to keep and what to throw away.
       Set<Uri?> invalidatedUris = this._invalidatedUris.toSet();
-      _invalidatePrecompiledMacros(c.options, invalidatedUris);
       _invalidateNotKeptUserBuilders(invalidatedUris);
       ReusageResult? reusedResult = _computeReusedLibraries(
           lastGoodKernelTarget,
@@ -311,6 +310,8 @@
       recorderForTesting?.recordRebuildBodiesCount(
           experimentalInvalidation?.missingSources.length ?? 0);
 
+      _invalidatePrecompiledMacros(c.options, reusedResult.notReusedLibraries);
+
       // Cleanup: After (potentially) removing builders we have stuff to cleanup
       // to not leak, and we might need to re-create the dill target.
       _cleanupRemovedBuilders(
@@ -1098,6 +1099,21 @@
     if (reusedResult.directlyInvalidated.isEmpty) return null;
     if (reusedResult.invalidatedBecauseOfPackageUpdate) return null;
 
+    if (enableMacros) {
+      /// TODO(johnniwinther): Add a [hasMacro] property to [LibraryBuilder].
+      for (LibraryBuilder builder in reusedResult.notReusedLibraries) {
+        Iterator<Builder> iterator = builder.iterator;
+        while (iterator.moveNext()) {
+          Builder childBuilder = iterator.current;
+          if (childBuilder is ClassBuilder && childBuilder.isMacro) {
+            // Changes to a library with macro classes can affect any class that
+            // depends on it.
+            return null;
+          }
+        }
+      }
+    }
+
     // Figure out if the file(s) have changed outline, or we can just
     // rebuild the bodies.
     for (LibraryBuilder builder in reusedResult.directlyInvalidated) {
@@ -1398,16 +1414,19 @@
     }
   }
 
-  void _invalidatePrecompiledMacros(
-      ProcessedOptions processedOptions, Set<Uri?> invalidatedUris) {
-    if (invalidatedUris.isEmpty) {
+  /// Removes the precompiled macros whose libraries cannot be reused.
+  void _invalidatePrecompiledMacros(ProcessedOptions processedOptions,
+      Set<LibraryBuilder> notReusedLibraries) {
+    if (notReusedLibraries.isEmpty) {
       return;
     }
     CompilerOptions compilerOptions = processedOptions.rawOptionsForTesting;
     Map<Uri, Uri>? precompiledMacroUris = compilerOptions.precompiledMacroUris;
     if (precompiledMacroUris != null) {
+      Set<Uri> importUris =
+          notReusedLibraries.map((library) => library.importUri).toSet();
       for (Uri macroLibraryUri in precompiledMacroUris.keys.toList()) {
-        if (invalidatedUris.contains(macroLibraryUri)) {
+        if (importUris.contains(macroLibraryUri)) {
           precompiledMacroUris.remove(macroLibraryUri);
         }
       }
diff --git a/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro.0.dart b/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro.0.dart
index 73a3a2d..a65202e 100644
--- a/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro.0.dart
+++ b/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro.0.dart
@@ -4,6 +4,7 @@
 
 import 'dart:async';
 import 'package:_fe_analyzer_shared/src/macros/api.dart';
+import 'macro_dependency.dart';
 
 macro
 
diff --git a/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro.1.dart b/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro.1.dart
index 0129964..5cfce9f 100644
--- a/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro.1.dart
+++ b/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro.1.dart
@@ -4,6 +4,7 @@
 
 import 'dart:async';
 import 'package:_fe_analyzer_shared/src/macros/api.dart';
+import 'macro_dependency.dart';
 
 macro
 
@@ -13,8 +14,6 @@
   @override
   FutureOr<void> buildDeclarationsForClass(ClassDeclaration clazz,
       ClassMemberDeclarationBuilder builder) async {
-    builder.declareInClass(new DeclarationCode.fromString('''
-  void method() {}
-'''));
+    builder.declareInClass(new DeclarationCode.fromString(generateBody()));
   }
 }
diff --git a/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro_dependency.0.dart b/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro_dependency.0.dart
new file mode 100644
index 0000000..2e1634f
--- /dev/null
+++ b/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro_dependency.0.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2022, 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.
+
+String generateBody() {
+  return '''
+  void method() {}
+''';
+}
diff --git a/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro_dependency.2.dart b/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro_dependency.2.dart
new file mode 100644
index 0000000..6861d3d
--- /dev/null
+++ b/pkg/front_end/test/macros/incremental/data/tests/user_macro/macro_dependency.2.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, 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.
+
+String generateBody() {
+  return '''
+  void method() {
+    print('method');
+  }
+''';
+}
diff --git a/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.0.dart b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.0.dart
index 9e7e582..26d9e54 100644
--- a/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.0.dart
+++ b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.0.dart
@@ -3,6 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'macro.dart';
+import 'main_lib.dart';
 
 @MethodMacro()
-class Class {}
+class Class {
+  void existingMethod() {
+    existingMethodDependency();
+  }
+}
diff --git a/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.0.dart.expect b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.0.dart.expect
index 3b13cdd..977e49e 100644
--- a/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.0.dart.expect
+++ b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.0.dart.expect
@@ -2,23 +2,34 @@
 import self as self;
 import "macro.dart" as mac;
 import "dart:core" as core;
+import "main_lib.dart" as mai;
 
 import "org-dartlang-test:///a/b/c/user_macro/macro.dart";
+import "org-dartlang-test:///a/b/c/user_macro/main_lib.dart";
 
 @#C1
 class Class extends core::Object {
   synthetic constructor •() → self::Class
     : super core::Object::•()
     ;
+  method existingMethod() → void {
+    mai::existingMethodDependency();
+  }
 }
 
 library /*isNonNullableByDefault*/;
+import self as mai;
+
+static method existingMethodDependency() → void {}
+
+library /*isNonNullableByDefault*/;
 import self as mac;
 import "dart:core" as core;
 import "package:_fe_analyzer_shared/src/macros/api.dart" as api;
 
 import "dart:async";
 import "package:_fe_analyzer_shared/src/macros/api.dart";
+import "org-dartlang-test:///a/b/c/user_macro/macro_dependency.dart";
 
 macro class MethodMacro extends core::Object implements api::ClassDeclarationsMacro /*hasConstConstructor*/  {
   const constructor •() → mac::MethodMacro
@@ -28,6 +39,14 @@
   method buildDeclarationsForClass(api::ClassDeclaration clazz, api::ClassMemberDeclarationBuilder builder) → FutureOr<void> async {}
 }
 
+library /*isNonNullableByDefault*/;
+import self as self2;
+import "dart:core" as core;
+
+static method generateBody() → core::String {
+  return "  void method() {}\n";
+}
+
 constants  {
   #C1 = mac::MethodMacro {}
   #C2 = dart.core::_Override {}
diff --git a/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.1.dart.expect b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.1.dart.expect
index 9a9c376..88b94c0 100644
--- a/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.1.dart.expect
+++ b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.1.dart.expect
@@ -2,8 +2,10 @@
 import self as self;
 import "macro.dart" as mac;
 import "dart:core" as core;
+import "main_lib.dart" as mai;
 
 import "org-dartlang-test:///a/b/c/user_macro/macro.dart";
+import "org-dartlang-test:///a/b/c/user_macro/main_lib.dart";
 
 @#C1
 class Class extends core::Object {
@@ -11,15 +13,20 @@
     : super core::Object::•()
     ;
   method /* from org-dartlang-augmentation:/a/b/c/user_macro/main.dart-0 */ method() → void {}
+  method existingMethod() → void {
+    mai::existingMethodDependency();
+  }
 }
 
 library /*isNonNullableByDefault*/;
 import self as mac;
 import "dart:core" as core;
 import "package:_fe_analyzer_shared/src/macros/api.dart" as api;
+import "macro_dependency.dart" as mac2;
 
 import "dart:async";
 import "package:_fe_analyzer_shared/src/macros/api.dart";
+import "org-dartlang-test:///a/b/c/user_macro/macro_dependency.dart";
 
 macro class MethodMacro extends core::Object implements api::ClassDeclarationsMacro /*hasConstConstructor*/  {
   const constructor •() → mac::MethodMacro
@@ -27,7 +34,7 @@
     ;
   @#C2
   method buildDeclarationsForClass(api::ClassDeclaration clazz, api::ClassMemberDeclarationBuilder builder) → FutureOr<void> async {
-    builder.{api::ClassMemberDeclarationBuilder::declareInClass}(new api::DeclarationCode::fromString("  void method() {}\n")){(api::DeclarationCode) → void};
+    builder.{api::ClassMemberDeclarationBuilder::declareInClass}(new api::DeclarationCode::fromString(mac2::generateBody())){(api::DeclarationCode) → void};
   }
 }
 
diff --git a/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.2.dart.expect b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.2.dart.expect
new file mode 100644
index 0000000..39bdd89
--- /dev/null
+++ b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.2.dart.expect
@@ -0,0 +1,54 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "macro.dart" as mac;
+import "dart:core" as core;
+import "main_lib.dart" as mai;
+
+import "org-dartlang-test:///a/b/c/user_macro/macro.dart";
+import "org-dartlang-test:///a/b/c/user_macro/main_lib.dart";
+
+@#C1
+class Class extends core::Object {
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  method /* from org-dartlang-augmentation:/a/b/c/user_macro/main.dart-0 */ method() → void {
+    core::print("method");
+  }
+  method existingMethod() → void {
+    mai::existingMethodDependency();
+  }
+}
+
+library /*isNonNullableByDefault*/;
+import self as mac;
+import "dart:core" as core;
+import "package:_fe_analyzer_shared/src/macros/api.dart" as api;
+import "macro_dependency.dart" as mac2;
+
+import "dart:async";
+import "package:_fe_analyzer_shared/src/macros/api.dart";
+import "org-dartlang-test:///a/b/c/user_macro/macro_dependency.dart";
+
+macro class MethodMacro extends core::Object implements api::ClassDeclarationsMacro /*hasConstConstructor*/  {
+  const constructor •() → mac::MethodMacro
+    : super core::Object::•()
+    ;
+  @#C2
+  method buildDeclarationsForClass(api::ClassDeclaration clazz, api::ClassMemberDeclarationBuilder builder) → FutureOr<void> async {
+    builder.{api::ClassMemberDeclarationBuilder::declareInClass}(new api::DeclarationCode::fromString(mac2::generateBody())){(api::DeclarationCode) → void};
+  }
+}
+
+library /*isNonNullableByDefault*/;
+import self as mac2;
+import "dart:core" as core;
+
+static method generateBody() → core::String {
+  return "  void method() {\n    print('method');\n  }\n";
+}
+
+constants  {
+  #C1 = mac::MethodMacro {}
+  #C2 = dart.core::_Override {}
+}
diff --git a/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.3.dart.expect b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.3.dart.expect
new file mode 100644
index 0000000..9e26179
--- /dev/null
+++ b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main.3.dart.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method existingMethodDependency() → void {
+  core::print("existingMethodDependency");
+}
+
diff --git a/pkg/front_end/test/macros/incremental/data/tests/user_macro/main_lib.0.dart b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main_lib.0.dart
new file mode 100644
index 0000000..0dc9b98
--- /dev/null
+++ b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main_lib.0.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2022, 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.
+
+void existingMethodDependency() {}
diff --git a/pkg/front_end/test/macros/incremental/data/tests/user_macro/main_lib.3.dart b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main_lib.3.dart
new file mode 100644
index 0000000..d574b8d
--- /dev/null
+++ b/pkg/front_end/test/macros/incremental/data/tests/user_macro/main_lib.3.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, 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.
+
+void existingMethodDependency() {
+  print('existingMethodDependency');
+}
diff --git a/pkg/front_end/test/macros/incremental/incremental_macro_test.dart b/pkg/front_end/test/macros/incremental/incremental_macro_test.dart
index e6fd95e..7fb1af7 100644
--- a/pkg/front_end/test/macros/incremental/incremental_macro_test.dart
+++ b/pkg/front_end/test/macros/incremental/incremental_macro_test.dart
@@ -90,7 +90,10 @@
   CompilerOptions compilerOptions = new CompilerOptions()
     ..sdkRoot = computePlatformBinariesLocation(forceBuildDir: true)
     ..packagesFileUri = Platform.script.resolve('data/package_config.json')
-    ..explicitExperimentalFlags = {ExperimentalFlag.macros: true}
+    ..explicitExperimentalFlags = {
+      ExperimentalFlag.macros: true,
+      ExperimentalFlag.alternativeInvalidationStrategy: true,
+    }
     ..macroSerializer = macroSerializer
     ..precompiledMacroUris = {}
     ..macroExecutorProvider = () async {
diff --git a/tools/VERSION b/tools/VERSION
index a02d0b9..a3c62a0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 198
+PRERELEASE 199
 PRERELEASE_PATCH 0
\ No newline at end of file