Add a tool to write all combined macro generated content.

Change-Id: I08554397016255bff82e6c420b8795999ba5990f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/210427
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/tool/macro/generate.dart b/pkg/analyzer/tool/macro/generate.dart
new file mode 100644
index 0000000..2cc9a41
--- /dev/null
+++ b/pkg/analyzer/tool/macro/generate.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' as io;
+
+import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/util/file_paths.dart' as file_paths;
+
+void main(List<String> arguments) async {
+  if (arguments.length != 1) {
+    _printUsage();
+    io.exit(1);
+  }
+
+  var resourceProvider = PhysicalResourceProvider.INSTANCE;
+  var pathContext = resourceProvider.pathContext;
+
+  // The directory must exist.
+  var packagePath = arguments[0];
+  var packageFolder = resourceProvider.getFolder(packagePath);
+  if (!packageFolder.exists) {
+    print('Error: $packagePath does not exist.');
+    io.exit(1);
+  }
+
+  // The directory must be a Pub package.
+  var pubspecYamlFile = packageFolder.getChildAssumingFile(
+    file_paths.pubspecYaml,
+  );
+  if (!pubspecYamlFile.exists) {
+    print('Error: ${pubspecYamlFile.path} does not exist.');
+    io.exit(1);
+  }
+
+  var collection = AnalysisContextCollection(
+    includedPaths: [packagePath],
+  );
+  for (var analysisContext in collection.contexts) {
+    var analyzedPaths = analysisContext.contextRoot.analyzedFiles();
+    for (var path in analyzedPaths) {
+      if (file_paths.isDart(pathContext, path)) {
+        var session = analysisContext.currentSession;
+        var unitElementResult = await session.getUnitElement(path);
+        if (unitElementResult is UnitElementResult) {
+          var unitElement =
+              unitElementResult.element as CompilationUnitElementImpl;
+          // If has macro-generated content, write it.
+          var macroGeneratedContent = unitElement.macroGeneratedContent;
+          if (macroGeneratedContent != null) {
+            var relativePath = pathContext.relative(path, from: packagePath);
+            var combinedPath = pathContext.join(
+                packagePath, '.dart_tool', 'analyzer', 'macro', relativePath);
+            resourceProvider.getFile(combinedPath)
+              ..parent2.create()
+              ..writeAsStringSync(macroGeneratedContent);
+          }
+        }
+      }
+    }
+  }
+}
+
+void _printUsage() {
+  print('''
+Usage: dart generate.dart path-to-pub-package
+Write combined code of files that have macro-generated declarations.
+''');
+}