[cfe] Include concrete augmented procedures in the AST

This is in preparation for supporting `augment super` access of
augmented members.

Change-Id: Ib306ef59faa7c9ad735304545aa414f6b21e2596
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/249862
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
diff --git a/pkg/front_end/lib/src/fasta/builder/builder.dart b/pkg/front_end/lib/src/fasta/builder/builder.dart
index 7b208f1..347694c 100644
--- a/pkg/front_end/lib/src/fasta/builder/builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/builder.dart
@@ -197,9 +197,6 @@
   /// Applies [patch] to this declaration.
   void applyPatch(Builder patch);
 
-  /// Returns the number of patches that was finished.
-  int finishPatch();
-
   /// Return `true` if this builder is a duplicate of another with the same
   /// name. This is `false` for the builder first declared amongst duplicates.
   bool get isDuplicate;
@@ -295,11 +292,5 @@
   }
 
   @override
-  int finishPatch() {
-    if (!isPatch) return 0;
-    unsupported("${runtimeType}.finishPatch", charOffset, fileUri);
-  }
-
-  @override
   bool get isDuplicate => next != null;
 }
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index be3c4cf..c0848ae 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -1996,7 +1996,7 @@
         }
       }
 
-      debugLibrary.build(lastGoodKernelTarget.loader.coreLibrary,
+      debugLibrary.buildOutlineNodes(lastGoodKernelTarget.loader.coreLibrary,
           modifyTarget: false);
       Expression compiledExpression = await lastGoodKernelTarget.loader
           .buildExpression(
diff --git a/pkg/front_end/lib/src/fasta/kernel/augmentation_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/augmentation_lowering.dart
new file mode 100644
index 0000000..67ba682
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/augmentation_lowering.dart
@@ -0,0 +1,19 @@
+// 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.
+
+import 'package:kernel/ast.dart';
+
+const String _augmentedNamePrefix = '_#';
+const String _augmentedNameSuffix = '#augment';
+
+/// Creates the synthesized name to use for the [index]th augmented member by
+/// the given [name] in [library].
+Name augmentedName(String name, Library library, int index) {
+  return new Name(
+      '$_augmentedNamePrefix'
+      '${name.isEmpty ? 'new' : name}'
+      '$_augmentedNameSuffix'
+      '$index',
+      library);
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart b/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
index 53d9f3d..0139e82 100644
--- a/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
@@ -538,7 +538,7 @@
     if (copyLocation) {
       fileUri = member.fileUri;
       startFileOffset =
-          member is Procedure ? member.startFileOffset : member.fileOffset;
+          member is Procedure ? member.fileStartOffset : member.fileOffset;
       fileOffset = member.fileOffset;
     } else {
       fileUri = enclosingClass.fileUri;
@@ -555,7 +555,7 @@
       stubKind: ProcedureStubKind.MemberSignature,
       stubTarget: member.memberSignatureOrigin ?? member,
     )
-      ..startFileOffset = startFileOffset
+      ..fileStartOffset = startFileOffset
       ..fileOffset = fileOffset
       ..isNonNullableByDefault = containsNnbdTypes
       ..parent = enclosingClass;
@@ -585,7 +585,7 @@
     if (copyLocation) {
       fileUri = member.fileUri;
       startFileOffset =
-          member is Procedure ? member.startFileOffset : member.fileOffset;
+          member is Procedure ? member.fileStartOffset : member.fileOffset;
       fileOffset = member.fileOffset;
     } else {
       fileUri = enclosingClass.fileUri;
@@ -611,7 +611,7 @@
       stubKind: ProcedureStubKind.MemberSignature,
       stubTarget: member.memberSignatureOrigin ?? member,
     )
-      ..startFileOffset = startFileOffset
+      ..fileStartOffset = startFileOffset
       ..fileOffset = fileOffset
       ..isNonNullableByDefault = containsNnbdTypes
       ..parent = enclosingClass;
@@ -630,7 +630,7 @@
     int fileOffset;
     if (copyLocation) {
       fileUri = procedure.fileUri;
-      startFileOffset = procedure.startFileOffset;
+      startFileOffset = procedure.fileStartOffset;
       fileOffset = procedure.fileOffset;
     } else {
       fileUri = enclosingClass.fileUri;
@@ -690,7 +690,7 @@
       stubKind: ProcedureStubKind.MemberSignature,
       stubTarget: procedure.memberSignatureOrigin ?? procedure,
     )
-      ..startFileOffset = startFileOffset
+      ..fileStartOffset = startFileOffset
       ..fileOffset = fileOffset
       ..isNonNullableByDefault = containsNnbdTypes
       ..parent = enclosingClass;
diff --git a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
index 77159ce..1e6ea3e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
@@ -295,7 +295,7 @@
 /// The [declarationConstructor] is the [Procedure] for the origin constructor
 /// and [implementationConstructorFunctionNode] is the [FunctionNode] for the
 /// implementation constructor. If the constructor is patched, these are not
-/// connected until [Builder.finishPatch].
+/// connected until [Builder.buildBodyNodes].
 FreshTypeParameters buildRedirectingFactoryTearOffProcedureParameters(
     {required Procedure tearOff,
     required Procedure implementationConstructor,
@@ -370,7 +370,7 @@
     Name name, Uri fileUri, int fileOffset, Reference? reference) {
   return new Procedure(name, ProcedureKind.Method, new FunctionNode(null),
       fileUri: fileUri, isStatic: true, isSynthetic: true, reference: reference)
-    ..startFileOffset = fileOffset
+    ..fileStartOffset = fileOffset
     ..fileOffset = fileOffset
     ..fileEndOffset = fileOffset
     ..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
index ffbbab7..f5ad8bd 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
@@ -325,7 +325,7 @@
   // TODO(ahe): restore file-offset once we track both origin and patch file
   // URIs. See https://github.com/dart-lang/sdk/issues/31579
   origin.fileUri = patch.fileUri;
-  origin.startFileOffset = patch.startFileOffset;
+  origin.fileStartOffset = patch.fileStartOffset;
   origin.fileOffset = patch.fileOffset;
   origin.fileEndOffset = patch.fileEndOffset;
   origin.annotations.forEach((m) => m.fileOffset = patch.fileOffset);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 101ed7f..6986604 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -400,7 +400,8 @@
     loader.finishTypeVariables(
         augmentationLibraries, objectClassBuilder, dynamicType);
     for (SourceLibraryBuilder augmentationLibrary in augmentationLibraries) {
-      augmentationLibrary.build(loader.coreLibrary, modifyTarget: false);
+      augmentationLibrary.buildOutlineNodes(loader.coreLibrary,
+          modifyTarget: false);
     }
     loader.resolveConstructors(augmentationLibraries);
   }
@@ -471,7 +472,7 @@
       loader.createTypeInferenceEngine();
 
       benchmarker?.enterPhase(BenchmarkPhases.outline_buildComponent);
-      loader.buildComponent();
+      loader.buildOutlineNodes();
 
       benchmarker?.enterPhase(BenchmarkPhases.outline_installDefaultSupertypes);
       installDefaultSupertypes();
@@ -637,7 +638,7 @@
       loader.finishNativeMethods();
 
       benchmarker?.enterPhase(BenchmarkPhases.body_finishPatchMethods);
-      loader.finishPatchMethods();
+      loader.buildBodyNodes();
 
       benchmarker?.enterPhase(BenchmarkPhases.body_finishAllConstructors);
       finishAllConstructors(sourceClasses);
diff --git a/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart b/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart
index 7199ba7..dfe1513 100644
--- a/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart
@@ -64,7 +64,7 @@
         fileUri: parent.library.fileUri,
         isStatic: true,
         reference: reference)
-      ..startFileOffset = charOffset
+      ..fileStartOffset = charOffset
       ..fileOffset = charOffset
       ..isNonNullableByDefault = parent.isNonNullableByDefault;
   }
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index f78f458..187af99 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -823,8 +823,14 @@
   }
 
   @override
-  void buildMembers(void Function(Member, BuiltMemberKind) f) {
-    assert(false, "Unexpected call to $runtimeType.buildMembers.");
+  void buildOutlineNodes(void Function(Member, BuiltMemberKind) f) {
+    assert(false, "Unexpected call to $runtimeType.buildOutlineNodes.");
+  }
+
+  @override
+  int buildBodyNodes(void Function(Member, BuiltMemberKind) f) {
+    assert(false, "Unexpected call to $runtimeType.buildBodyNodes.");
+    return 0;
   }
 
   @override
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 d5bf381..593d7b2 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
@@ -182,7 +182,7 @@
         } else if (declaration is SourceMemberBuilder) {
           SourceMemberBuilder memberBuilder = declaration;
           memberBuilder
-              .buildMembers((Member member, BuiltMemberKind memberKind) {
+              .buildOutlineNodes((Member member, BuiltMemberKind memberKind) {
             member.parent = cls;
             if (!memberBuilder.isPatch &&
                 !memberBuilder.isDuplicate &&
@@ -1390,24 +1390,57 @@
     }
   }
 
-  @override
-  int finishPatch() {
-    if (!isPatch) return 0;
-
+  int buildBodyNodes() {
     // TODO(ahe): restore file-offset once we track both origin and patch file
     // URIs. See https://github.com/dart-lang/sdk/issues/31579
-    cls.annotations.forEach((m) => m.fileOffset = origin.cls.fileOffset);
+    if (isPatch) {
+      cls.annotations.forEach((m) => m.fileOffset = origin.cls.fileOffset);
+    }
 
     int count = 0;
-    scope.forEach((String name, Builder declaration) {
-      count += declaration.finishPatch();
-    });
-    constructorScope.forEach((String name, Builder declaration) {
-      count += declaration.finishPatch();
-    });
+
+    void buildMembers(String name, Builder builder) {
+      if (builder.parent != this) {
+        return;
+      }
+      Builder? current = builder;
+      while (current != null) {
+        if (current is SourceMemberBuilder) {
+          count +=
+              current.buildBodyNodes((Member member, BuiltMemberKind kind) {
+            _buildMember(current as SourceMemberBuilder, member, kind);
+          });
+        }
+        current = current.next;
+      }
+    }
+
+    scope.forEach(buildMembers);
+    constructorScope.forEach(buildMembers);
     return count;
   }
 
+  void _buildMember(SourceMemberBuilder memberBuilder, Member member,
+      BuiltMemberKind memberKind) {
+    member.parent = cls;
+    if (!memberBuilder.isDuplicate &&
+        !memberBuilder.isConflictingSetter &&
+        !memberBuilder.isConflictingAugmentationMember) {
+      if (member is Procedure) {
+        cls.addProcedure(member);
+      } else if (member is Field) {
+        cls.addField(member);
+      } else if (member is Constructor) {
+        cls.addConstructor(member);
+      } else if (member is RedirectingFactory) {
+        cls.addRedirectingFactory(member);
+      } else {
+        unhandled("${member.runtimeType}", "getMember", member.fileOffset,
+            member.fileUri);
+      }
+    }
+  }
+
   /// Return a map whose keys are the supertypes of this [SourceClassBuilder]
   /// after expansion of type aliases, if any. For each supertype key, the
   /// corresponding value is the type alias which was unaliased in order to
diff --git a/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart b/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
index 148e2b6..be790e8 100644
--- a/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
@@ -199,7 +199,7 @@
   }
 
   @override
-  void buildMembers(void Function(Member, BuiltMemberKind) f) {
+  void buildOutlineNodes(void Function(Member, BuiltMemberKind) f) {
     _build();
     f(_constructor, BuiltMemberKind.Constructor);
     if (_constructorTearOff != null) {
@@ -708,7 +708,7 @@
   }
 
   @override
-  int finishPatch() {
+  int buildBodyNodes(void Function(Member, BuiltMemberKind) f) {
     if (!isPatch) return 0;
     _finishPatch();
     return 1;
diff --git a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
index 578747e..874a967 100644
--- a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
@@ -101,6 +101,7 @@
 
     ClassBuilder objectClassBuilder =
         coreLibrary.lookupLocalMember('Object', required: true) as ClassBuilder;
+
     void buildBuilders(String name, Builder? declaration) {
       while (declaration != null) {
         Builder? objectGetter = objectClassBuilder.lookupLocalMember(name);
@@ -125,64 +126,9 @@
         } else if (declaration is SourceMemberBuilder) {
           SourceMemberBuilder memberBuilder = declaration;
           memberBuilder
-              .buildMembers((Member member, BuiltMemberKind memberKind) {
-            if (addMembersToLibrary &&
-                !memberBuilder.isPatch &&
-                !memberBuilder.isDuplicate &&
-                !memberBuilder.isConflictingSetter) {
-              ExtensionMemberKind kind;
-              String name = memberBuilder.name;
-              switch (memberKind) {
-                case BuiltMemberKind.Constructor:
-                case BuiltMemberKind.RedirectingFactory:
-                case BuiltMemberKind.Field:
-                case BuiltMemberKind.Method:
-                  unhandled(
-                      "${member.runtimeType}:${memberKind}",
-                      "buildMembers",
-                      memberBuilder.charOffset,
-                      memberBuilder.fileUri);
-                case BuiltMemberKind.ExtensionField:
-                case BuiltMemberKind.LateIsSetField:
-                  kind = ExtensionMemberKind.Field;
-                  break;
-                case BuiltMemberKind.ExtensionMethod:
-                  kind = ExtensionMemberKind.Method;
-                  break;
-                case BuiltMemberKind.ExtensionGetter:
-                case BuiltMemberKind.LateGetter:
-                  kind = ExtensionMemberKind.Getter;
-                  break;
-                case BuiltMemberKind.ExtensionSetter:
-                case BuiltMemberKind.LateSetter:
-                  kind = ExtensionMemberKind.Setter;
-                  break;
-                case BuiltMemberKind.ExtensionOperator:
-                  kind = ExtensionMemberKind.Operator;
-                  break;
-                case BuiltMemberKind.ExtensionTearOff:
-                  kind = ExtensionMemberKind.TearOff;
-                  break;
-              }
-              // ignore: unnecessary_null_comparison
-              assert(kind != null);
-              Reference memberReference;
-              if (member is Field) {
-                libraryBuilder.library.addField(member);
-                memberReference = member.fieldReference;
-              } else if (member is Procedure) {
-                libraryBuilder.library.addProcedure(member);
-                memberReference = member.reference;
-              } else {
-                unhandled("${member.runtimeType}", "buildBuilders",
-                    member.fileOffset, member.fileUri);
-              }
-              extension.members.add(new ExtensionMemberDescriptor(
-                  name: new Name(name, libraryBuilder.library),
-                  member: memberReference,
-                  isStatic: memberBuilder.isStatic,
-                  kind: kind));
-            }
+              .buildOutlineNodes((Member member, BuiltMemberKind memberKind) {
+            _buildMember(memberBuilder, member, memberKind,
+                addMembersToLibrary: addMembersToLibrary);
           });
         } else {
           unhandled("${declaration.runtimeType}", "buildBuilders",
@@ -197,6 +143,65 @@
     return _extension;
   }
 
+  void _buildMember(SourceMemberBuilder memberBuilder, Member member,
+      BuiltMemberKind memberKind,
+      {required bool addMembersToLibrary}) {
+    if (addMembersToLibrary &&
+        !memberBuilder.isPatch &&
+        !memberBuilder.isDuplicate &&
+        !memberBuilder.isConflictingSetter) {
+      ExtensionMemberKind kind;
+      String name = memberBuilder.name;
+      switch (memberKind) {
+        case BuiltMemberKind.Constructor:
+        case BuiltMemberKind.RedirectingFactory:
+        case BuiltMemberKind.Field:
+        case BuiltMemberKind.Method:
+          unhandled("${member.runtimeType}:${memberKind}", "buildMembers",
+              memberBuilder.charOffset, memberBuilder.fileUri);
+        case BuiltMemberKind.ExtensionField:
+        case BuiltMemberKind.LateIsSetField:
+          kind = ExtensionMemberKind.Field;
+          break;
+        case BuiltMemberKind.ExtensionMethod:
+          kind = ExtensionMemberKind.Method;
+          break;
+        case BuiltMemberKind.ExtensionGetter:
+        case BuiltMemberKind.LateGetter:
+          kind = ExtensionMemberKind.Getter;
+          break;
+        case BuiltMemberKind.ExtensionSetter:
+        case BuiltMemberKind.LateSetter:
+          kind = ExtensionMemberKind.Setter;
+          break;
+        case BuiltMemberKind.ExtensionOperator:
+          kind = ExtensionMemberKind.Operator;
+          break;
+        case BuiltMemberKind.ExtensionTearOff:
+          kind = ExtensionMemberKind.TearOff;
+          break;
+      }
+      // ignore: unnecessary_null_comparison
+      assert(kind != null);
+      Reference memberReference;
+      if (member is Field) {
+        libraryBuilder.library.addField(member);
+        memberReference = member.fieldReference;
+      } else if (member is Procedure) {
+        libraryBuilder.library.addProcedure(member);
+        memberReference = member.reference;
+      } else {
+        unhandled("${member.runtimeType}", "buildBuilders", member.fileOffset,
+            member.fileUri);
+      }
+      extension.members.add(new ExtensionMemberDescriptor(
+          name: new Name(name, libraryBuilder.library),
+          member: memberReference,
+          isStatic: memberBuilder.isStatic,
+          kind: kind));
+    }
+  }
+
   @override
   void applyPatch(Builder patch) {
     if (patch is SourceExtensionBuilder) {
@@ -230,13 +235,19 @@
     }
   }
 
-  @override
-  int finishPatch() {
-    if (!isPatch) return 0;
-
+  int buildBodyNodes({required bool addMembersToLibrary}) {
     int count = 0;
-    scope.forEach((String name, Builder declaration) {
-      count += declaration.finishPatch();
+    scope.forEach((String name, Builder? declaration) {
+      while (declaration != null) {
+        if (declaration is SourceMemberBuilder) {
+          count +=
+              declaration.buildBodyNodes((Member member, BuiltMemberKind kind) {
+            _buildMember(declaration as SourceMemberBuilder, member, kind,
+                addMembersToLibrary: addMembersToLibrary);
+          });
+        }
+        declaration = declaration.next;
+      }
     });
     return count;
   }
diff --git a/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart b/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
index ec7ffb5..c90fe39 100644
--- a/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_factory_builder.dart
@@ -75,7 +75,7 @@
             new FunctionNode(null),
             fileUri: libraryBuilder.fileUri,
             reference: procedureReference)
-          ..startFileOffset = startCharOffset
+          ..fileStartOffset = startCharOffset
           ..fileOffset = charOffset
           ..fileEndOffset = charEndOffset
           ..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault,
@@ -132,7 +132,7 @@
   Iterable<Member> get exportedMembers => [_procedure];
 
   @override
-  void buildMembers(void Function(Member, BuiltMemberKind) f) {
+  void buildOutlineNodes(void Function(Member, BuiltMemberKind) f) {
     _build();
     f(_procedureInternal, BuiltMemberKind.Method);
     if (_factoryTearOff != null) {
@@ -236,7 +236,7 @@
   }
 
   @override
-  int finishPatch() {
+  int buildBodyNodes(void Function(Member, BuiltMemberKind) f) {
     if (!isPatch) return 0;
     _finishPatch();
     return 1;
@@ -338,7 +338,7 @@
   }
 
   @override
-  void buildMembers(void Function(Member, BuiltMemberKind) f) {
+  void buildOutlineNodes(void Function(Member, BuiltMemberKind) f) {
     _build();
     f(_procedureInternal, BuiltMemberKind.RedirectingFactory);
     if (_factoryTearOff != null) {
diff --git a/pkg/front_end/lib/src/fasta/source/source_field_builder.dart b/pkg/front_end/lib/src/fasta/source/source_field_builder.dart
index b05b07b..1fccff2 100644
--- a/pkg/front_end/lib/src/fasta/source/source_field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_field_builder.dart
@@ -374,7 +374,7 @@
   Iterable<Member> get exportedMembers => _fieldEncoding.exportedMembers;
 
   @override
-  void buildMembers(void Function(Member, BuiltMemberKind) f) {
+  void buildOutlineNodes(void Function(Member, BuiltMemberKind) f) {
     _build();
     _fieldEncoding.registerMembers(libraryBuilder, this, f);
   }
@@ -531,6 +531,11 @@
       SourceLibraryBuilder library, TypeEnvironment typeEnvironment) {
     library.checkTypesInField(this, typeEnvironment);
   }
+
+  @override
+  int buildBodyNodes(void Function(Member, BuiltMemberKind) f) {
+    return 0;
+  }
 }
 
 /// Strategy pattern for creating different encodings of a declared field.
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 db9853c..5a845c0e 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
@@ -1038,7 +1038,8 @@
   }
 
   /// Builds the core AST structure of this library as needed for the outline.
-  Library build(LibraryBuilder coreLibrary, {bool modifyTarget: true}) {
+  Library buildOutlineNodes(LibraryBuilder coreLibrary,
+      {bool modifyTarget: true}) {
     // TODO(johnniwinther): Avoid the need to process patch libraries before
     // the origin. Currently, settings performed by the patch are overridden
     // by the origin. For instance, the `Map` class is abstract in the origin
@@ -1048,7 +1049,7 @@
     Iterable<SourceLibraryBuilder>? patches = this.patchLibraries;
     if (patches != null) {
       for (SourceLibraryBuilder patchLibrary in patches) {
-        patchLibrary.build(coreLibrary, modifyTarget: modifyTarget);
+        patchLibrary.buildOutlineNodes(coreLibrary, modifyTarget: modifyTarget);
       }
     }
 
@@ -1058,7 +1059,7 @@
 
     Iterator<Builder> iterator = this.iterator;
     while (iterator.moveNext()) {
-      buildBuilder(iterator.current, coreLibrary);
+      _buildOutlineNodes(iterator.current, coreLibrary);
     }
 
     if (!modifyTarget) return library;
@@ -3050,7 +3051,7 @@
   }
 
   /// Builds the core AST structures for [declaration] needed for the outline.
-  void buildBuilder(Builder declaration, LibraryBuilder coreLibrary) {
+  void _buildOutlineNodes(Builder declaration, LibraryBuilder coreLibrary) {
     String findDuplicateSuffix(Builder declaration) {
       if (declaration.next != null) {
         int count = 0;
@@ -3077,35 +3078,15 @@
         library.addExtension(extension);
       }
     } else if (declaration is SourceMemberBuilder) {
-      declaration.buildMembers((Member member, BuiltMemberKind memberKind) {
-        if (member is Field) {
-          member.isStatic = true;
-          if (!declaration.isPatch && !declaration.isDuplicate) {
-            library.addField(member);
-          }
-        } else if (member is Procedure) {
-          member.isStatic = true;
-          if (!declaration.isPatch &&
-              !declaration.isDuplicate &&
-              !declaration.isConflictingSetter) {
-            library.addProcedure(member);
-          }
-        } else {
-          unhandled("${member.runtimeType}:${memberKind}", "buildBuilder",
-              declaration.charOffset, declaration.fileUri);
-        }
+      declaration
+          .buildOutlineNodes((Member member, BuiltMemberKind memberKind) {
+        _addMemberToLibrary(declaration, member, memberKind);
       });
     } else if (declaration is SourceTypeAliasBuilder) {
       Typedef typedef = declaration.build();
       if (!declaration.isPatch && !declaration.isDuplicate) {
         library.addTypedef(typedef);
       }
-    } else if (declaration is SourceEnumBuilder) {
-      Class cls = declaration.build(coreLibrary);
-      if (!declaration.isPatch) {
-        cls.name += findDuplicateSuffix(declaration);
-        library.addClass(cls);
-      }
     } else if (declaration is PrefixBuilder) {
       // Ignored. Kernel doesn't represent prefixes.
       return;
@@ -3118,6 +3099,26 @@
     }
   }
 
+  void _addMemberToLibrary(SourceMemberBuilder declaration, Member member,
+      BuiltMemberKind memberKind) {
+    if (member is Field) {
+      member.isStatic = true;
+      if (!declaration.isPatch && !declaration.isDuplicate) {
+        library.addField(member);
+      }
+    } else if (member is Procedure) {
+      member.isStatic = true;
+      if (!declaration.isPatch &&
+          !declaration.isDuplicate &&
+          !declaration.isConflictingSetter) {
+        library.addProcedure(member);
+      }
+    } else {
+      unhandled("${member.runtimeType}:${memberKind}", "_buildMember",
+          declaration.charOffset, declaration.fileUri);
+    }
+  }
+
   void addNativeDependency(String nativeImportPath) {
     MemberBuilder constructor = loader.getNativeAnnotation();
     Arguments arguments =
@@ -3934,20 +3935,43 @@
     }
   }
 
-  int finishPatchMethods() {
+  /// Builds the AST nodes needed for the full compilation.
+  ///
+  /// This includes patching member bodies and adding augmented members.
+  int buildBodyNodes() {
     int count = 0;
 
     Iterable<SourceLibraryBuilder>? patches = this.patchLibraries;
     if (patches != null) {
       for (SourceLibraryBuilder patchLibrary in patches) {
-        count += patchLibrary.finishPatchMethods();
+        count += patchLibrary.buildBodyNodes();
       }
     }
 
-    if (isPatch) {
-      Iterator<Builder> iterator = this.iterator;
-      while (iterator.moveNext()) {
-        count += iterator.current.finishPatch();
+    Iterator<Builder> iterator = this.iterator;
+    while (iterator.moveNext()) {
+      Builder builder = iterator.current;
+      if (builder is SourceMemberBuilder) {
+        count +=
+            builder.buildBodyNodes((Member member, BuiltMemberKind memberKind) {
+          _addMemberToLibrary(builder, member, memberKind);
+        });
+      } else if (builder is SourceClassBuilder) {
+        count += builder.buildBodyNodes();
+      } else if (builder is SourceExtensionBuilder) {
+        count +=
+            builder.buildBodyNodes(addMembersToLibrary: !builder.isDuplicate);
+      } else if (builder is SourceClassBuilder) {
+        count += builder.buildBodyNodes();
+      } else if (builder is SourceTypeAliasBuilder) {
+        // Do nothing.
+      } else if (builder is PrefixBuilder) {
+        // Ignored. Kernel doesn't represent prefixes.
+      } else if (builder is BuiltinTypeDeclarationBuilder) {
+        // Nothing needed.
+      } else {
+        unhandled("${builder.runtimeType}", "buildBodyNodes",
+            builder.charOffset, builder.fileUri);
       }
     }
     return count;
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 d3b47de..6e7c3fe 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -1793,10 +1793,10 @@
     ticker.logMs("Finished $count native methods");
   }
 
-  void finishPatchMethods() {
+  void buildBodyNodes() {
     int count = 0;
     for (SourceLibraryBuilder library in sourceLibraryBuilders) {
-      count += library.finishPatchMethods();
+      count += library.buildBodyNodes();
     }
     ticker.logMs("Finished $count patch methods");
   }
@@ -2020,9 +2020,9 @@
   }
 
   /// Builds the core AST structure needed for the outline of the component.
-  void buildComponent() {
+  void buildOutlineNodes() {
     for (SourceLibraryBuilder library in sourceLibraryBuilders) {
-      Library target = library.build(coreLibrary);
+      Library target = library.buildOutlineNodes(coreLibrary);
       if (library.referencesFrom != null) {
         referenceFromIndex ??= new ReferenceFromIndex();
         referenceFromIndex!
diff --git a/pkg/front_end/lib/src/fasta/source/source_member_builder.dart b/pkg/front_end/lib/src/fasta/source/source_member_builder.dart
index 429809d..822ea53 100644
--- a/pkg/front_end/lib/src/fasta/source/source_member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_member_builder.dart
@@ -29,13 +29,18 @@
   SourceLibraryBuilder get libraryBuilder;
 
   /// Builds the core AST structures for this member as needed for the outline.
-  void buildMembers(void Function(Member, BuiltMemberKind) f);
+  void buildOutlineNodes(void Function(Member, BuiltMemberKind) f);
 
   void buildOutlineExpressions(
       ClassHierarchy classHierarchy,
       List<DelayedActionPerformer> delayedActionPerformers,
       List<DelayedDefaultValueCloner> delayedDefaultValueCloners);
 
+  /// Builds the AST nodes for this member as needed for the full compilation.
+  ///
+  /// This includes adding patched bodies and augmented members.
+  int buildBodyNodes(void Function(Member, BuiltMemberKind) f);
+
   /// Checks the variance of type parameters [sourceClassBuilder] used in the
   /// signature of this member.
   void checkVariance(
@@ -60,11 +65,16 @@
       retainDataForTesting ? new MemberDataForTesting() : null;
 
   @override
-  void buildMembers(void Function(Member, BuiltMemberKind) f) {
+  void buildOutlineNodes(void Function(Member, BuiltMemberKind) f) {
     assert(false, "Unexpected call to $runtimeType.buildMembers.");
   }
 
   @override
+  int buildBodyNodes(void Function(Member, BuiltMemberKind) f) {
+    return 0;
+  }
+
+  @override
   bool get isAugmentation => false;
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart b/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
index 9588563..e6686bc 100644
--- a/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_procedure_builder.dart
@@ -14,6 +14,7 @@
 import '../builder/procedure_builder.dart';
 import '../builder/type_builder.dart';
 import '../builder/type_variable_builder.dart';
+import '../kernel/augmentation_lowering.dart';
 import '../kernel/hierarchy/class_member.dart';
 import '../kernel/hierarchy/members_builder.dart';
 import '../kernel/kernel_helper.dart';
@@ -96,7 +97,7 @@
         fileUri: libraryBuilder.fileUri,
         reference: procedureReference,
         isSynthetic: isSynthetic)
-      ..startFileOffset = startCharOffset
+      ..fileStartOffset = startCharOffset
       ..fileOffset = charOffset
       ..fileEndOffset = charEndOffset
       ..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault;
@@ -231,7 +232,7 @@
   Iterable<Member> get exportedMembers => [procedure];
 
   @override
-  void buildMembers(void Function(Member, BuiltMemberKind) f) {
+  void buildOutlineNodes(void Function(Member, BuiltMemberKind) f) {
     _build();
     if (isExtensionMethod) {
       switch (kind) {
@@ -467,11 +468,33 @@
   }
 
   @override
-  int finishPatch() {
-    if (!isPatch) return 0;
+  int buildBodyNodes(void Function(Member, BuiltMemberKind) f) {
+    List<SourceProcedureBuilder>? patches = _patches;
+    if (patches != null) {
+      Procedure augmentedProcedure = _procedure;
+      int index = 0;
+      for (SourceProcedureBuilder patch in patches) {
+        if (!augmentedProcedure.isExternal && !augmentedProcedure.isAbstract) {
+          Procedure newProcedure = new Procedure(
+              augmentedName(augmentedProcedure.name.text,
+                  libraryBuilder.library, index++),
+              augmentedProcedure.kind,
+              augmentedProcedure.function,
+              fileUri: augmentedProcedure.fileUri)
+            ..fileOffset = augmentedProcedure.fileOffset
+            ..fileEndOffset = augmentedProcedure.fileEndOffset
+            ..fileStartOffset = augmentedProcedure.fileStartOffset
+            ..signatureType = augmentedProcedure.signatureType
+            ..flags = augmentedProcedure.flags;
+          f(newProcedure, BuiltMemberKind.Method);
+        }
+        augmentedProcedure = patch.actualProcedure;
+      }
+      finishProcedurePatch(procedure, augmentedProcedure);
 
-    finishProcedurePatch(origin.procedure, _procedure);
-    return 1;
+      return patches.length;
+    }
+    return 0;
   }
 
   @override
diff --git a/pkg/front_end/test/outline_extractor_suite.dart b/pkg/front_end/test/outline_extractor_suite.dart
index 42adf8c..a41a076 100644
--- a/pkg/front_end/test/outline_extractor_suite.dart
+++ b/pkg/front_end/test/outline_extractor_suite.dart
@@ -248,7 +248,7 @@
   }
 
   @override
-  bool checkProcedure_startFileOffset(
+  bool checkProcedure_fileStartOffset(
       EquivalenceVisitor visitor, Procedure node, Procedure other) {
     return true;
   }
diff --git a/pkg/front_end/test/outline_extractor_tester.dart b/pkg/front_end/test/outline_extractor_tester.dart
index 01fbca9..c77a98a 100644
--- a/pkg/front_end/test/outline_extractor_tester.dart
+++ b/pkg/front_end/test/outline_extractor_tester.dart
@@ -236,7 +236,7 @@
   }
 
   @override
-  bool checkProcedure_startFileOffset(
+  bool checkProcedure_fileStartOffset(
       EquivalenceVisitor visitor, Procedure node, Procedure other) {
     return true;
   }
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index eaad1d4..e401254 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -82,6 +82,7 @@
 augment
 augmentation
 augmentations
+augmented
 augmenting
 augments
 auto
diff --git a/pkg/front_end/testcases/macros/augment_concrete.dart b/pkg/front_end/testcases/macros/augment_concrete.dart
new file mode 100644
index 0000000..821e483
--- /dev/null
+++ b/pkg/front_end/testcases/macros/augment_concrete.dart
@@ -0,0 +1,31 @@
+// 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.
+
+import augment 'augment_concrete_lib1.dart';
+import augment 'augment_concrete_lib2.dart';
+
+void topLevelMethod() {
+  print('topLevelMethod original');
+}
+
+external void externalTopLevelMethod();
+
+class Class {
+  void instanceMethod() {
+    print('instanceMethod original');
+  }
+
+  static void staticMethod() {
+    print('staticMethod original');
+  }
+
+  external void externalInstanceMethod();
+}
+
+main() {
+  topLevelMethod();
+  new Class().instanceMethod();
+  Class.staticMethod();
+  new Class().externalInstanceMethod();
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/macros/augment_concrete.dart.strong.expect b/pkg/front_end/testcases/macros/augment_concrete.dart.strong.expect
new file mode 100644
index 0000000..83a035a
--- /dev/null
+++ b/pkg/front_end/testcases/macros/augment_concrete.dart.strong.expect
@@ -0,0 +1,51 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///augment_concrete.dart";
+import "org-dartlang-testcase:///augment_concrete.dart";
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ instanceMethod() → void {
+    core::print("instanceMethod augmentation 2");
+  }
+  static method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ staticMethod() → void {
+    core::print("staticMethod augmentation 2");
+  }
+  method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ externalInstanceMethod() → void {
+    core::print("externalInstanceMethod augmentation 2");
+  }
+  method _#instanceMethod#augment0() → void {
+    core::print("instanceMethod original");
+  }
+  method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#instanceMethod#augment1() → void {
+    core::print("instanceMethod augmentation 1");
+  }
+  static method _#staticMethod#augment0() → void {
+    core::print("staticMethod original");
+  }
+  static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#staticMethod#augment1() → void {
+    core::print("staticMethod augmentation 1");
+  }
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ topLevelMethod() → void {
+  core::print("topLevelMethod augmentation 2");
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ externalTopLevelMethod() → void {
+  core::print("externalTopLevelMethod augmentation 1");
+}
+static method main() → dynamic {
+  self::topLevelMethod();
+  new self::Class::•().{self::Class::instanceMethod}(){() → void};
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::externalInstanceMethod}(){() → void};
+}
+static method _#topLevelMethod#augment0() → void {
+  core::print("topLevelMethod original");
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#topLevelMethod#augment1() → void {
+  core::print("topLevelMethod augmentation 1");
+}
diff --git a/pkg/front_end/testcases/macros/augment_concrete.dart.strong.transformed.expect b/pkg/front_end/testcases/macros/augment_concrete.dart.strong.transformed.expect
new file mode 100644
index 0000000..83a035a
--- /dev/null
+++ b/pkg/front_end/testcases/macros/augment_concrete.dart.strong.transformed.expect
@@ -0,0 +1,51 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///augment_concrete.dart";
+import "org-dartlang-testcase:///augment_concrete.dart";
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ instanceMethod() → void {
+    core::print("instanceMethod augmentation 2");
+  }
+  static method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ staticMethod() → void {
+    core::print("staticMethod augmentation 2");
+  }
+  method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ externalInstanceMethod() → void {
+    core::print("externalInstanceMethod augmentation 2");
+  }
+  method _#instanceMethod#augment0() → void {
+    core::print("instanceMethod original");
+  }
+  method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#instanceMethod#augment1() → void {
+    core::print("instanceMethod augmentation 1");
+  }
+  static method _#staticMethod#augment0() → void {
+    core::print("staticMethod original");
+  }
+  static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#staticMethod#augment1() → void {
+    core::print("staticMethod augmentation 1");
+  }
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ topLevelMethod() → void {
+  core::print("topLevelMethod augmentation 2");
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ externalTopLevelMethod() → void {
+  core::print("externalTopLevelMethod augmentation 1");
+}
+static method main() → dynamic {
+  self::topLevelMethod();
+  new self::Class::•().{self::Class::instanceMethod}(){() → void};
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::externalInstanceMethod}(){() → void};
+}
+static method _#topLevelMethod#augment0() → void {
+  core::print("topLevelMethod original");
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#topLevelMethod#augment1() → void {
+  core::print("topLevelMethod augmentation 1");
+}
diff --git a/pkg/front_end/testcases/macros/augment_concrete.dart.textual_outline.expect b/pkg/front_end/testcases/macros/augment_concrete.dart.textual_outline.expect
new file mode 100644
index 0000000..68a15f5
--- /dev/null
+++ b/pkg/front_end/testcases/macros/augment_concrete.dart.textual_outline.expect
@@ -0,0 +1,10 @@
+import augment 'augment_concrete_lib1.dart';
+import augment 'augment_concrete_lib2.dart';
+void topLevelMethod() {}
+external void externalTopLevelMethod();
+class Class {
+  void instanceMethod() {}
+  static void staticMethod() {}
+  external void externalInstanceMethod();
+}
+main() {}
diff --git a/pkg/front_end/testcases/macros/augment_concrete.dart.weak.expect b/pkg/front_end/testcases/macros/augment_concrete.dart.weak.expect
new file mode 100644
index 0000000..83a035a
--- /dev/null
+++ b/pkg/front_end/testcases/macros/augment_concrete.dart.weak.expect
@@ -0,0 +1,51 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///augment_concrete.dart";
+import "org-dartlang-testcase:///augment_concrete.dart";
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ instanceMethod() → void {
+    core::print("instanceMethod augmentation 2");
+  }
+  static method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ staticMethod() → void {
+    core::print("staticMethod augmentation 2");
+  }
+  method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ externalInstanceMethod() → void {
+    core::print("externalInstanceMethod augmentation 2");
+  }
+  method _#instanceMethod#augment0() → void {
+    core::print("instanceMethod original");
+  }
+  method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#instanceMethod#augment1() → void {
+    core::print("instanceMethod augmentation 1");
+  }
+  static method _#staticMethod#augment0() → void {
+    core::print("staticMethod original");
+  }
+  static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#staticMethod#augment1() → void {
+    core::print("staticMethod augmentation 1");
+  }
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ topLevelMethod() → void {
+  core::print("topLevelMethod augmentation 2");
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ externalTopLevelMethod() → void {
+  core::print("externalTopLevelMethod augmentation 1");
+}
+static method main() → dynamic {
+  self::topLevelMethod();
+  new self::Class::•().{self::Class::instanceMethod}(){() → void};
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::externalInstanceMethod}(){() → void};
+}
+static method _#topLevelMethod#augment0() → void {
+  core::print("topLevelMethod original");
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#topLevelMethod#augment1() → void {
+  core::print("topLevelMethod augmentation 1");
+}
diff --git a/pkg/front_end/testcases/macros/augment_concrete.dart.weak.modular.expect b/pkg/front_end/testcases/macros/augment_concrete.dart.weak.modular.expect
new file mode 100644
index 0000000..83a035a
--- /dev/null
+++ b/pkg/front_end/testcases/macros/augment_concrete.dart.weak.modular.expect
@@ -0,0 +1,51 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///augment_concrete.dart";
+import "org-dartlang-testcase:///augment_concrete.dart";
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ instanceMethod() → void {
+    core::print("instanceMethod augmentation 2");
+  }
+  static method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ staticMethod() → void {
+    core::print("staticMethod augmentation 2");
+  }
+  method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ externalInstanceMethod() → void {
+    core::print("externalInstanceMethod augmentation 2");
+  }
+  method _#instanceMethod#augment0() → void {
+    core::print("instanceMethod original");
+  }
+  method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#instanceMethod#augment1() → void {
+    core::print("instanceMethod augmentation 1");
+  }
+  static method _#staticMethod#augment0() → void {
+    core::print("staticMethod original");
+  }
+  static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#staticMethod#augment1() → void {
+    core::print("staticMethod augmentation 1");
+  }
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ topLevelMethod() → void {
+  core::print("topLevelMethod augmentation 2");
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ externalTopLevelMethod() → void {
+  core::print("externalTopLevelMethod augmentation 1");
+}
+static method main() → dynamic {
+  self::topLevelMethod();
+  new self::Class::•().{self::Class::instanceMethod}(){() → void};
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::externalInstanceMethod}(){() → void};
+}
+static method _#topLevelMethod#augment0() → void {
+  core::print("topLevelMethod original");
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#topLevelMethod#augment1() → void {
+  core::print("topLevelMethod augmentation 1");
+}
diff --git a/pkg/front_end/testcases/macros/augment_concrete.dart.weak.outline.expect b/pkg/front_end/testcases/macros/augment_concrete.dart.weak.outline.expect
new file mode 100644
index 0000000..0c99b32
--- /dev/null
+++ b/pkg/front_end/testcases/macros/augment_concrete.dart.weak.outline.expect
@@ -0,0 +1,21 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///augment_concrete.dart";
+import "org-dartlang-testcase:///augment_concrete.dart";
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class
+    ;
+  method instanceMethod() → void
+    ;
+  static method staticMethod() → void
+    ;
+  external method externalInstanceMethod() → void;
+}
+static method topLevelMethod() → void
+  ;
+external static method externalTopLevelMethod() → void;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/macros/augment_concrete.dart.weak.transformed.expect b/pkg/front_end/testcases/macros/augment_concrete.dart.weak.transformed.expect
new file mode 100644
index 0000000..83a035a
--- /dev/null
+++ b/pkg/front_end/testcases/macros/augment_concrete.dart.weak.transformed.expect
@@ -0,0 +1,51 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///augment_concrete.dart";
+import "org-dartlang-testcase:///augment_concrete.dart";
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ instanceMethod() → void {
+    core::print("instanceMethod augmentation 2");
+  }
+  static method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ staticMethod() → void {
+    core::print("staticMethod augmentation 2");
+  }
+  method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ externalInstanceMethod() → void {
+    core::print("externalInstanceMethod augmentation 2");
+  }
+  method _#instanceMethod#augment0() → void {
+    core::print("instanceMethod original");
+  }
+  method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#instanceMethod#augment1() → void {
+    core::print("instanceMethod augmentation 1");
+  }
+  static method _#staticMethod#augment0() → void {
+    core::print("staticMethod original");
+  }
+  static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#staticMethod#augment1() → void {
+    core::print("staticMethod augmentation 1");
+  }
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib2.dart */ topLevelMethod() → void {
+  core::print("topLevelMethod augmentation 2");
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ externalTopLevelMethod() → void {
+  core::print("externalTopLevelMethod augmentation 1");
+}
+static method main() → dynamic {
+  self::topLevelMethod();
+  new self::Class::•().{self::Class::instanceMethod}(){() → void};
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::externalInstanceMethod}(){() → void};
+}
+static method _#topLevelMethod#augment0() → void {
+  core::print("topLevelMethod original");
+}
+static method /* from org-dartlang-testcase:///augment_concrete_lib1.dart */ _#topLevelMethod#augment1() → void {
+  core::print("topLevelMethod augmentation 1");
+}
diff --git a/pkg/front_end/testcases/macros/augment_concrete_lib1.dart b/pkg/front_end/testcases/macros/augment_concrete_lib1.dart
new file mode 100644
index 0000000..e036435
--- /dev/null
+++ b/pkg/front_end/testcases/macros/augment_concrete_lib1.dart
@@ -0,0 +1,21 @@
+// 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.
+
+augment void topLevelMethod() {
+  print('topLevelMethod augmentation 1');
+}
+
+augment void externalTopLevelMethod() {
+  print('externalTopLevelMethod augmentation 1');
+}
+
+augment class Class {
+  augment void instanceMethod() {
+    print('instanceMethod augmentation 1');
+  }
+
+  augment static void staticMethod() {
+    print('staticMethod augmentation 1');
+  }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/macros/augment_concrete_lib2.dart b/pkg/front_end/testcases/macros/augment_concrete_lib2.dart
new file mode 100644
index 0000000..de1bc9b
--- /dev/null
+++ b/pkg/front_end/testcases/macros/augment_concrete_lib2.dart
@@ -0,0 +1,21 @@
+// 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.
+
+augment void topLevelMethod() {
+  print('topLevelMethod augmentation 2');
+}
+
+augment class Class {
+  augment void instanceMethod() {
+    print('instanceMethod augmentation 2');
+  }
+
+  augment static void staticMethod() {
+    print('staticMethod augmentation 2');
+  }
+
+  augment void externalInstanceMethod() {
+    print('externalInstanceMethod augmentation 2');
+  }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/macros/augment_super.dart.strong.expect b/pkg/front_end/testcases/macros/augment_super.dart.strong.expect
index d309789..fa16fcc 100644
--- a/pkg/front_end/testcases/macros/augment_super.dart.strong.expect
+++ b/pkg/front_end/testcases/macros/augment_super.dart.strong.expect
@@ -122,6 +122,11 @@
     augment; // Error
     ^^^^^^^" in this{<unresolved>}.augment;
   }
+  method _#instanceMethod#augment0() → void {}
+  method _#instanceMethodErrors#augment0() → void {}
+  get _#instanceProperty#augment0() → core::int
+    return 42;
+  set _#instanceProperty#augment0(core::int value) → void {}
 }
 static method /* from org-dartlang-testcase:///augment_super_lib.dart */ topLevelMethod() → void {
   (null as{ForNonNullableByDefault} dynamic){dynamic}.call();
@@ -162,3 +167,7 @@
   augment; // Error
   ^^^^^^^";
 }
+static method _#topLevelMethod#augment0() → void {}
+static get _#topLevelProperty#augment0() → core::List<core::int>
+  return <core::int>[42];
+static set _#topLevelProperty#augment0(core::List<core::int> value) → void {}
diff --git a/pkg/front_end/testcases/macros/augment_super.dart.strong.transformed.expect b/pkg/front_end/testcases/macros/augment_super.dart.strong.transformed.expect
index e1236aa..7334815 100644
--- a/pkg/front_end/testcases/macros/augment_super.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/macros/augment_super.dart.strong.transformed.expect
@@ -122,6 +122,11 @@
     augment; // Error
     ^^^^^^^" in this{<unresolved>}.augment;
   }
+  method _#instanceMethod#augment0() → void {}
+  method _#instanceMethodErrors#augment0() → void {}
+  get _#instanceProperty#augment0() → core::int
+    return 42;
+  set _#instanceProperty#augment0(core::int value) → void {}
 }
 static method /* from org-dartlang-testcase:///augment_super_lib.dart */ topLevelMethod() → void {
   (null as{ForNonNullableByDefault} dynamic){dynamic}.call();
@@ -168,6 +173,10 @@
   augment; // Error
   ^^^^^^^";
 }
+static method _#topLevelMethod#augment0() → void {}
+static get _#topLevelProperty#augment0() → core::List<core::int>
+  return core::_GrowableList::_literal1<core::int>(42);
+static set _#topLevelProperty#augment0(core::List<core::int> value) → void {}
 
 
 Extra constant evaluation status:
@@ -177,4 +186,4 @@
 Evaluated: AsExpression @ org-dartlang-testcase:///augment_super_lib.dart:16:15 -> NullConstant(null)
 Evaluated: AsExpression @ org-dartlang-testcase:///augment_super_lib.dart:16:30 -> NullConstant(null)
 Evaluated: AsExpression @ org-dartlang-testcase:///augment_super_lib.dart:20:3 -> NullConstant(null)
-Extra constant evaluation: evaluated: 31, effectively constant: 6
+Extra constant evaluation: evaluated: 32, effectively constant: 6
diff --git a/pkg/front_end/testcases/macros/augment_super.dart.weak.expect b/pkg/front_end/testcases/macros/augment_super.dart.weak.expect
index d309789..fa16fcc 100644
--- a/pkg/front_end/testcases/macros/augment_super.dart.weak.expect
+++ b/pkg/front_end/testcases/macros/augment_super.dart.weak.expect
@@ -122,6 +122,11 @@
     augment; // Error
     ^^^^^^^" in this{<unresolved>}.augment;
   }
+  method _#instanceMethod#augment0() → void {}
+  method _#instanceMethodErrors#augment0() → void {}
+  get _#instanceProperty#augment0() → core::int
+    return 42;
+  set _#instanceProperty#augment0(core::int value) → void {}
 }
 static method /* from org-dartlang-testcase:///augment_super_lib.dart */ topLevelMethod() → void {
   (null as{ForNonNullableByDefault} dynamic){dynamic}.call();
@@ -162,3 +167,7 @@
   augment; // Error
   ^^^^^^^";
 }
+static method _#topLevelMethod#augment0() → void {}
+static get _#topLevelProperty#augment0() → core::List<core::int>
+  return <core::int>[42];
+static set _#topLevelProperty#augment0(core::List<core::int> value) → void {}
diff --git a/pkg/front_end/testcases/macros/augment_super.dart.weak.modular.expect b/pkg/front_end/testcases/macros/augment_super.dart.weak.modular.expect
index d309789..fa16fcc 100644
--- a/pkg/front_end/testcases/macros/augment_super.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/macros/augment_super.dart.weak.modular.expect
@@ -122,6 +122,11 @@
     augment; // Error
     ^^^^^^^" in this{<unresolved>}.augment;
   }
+  method _#instanceMethod#augment0() → void {}
+  method _#instanceMethodErrors#augment0() → void {}
+  get _#instanceProperty#augment0() → core::int
+    return 42;
+  set _#instanceProperty#augment0(core::int value) → void {}
 }
 static method /* from org-dartlang-testcase:///augment_super_lib.dart */ topLevelMethod() → void {
   (null as{ForNonNullableByDefault} dynamic){dynamic}.call();
@@ -162,3 +167,7 @@
   augment; // Error
   ^^^^^^^";
 }
+static method _#topLevelMethod#augment0() → void {}
+static get _#topLevelProperty#augment0() → core::List<core::int>
+  return <core::int>[42];
+static set _#topLevelProperty#augment0(core::List<core::int> value) → void {}
diff --git a/pkg/front_end/testcases/macros/augment_super.dart.weak.transformed.expect b/pkg/front_end/testcases/macros/augment_super.dart.weak.transformed.expect
index 6d9c5f8..c063461 100644
--- a/pkg/front_end/testcases/macros/augment_super.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/macros/augment_super.dart.weak.transformed.expect
@@ -122,6 +122,11 @@
     augment; // Error
     ^^^^^^^" in this{<unresolved>}.augment;
   }
+  method _#instanceMethod#augment0() → void {}
+  method _#instanceMethodErrors#augment0() → void {}
+  get _#instanceProperty#augment0() → core::int
+    return 42;
+  set _#instanceProperty#augment0(core::int value) → void {}
 }
 static method /* from org-dartlang-testcase:///augment_super_lib.dart */ topLevelMethod() → void {
   (null as{ForNonNullableByDefault} dynamic){dynamic}.call();
@@ -168,6 +173,10 @@
   augment; // Error
   ^^^^^^^";
 }
+static method _#topLevelMethod#augment0() → void {}
+static get _#topLevelProperty#augment0() → core::List<core::int>
+  return core::_GrowableList::_literal1<core::int>(42);
+static set _#topLevelProperty#augment0(core::List<core::int> value) → void {}
 
 
 Extra constant evaluation status:
@@ -177,4 +186,4 @@
 Evaluated: AsExpression @ org-dartlang-testcase:///augment_super_lib.dart:16:15 -> NullConstant(null)
 Evaluated: AsExpression @ org-dartlang-testcase:///augment_super_lib.dart:16:30 -> NullConstant(null)
 Evaluated: AsExpression @ org-dartlang-testcase:///augment_super_lib.dart:20:3 -> NullConstant(null)
-Extra constant evaluation: evaluated: 30, effectively constant: 6
+Extra constant evaluation: evaluated: 31, effectively constant: 6
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index 7be4428..d19b28b 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -112,6 +112,7 @@
 inference/unsafe_block_closure_inference_function_call_explicit_type_param_via_expr1: FormatterCrash
 late_lowering/later: FormatterCrash
 macros/augment_class: FormatterCrash
+macros/augment_concrete: FormatterCrash
 macros/augment_super: FormatterCrash
 macros/class_members: FormatterCrash
 macros/inject_constructor: FormatterCrash
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 93f8ea9..ae11a58 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -2904,7 +2904,7 @@
   /// Valid values are from 0 and up, or -1 ([TreeNode.noOffset]) if the file
   /// start offset is not available (this is the default if none is specifically
   /// set).
-  int startFileOffset = TreeNode.noOffset;
+  int fileStartOffset = TreeNode.noOffset;
 
   final ProcedureKind kind;
   int flags = 0;
@@ -2912,31 +2912,6 @@
   @override
   FunctionNode function;
 
-  // The function node's body might be lazily loaded, meaning that this value
-  // might not be set correctly yet. Make sure the body is loaded before
-  // returning anything.
-  @override
-  int get transformerFlags {
-    function.body;
-    return super.transformerFlags;
-  }
-
-  // The function node's body might be lazily loaded, meaning that this value
-  // might get overwritten later (when the body is read). To avoid that read the
-  // body now and only set the value afterwards.
-  @override
-  void set transformerFlags(int newValue) {
-    function.body;
-    super.transformerFlags = newValue;
-  }
-
-  // This function will set the transformer flags without loading the body.
-  // Used when reading the binary. For other cases one should probably use
-  // `transformerFlags = value;`.
-  void setTransformerFlagsWithoutLazyLoading(int newValue) {
-    super.transformerFlags = newValue;
-  }
-
   ProcedureStubKind stubKind;
   Reference? stubTargetReference;
 
@@ -3025,6 +3000,31 @@
         "$memberSignatureOrigin for $this.");
   }
 
+  // The function node's body might be lazily loaded, meaning that this value
+  // might not be set correctly yet. Make sure the body is loaded before
+  // returning anything.
+  @override
+  int get transformerFlags {
+    function.body;
+    return super.transformerFlags;
+  }
+
+  // The function node's body might be lazily loaded, meaning that this value
+  // might get overwritten later (when the body is read). To avoid that read the
+  // body now and only set the value afterwards.
+  @override
+  void set transformerFlags(int newValue) {
+    function.body;
+    super.transformerFlags = newValue;
+  }
+
+  // This function will set the transformer flags without loading the body.
+  // Used when reading the binary. For other cases one should probably use
+  // `transformerFlags = value;`.
+  void setTransformerFlagsWithoutLazyLoading(int newValue) {
+    super.transformerFlags = newValue;
+  }
+
   @override
   void bindCanonicalNames(CanonicalName parent) {
     parent.getChildFromProcedure(this).bindTo(reference);
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index cc22844..a4fd2ba 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -1706,7 +1706,7 @@
     }
     int transformerFlags = getAndResetTransformerFlags();
     assert(((_) => true)(debugPath.removeLast()));
-    node.startFileOffset = startFileOffset;
+    node.fileStartOffset = startFileOffset;
     node.fileOffset = fileOffset;
     node.fileEndOffset = fileEndOffset;
     node.flags = flags;
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 781c8ba..6b7c969 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -1348,7 +1348,7 @@
     writeByte(Tag.Procedure);
     _writeNonNullCanonicalName(canonicalName);
     writeUriReference(node.fileUri);
-    writeOffset(node.startFileOffset);
+    writeOffset(node.fileStartOffset);
     writeOffset(node.fileOffset);
     writeOffset(node.fileEndOffset);
     writeByte(node.kind.index);
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index d8f5c67b..2de4631 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -917,7 +917,7 @@
       ..annotations = cloneAnnotations && !node.annotations.isEmpty
           ? node.annotations.map(super.clone).toList()
           : const <Expression>[]
-      ..startFileOffset = _cloneFileOffset(node.startFileOffset)
+      ..fileStartOffset = _cloneFileOffset(node.fileStartOffset)
       ..fileOffset = _cloneFileOffset(node.fileOffset)
       ..fileEndOffset = _cloneFileOffset(node.fileEndOffset)
       ..flags = node.flags;
diff --git a/pkg/kernel/lib/src/equivalence.dart b/pkg/kernel/lib/src/equivalence.dart
index a5efbee..a1f334a 100644
--- a/pkg/kernel/lib/src/equivalence.dart
+++ b/pkg/kernel/lib/src/equivalence.dart
@@ -1786,7 +1786,7 @@
     }
     visitor.pushNodeState(node, other);
     bool result = true;
-    if (!checkProcedure_startFileOffset(visitor, node, other)) {
+    if (!checkProcedure_fileStartOffset(visitor, node, other)) {
       result = visitor.resultOnInequivalence;
     }
     if (!checkProcedure_kind(visitor, node, other)) {
@@ -5172,10 +5172,10 @@
     return checkMember_fileOffset(visitor, node, other);
   }
 
-  bool checkProcedure_startFileOffset(
+  bool checkProcedure_fileStartOffset(
       EquivalenceVisitor visitor, Procedure node, Procedure other) {
     return visitor.checkValues(
-        node.startFileOffset, other.startFileOffset, 'startFileOffset');
+        node.fileStartOffset, other.fileStartOffset, 'fileStartOffset');
   }
 
   bool checkProcedure_kind(