[cfe] Determine macro classes using 'macro' modifier

Determining which classes are considered macro classes is changed
from using the superclass/interface relation to using the 'macro'
class modifier.

Change-Id: I2497e1f29adbb4fe8d627e0029fc051323745571
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/224523
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 5dace80..82bbe12 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -837,7 +837,9 @@
               'macros', libraryBuilder.enableMacrosVersionInLibrary.toText()),
           macroToken.next!.charOffset,
           macroToken.next!.length);
+      macroToken = null;
     }
+    push(macroToken ?? NullValue.Token);
   }
 
   @override
@@ -927,7 +929,9 @@
               'macros', libraryBuilder.enableMacrosVersionInLibrary.toText()),
           macroToken.next!.charOffset,
           macroToken.next!.length);
+      macroToken = null;
     }
+    push(macroToken ?? NullValue.Token);
   }
 
   @override
@@ -1060,10 +1064,26 @@
   @override
   void endClassDeclaration(Token beginToken, Token endToken) {
     debugEvent("endClassDeclaration");
+    assert(checkState(beginToken, [
+      /* interfaces */ ValueKinds.TypeBuilderListOrNull,
+      /* supertype offset */ ValueKinds.Integer,
+      /* supertype */ unionOfKinds([
+        ValueKinds.TypeBuilderOrNull,
+        ValueKinds.ParserRecovery,
+      ]),
+      /* macro token */ ValueKinds.TokenOrNull,
+      /* modifiers */ ValueKinds.Integer,
+      /* type variables */ ValueKinds.TypeVariableListOrNull,
+      /* name offset */ ValueKinds.Integer,
+      /* name */ ValueKinds.NameOrParserRecovery,
+      /* metadata */ ValueKinds.MetadataListOrNull,
+    ]));
+
     List<TypeBuilder>? interfaces =
         pop(NullValue.TypeBuilderList) as List<TypeBuilder>?;
     int supertypeOffset = popCharOffset();
     TypeBuilder? supertype = nullIfParserRecovery(pop()) as TypeBuilder?;
+    Token? macroToken = pop(NullValue.Token) as Token?;
     int modifiers = pop() as int;
     List<TypeVariableBuilder>? typeVariables =
         pop() as List<TypeVariableBuilder>?;
@@ -1140,7 +1160,8 @@
           startCharOffset,
           nameOffset,
           endToken.charOffset,
-          supertypeOffset);
+          supertypeOffset,
+          isMacro: macroToken != null);
     }
     libraryBuilder.setCurrentClassName(null);
     popDeclarationContext(DeclarationContext.Class);
@@ -1898,9 +1919,25 @@
   void endNamedMixinApplication(Token beginToken, Token classKeyword,
       Token equals, Token? implementsKeyword, Token endToken) {
     debugEvent("endNamedMixinApplication");
+    assert(checkState(beginToken, [
+      if (implementsKeyword != null)
+        /* interfaces */ ValueKinds.TypeBuilderListOrNull,
+      /* mixin application */ unionOfKinds([
+        ValueKinds.ParserRecovery,
+        ValueKinds.TypeBuilder,
+      ]),
+      /* macro token */ ValueKinds.TokenOrNull,
+      /* modifiers */ ValueKinds.Integer,
+      /* type variables */ ValueKinds.TypeVariableListOrNull,
+      /* name offset */ ValueKinds.Integer,
+      /* name */ ValueKinds.NameOrParserRecovery,
+      /* metadata */ ValueKinds.MetadataListOrNull,
+    ]));
+
     List<TypeBuilder>? interfaces =
         popIfNotNull(implementsKeyword) as List<TypeBuilder>?;
     Object? mixinApplication = pop();
+    Token? macroToken = pop(NullValue.Token) as Token?;
     int modifiers = pop() as int;
     List<TypeVariableBuilder>? typeVariables =
         pop() as List<TypeVariableBuilder>?;
@@ -1968,7 +2005,8 @@
           interfaces,
           startCharOffset,
           charOffset,
-          charEndOffset);
+          charEndOffset,
+          isMacro: macroToken != null);
     }
     popDeclarationContext(DeclarationContext.NamedMixinApplication);
   }
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 23ad100..f9033bb 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -100,26 +100,29 @@
 
   final IndexedClass? referencesFromIndexed;
 
+  final bool isMacro;
+
   SourceClassBuilder(
-    List<MetadataBuilder>? metadata,
-    int modifiers,
-    String name,
-    List<TypeVariableBuilder>? typeVariables,
-    TypeBuilder? supertype,
-    List<TypeBuilder>? interfaces,
-    List<TypeBuilder>? onTypes,
-    Scope scope,
-    ConstructorScope constructors,
-    SourceLibraryBuilder parent,
-    this.constructorReferences,
-    int startCharOffset,
-    int nameOffset,
-    int charEndOffset,
-    this.referencesFromIndexed, {
-    Class? cls,
-    this.mixedInTypeBuilder,
-    this.isMixinDeclaration = false,
-  })  : actualCls = initializeClass(cls, typeVariables, name, parent,
+      List<MetadataBuilder>? metadata,
+      int modifiers,
+      String name,
+      List<TypeVariableBuilder>? typeVariables,
+      TypeBuilder? supertype,
+      List<TypeBuilder>? interfaces,
+      List<TypeBuilder>? onTypes,
+      Scope scope,
+      ConstructorScope constructors,
+      SourceLibraryBuilder parent,
+      this.constructorReferences,
+      int startCharOffset,
+      int nameOffset,
+      int charEndOffset,
+      this.referencesFromIndexed,
+      {Class? cls,
+      this.mixedInTypeBuilder,
+      this.isMixinDeclaration = false,
+      this.isMacro: false})
+      : actualCls = initializeClass(cls, typeVariables, name, parent,
             startCharOffset, nameOffset, charEndOffset, referencesFromIndexed),
         super(metadata, modifiers, name, typeVariables, supertype, interfaces,
             onTypes, scope, constructors, parent, nameOffset) {
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 5089e47..3c68b27 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -1764,7 +1764,8 @@
       int startOffset,
       int nameOffset,
       int endOffset,
-      int supertypeOffset) {
+      int supertypeOffset,
+      {required bool isMacro}) {
     _addClass(
         TypeParameterScopeKind.classDeclaration,
         metadata,
@@ -1776,7 +1777,8 @@
         startOffset,
         nameOffset,
         endOffset,
-        supertypeOffset);
+        supertypeOffset,
+        isMacro: isMacro);
   }
 
   void addMixinDeclaration(
@@ -1801,7 +1803,8 @@
         startOffset,
         nameOffset,
         endOffset,
-        supertypeOffset);
+        supertypeOffset,
+        isMacro: false);
   }
 
   void _addClass(
@@ -1815,7 +1818,8 @@
       int startOffset,
       int nameOffset,
       int endOffset,
-      int supertypeOffset) {
+      int supertypeOffset,
+      {required bool isMacro}) {
     _checkBadFunctionDeclUse(className, kind, nameOffset);
     _checkBadFunctionParameter(typeVariables);
     // Nested declaration began in `OutlineBuilder.beginClassDeclaration`.
@@ -1853,7 +1857,7 @@
         typeVariables,
         applyMixins(supertype, startOffset, nameOffset, endOffset, className,
             isMixinDeclaration,
-            typeVariables: typeVariables),
+            typeVariables: typeVariables, isMacro: false),
         interfaces,
         // TODO(johnniwinther): Add the `on` clause types of a mixin declaration
         // here.
@@ -1866,7 +1870,8 @@
         nameOffset,
         endOffset,
         _currentClassReferencesFromIndexed,
-        isMixinDeclaration: isMixinDeclaration);
+        isMixinDeclaration: isMixinDeclaration,
+        isMacro: isMacro);
 
     constructorReferences.clear();
     Map<String, TypeVariableBuilder>? typeVariablesByName =
@@ -2126,7 +2131,8 @@
       String? name,
       List<TypeVariableBuilder>? typeVariables,
       int modifiers: 0,
-      List<TypeBuilder>? interfaces}) {
+      List<TypeBuilder>? interfaces,
+      required bool isMacro}) {
     if (name == null) {
       // The following parameters should only be used when building a named
       // mixin application.
@@ -2318,34 +2324,34 @@
         }
 
         SourceClassBuilder application = new SourceClassBuilder(
-          isNamedMixinApplication ? metadata : null,
-          isNamedMixinApplication
-              ? modifiers | namedMixinApplicationMask
-              : abstractMask,
-          fullname,
-          applicationTypeVariables,
-          isMixinDeclaration ? null : supertype,
-          isNamedMixinApplication
-              ? interfaces
-              : isMixinDeclaration
-                  ? [supertype, mixin]
-                  : null,
-          null, // No `on` clause types.
-          new Scope(
-              local: <String, MemberBuilder>{},
-              setters: <String, MemberBuilder>{},
-              parent: scope.withTypeVariables(typeVariables),
-              debugName: "mixin $fullname ",
-              isModifiable: false),
-          new ConstructorScope(fullname, <String, MemberBuilder>{}),
-          this,
-          <ConstructorReferenceBuilder>[],
-          computedStartCharOffset,
-          charOffset,
-          charEndOffset,
-          referencesFromIndexedClass,
-          mixedInTypeBuilder: isMixinDeclaration ? null : mixin,
-        );
+            isNamedMixinApplication ? metadata : null,
+            isNamedMixinApplication
+                ? modifiers | namedMixinApplicationMask
+                : abstractMask,
+            fullname,
+            applicationTypeVariables,
+            isMixinDeclaration ? null : supertype,
+            isNamedMixinApplication
+                ? interfaces
+                : isMixinDeclaration
+                    ? [supertype, mixin]
+                    : null,
+            null, // No `on` clause types.
+            new Scope(
+                local: <String, MemberBuilder>{},
+                setters: <String, MemberBuilder>{},
+                parent: scope.withTypeVariables(typeVariables),
+                debugName: "mixin $fullname ",
+                isModifiable: false),
+            new ConstructorScope(fullname, <String, MemberBuilder>{}),
+            this,
+            <ConstructorReferenceBuilder>[],
+            computedStartCharOffset,
+            charOffset,
+            charEndOffset,
+            referencesFromIndexedClass,
+            mixedInTypeBuilder: isMixinDeclaration ? null : mixin,
+            isMacro: isNamedMixinApplication && isMacro);
         // TODO(ahe, kmillikin): Should always be true?
         // pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart can't
         // handle that :(
@@ -2372,7 +2378,8 @@
       List<TypeBuilder>? interfaces,
       int startCharOffset,
       int charOffset,
-      int charEndOffset) {
+      int charEndOffset,
+      {required bool isMacro}) {
     // Nested declaration began in `OutlineBuilder.beginNamedMixinApplication`.
     endNestedDeclaration(TypeParameterScopeKind.namedMixinApplication, name)
         .resolveNamedTypes(typeVariables, this);
@@ -2382,7 +2389,8 @@
         name: name,
         typeVariables: typeVariables,
         modifiers: modifiers,
-        interfaces: interfaces)!;
+        interfaces: interfaces,
+        isMacro: isMacro)!;
     checkTypeVariables(typeVariables, supertype.declaration);
   }
 
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 4ec6c32..2f6b52c 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -35,7 +35,6 @@
 import '../../base/common.dart';
 import '../../base/instrumentation.dart' show Instrumentation;
 import '../../base/nnbd_mode.dart';
-import '../dill/dill_class_builder.dart';
 import '../dill/dill_library_builder.dart';
 import '../builder_graph.dart';
 import '../builder/builder.dart';
@@ -1324,36 +1323,8 @@
     Set<ClassBuilder> macroClasses = {macroClassBuilder};
     Set<Uri> macroLibraries = {macroLibraryBuilder.importUri};
 
-    bool isMacroClass(TypeDeclarationBuilder? typeDeclarationBuilder) {
-      if (typeDeclarationBuilder == null) return false;
-      while (typeDeclarationBuilder is TypeAliasBuilder) {
-        typeDeclarationBuilder =
-            typeDeclarationBuilder.unaliasDeclaration(null);
-      }
-      if (typeDeclarationBuilder is ClassBuilder) {
-        if (macroClasses.contains(typeDeclarationBuilder)) return true;
-        if (typeDeclarationBuilder is DillClassBuilder) {
-          // TODO(johnniwinther): Recognize macro classes from dill.
-        }
-      }
-      return false;
-    }
-
     for (SourceClassBuilder sourceClassBuilder in sourceClassBuilders) {
-      bool isMacro =
-          isMacroClass(sourceClassBuilder.supertypeBuilder?.declaration);
-      if (!isMacro && sourceClassBuilder.interfaceBuilders != null) {
-        for (TypeBuilder interfaceBuilder
-            in sourceClassBuilder.interfaceBuilders!) {
-          if (isMacroClass(interfaceBuilder.declaration)) {
-            isMacro = true;
-            break;
-          }
-        }
-      }
-      isMacro = isMacro ||
-          isMacroClass(sourceClassBuilder.mixedInTypeBuilder?.declaration);
-      if (isMacro) {
+      if (sourceClassBuilder.isMacro) {
         macroClasses.add(sourceClassBuilder);
         macroLibraries.add(sourceClassBuilder.library.importUri);
         if (retainDataForTesting) {
diff --git a/pkg/front_end/test/macros/data/pkgs/macro/lib/macro.dart b/pkg/front_end/test/macros/data/pkgs/macro/lib/macro.dart
index bfe0285..f79b175 100644
--- a/pkg/front_end/test/macros/data/pkgs/macro/lib/macro.dart
+++ b/pkg/front_end/test/macros/data/pkgs/macro/lib/macro.dart
@@ -4,15 +4,15 @@
 
 import 'package:macro_builder/macro_builder.dart';
 
-class Macro1 implements Macro {
+macro class Macro1 implements Macro {
   const Macro1();
 }
 
-class Macro2 implements Macro {
+macro class Macro2 implements Macro {
   const Macro2();
 }
 
-class Macro3 implements Macro {
+macro class Macro3 implements Macro {
   const Macro3();
 }
 
diff --git a/pkg/front_end/test/macros/data/tests/declare_macro.dart b/pkg/front_end/test/macros/data/tests/declare_macro.dart
index 5d396f7..e6d329e 100644
--- a/pkg/front_end/test/macros/data/tests/declare_macro.dart
+++ b/pkg/front_end/test/macros/data/tests/declare_macro.dart
@@ -12,6 +12,6 @@
 
 import 'package:macro_builder/macro_builder.dart';
 
-class MyMacro implements Macro {}
+macro class MyMacro implements Macro {}
 
 void main() {}
diff --git a/pkg/front_end/test/macros/data/tests/declare_vs_apply/macro_lib.dart b/pkg/front_end/test/macros/data/tests/declare_vs_apply/macro_lib.dart
index 149d512..f1aac83 100644
--- a/pkg/front_end/test/macros/data/tests/declare_vs_apply/macro_lib.dart
+++ b/pkg/front_end/test/macros/data/tests/declare_vs_apply/macro_lib.dart
@@ -10,6 +10,6 @@
 import 'package:macro_builder/macro_builder.dart';
 import 'macro_lib_dep.dart';
 
-class Macro1 extends MacroBase implements Macro {
+macro class Macro1 extends MacroBase implements Macro {
   const Macro1();
 }
diff --git a/pkg/front_end/test/macros/data/tests/import_macro_source/macro_lib.dart b/pkg/front_end/test/macros/data/tests/import_macro_source/macro_lib.dart
index a05f387..c08cbcd 100644
--- a/pkg/front_end/test/macros/data/tests/import_macro_source/macro_lib.dart
+++ b/pkg/front_end/test/macros/data/tests/import_macro_source/macro_lib.dart
@@ -9,6 +9,6 @@
 
 import 'package:macro_builder/macro_builder.dart';
 
-class Macro1 implements Macro {
+macro class Macro1 implements Macro {
   const Macro1();
 }
diff --git a/pkg/front_end/test/macros/data/tests/macro_declarations.dart b/pkg/front_end/test/macros/data/tests/macro_declarations.dart
index 872dad84..f5f5a5f 100644
--- a/pkg/front_end/test/macros/data/tests/macro_declarations.dart
+++ b/pkg/front_end/test/macros/data/tests/macro_declarations.dart
@@ -13,25 +13,47 @@
   ImplementsAlias,
   Mixin,
   MixinAlias,
-  _Mixin&Object&Macro,
-  _MixinAlias&Object&Alias],
+  NamedMixin1,
+  NamedMixin2],
  macrosAreAvailable
 */
 
 import 'package:macro_builder/macro_builder.dart';
 
-class Extends extends Macro {}
+macro class Extends extends Macro {}
 
-class Implements implements Macro {}
+macro class Implements implements Macro {}
 
-class Mixin with Macro {}
+macro class Mixin with Macro {}
+
+mixin _Mixin {}
+
+macro class NamedMixin1 = Macro with _Mixin;
+
+macro class NamedMixin2 = Object with Macro;
 
 typedef Alias = Macro;
 
-class ExtendsAlias extends Alias {}
+macro class ExtendsAlias extends Alias {}
 
-class ImplementsAlias implements Alias {}
+macro class ImplementsAlias implements Alias {}
 
-class MixinAlias with Alias {}
+macro class MixinAlias with Alias {}
+
+class ExtendsNoKeyword extends Macro {}
+
+class ImplementsNoKeyword implements Macro {}
+
+class MixinNoKeyword with Macro {}
+
+class ExtendsAliasNoKeyword extends Alias {}
+
+class ImplementsAliasNoKeyword implements Alias {}
+
+class MixinAliasNoKeyword with Alias {}
+
+class NamedMixin1NoKeyword = Macro with _Mixin;
+
+class NamedMixin2NoKeyword = Object with Macro;
 
 void main() {}
diff --git a/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib1.dart b/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib1.dart
index a05f387..c08cbcd 100644
--- a/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib1.dart
+++ b/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib1.dart
@@ -9,6 +9,6 @@
 
 import 'package:macro_builder/macro_builder.dart';
 
-class Macro1 implements Macro {
+macro class Macro1 implements Macro {
   const Macro1();
 }
diff --git a/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib2a.dart b/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib2a.dart
index 967801f..729e7f1 100644
--- a/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib2a.dart
+++ b/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib2a.dart
@@ -9,6 +9,6 @@
 
 import 'package:macro_builder/macro_builder.dart';
 
-class Macro2a implements Macro {
+macro class Macro2a implements Macro {
   const Macro2a();
 }
diff --git a/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib2b.dart b/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib2b.dart
index b9bc7d2..df143f5 100644
--- a/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib2b.dart
+++ b/pkg/front_end/test/macros/data/tests/multiple_macros/macro_lib2b.dart
@@ -16,6 +16,6 @@
  appliedMacros=[Macro2a],
  macrosAreApplied
 */
-class Macro2b implements Macro {
+macro class Macro2b implements Macro {
   const Macro2b();
 }
diff --git a/pkg/front_end/test/macros/data/tests/use_macro_source/macro_lib.dart b/pkg/front_end/test/macros/data/tests/use_macro_source/macro_lib.dart
index 3f926a8..f3767a5 100644
--- a/pkg/front_end/test/macros/data/tests/use_macro_source/macro_lib.dart
+++ b/pkg/front_end/test/macros/data/tests/use_macro_source/macro_lib.dart
@@ -11,11 +11,11 @@
 
 import 'package:macro_builder/macro_builder.dart';
 
-class Macro1 implements Macro {
+macro class Macro1 implements Macro {
   const Macro1();
 }
 
-class Macro2 implements Macro {
+macro class Macro2 implements Macro {
   const Macro2();
 }
 
diff --git a/pkg/front_end/test/macros/macro_test.dart b/pkg/front_end/test/macros/macro_test.dart
index 82fe62d..c1aa33e 100644
--- a/pkg/front_end/test/macros/macro_test.dart
+++ b/pkg/front_end/test/macros/macro_test.dart
@@ -8,6 +8,7 @@
 import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
 
 import 'package:_fe_analyzer_shared/src/testing/features.dart';
+import 'package:front_end/src/api_prototype/experimental_flags.dart';
 import 'package:front_end/src/fasta/kernel/macro.dart';
 import 'package:front_end/src/testing/id_testing_helper.dart';
 import 'package:kernel/ast.dart';
@@ -23,6 +24,7 @@
       onFailure: onFailure,
       runTest: runTestFor(const MacroDataComputer(), [
         new TestConfig(cfeMarker, 'cfe',
+            explicitExperimentalFlags: {ExperimentalFlag.macros: true},
             packageConfigUri:
                 Platform.script.resolve('data/package_config.json'))
       ]));
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 7a1fd28..ea9623a 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -675,6 +675,8 @@
 misspelled
 mistake
 mistakes
+mixin1
+mixin2
 mmethod
 mod
 modelled