don't report `prefer_const_constructors_in_immutables` on macro constructors

Fixes: https://github.com/dart-lang/linter/issues/4966

Change-Id: I4aee65dc62df509833796100ca6f86b904fc72ad
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/365860
Commit-Queue: Phil Quitslund <pquitslund@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/linter/lib/src/extensions.dart b/pkg/linter/lib/src/extensions.dart
index 40cff5b..e3ed364 100644
--- a/pkg/linter/lib/src/extensions.dart
+++ b/pkg/linter/lib/src/extensions.dart
@@ -8,9 +8,11 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/src/dart/ast/ast.dart'; // ignore: implementation_imports
+import 'package:analyzer/src/dart/element/element.dart'; // ignore: implementation_imports
 import 'package:analyzer/src/dart/element/member.dart'; // ignore: implementation_imports
-// ignore: implementation_imports
-import 'package:analyzer/src/dart/element/type.dart' show InvalidTypeImpl;
+import 'package:analyzer/src/dart/element/type.dart' // ignore: implementation_imports
+    show
+        InvalidTypeImpl;
 import 'package:collection/collection.dart';
 
 import 'analyzer.dart';
@@ -337,6 +339,11 @@
     }
     return self;
   }
+
+  bool get isMacro {
+    var self = this;
+    return self is ClassElementImpl && self.isMacro;
+  }
 }
 
 extension ExpressionExtension on Expression? {
diff --git a/pkg/linter/lib/src/rules/prefer_const_constructors_in_immutables.dart b/pkg/linter/lib/src/rules/prefer_const_constructors_in_immutables.dart
index f52de28..1015aed 100644
--- a/pkg/linter/lib/src/rules/prefer_const_constructors_in_immutables.dart
+++ b/pkg/linter/lib/src/rules/prefer_const_constructors_in_immutables.dart
@@ -9,6 +9,7 @@
 import 'package:collection/collection.dart' show IterableExtension;
 
 import '../analyzer.dart';
+import '../extensions.dart';
 
 const _desc = r'Prefer declaring `const` constructors on `@immutable` classes.';
 
@@ -74,8 +75,10 @@
     if (element == null) return;
     if (element.isConst) return;
     if (node.body is! EmptyFunctionBody) return;
-    if (element.enclosingElement.mixins.isNotEmpty) return;
-    if (!_hasImmutableAnnotation(element.enclosingElement)) return;
+    var enclosingElement = element.enclosingElement;
+    if (enclosingElement.isMacro) return;
+    if (enclosingElement.mixins.isNotEmpty) return;
+    if (!_hasImmutableAnnotation(enclosingElement)) return;
     var isRedirected =
         element.isFactory && element.redirectedConstructor != null;
     if (isRedirected && (element.redirectedConstructor?.isConst ?? false)) {
diff --git a/pkg/linter/test/rule_test_support.dart b/pkg/linter/test/rule_test_support.dart
index c4d93e3..352ad6c 100644
--- a/pkg/linter/test/rule_test_support.dart
+++ b/pkg/linter/test/rule_test_support.dart
@@ -764,6 +764,12 @@
     );
   }
 
+  @mustCallSuper
+  Future<void> tearDown() async {
+    await _analysisContextCollection?.dispose();
+    _analysisContextCollection = null;
+  }
+
   DriverBasedAnalysisContext _contextFor(String path) {
     _createAnalysisContexts();
 
diff --git a/pkg/linter/test/rules/prefer_const_constructors_in_immutables_test.dart b/pkg/linter/test/rules/prefer_const_constructors_in_immutables_test.dart
index 5d28692..82d8467 100644
--- a/pkg/linter/test/rules/prefer_const_constructors_in_immutables_test.dart
+++ b/pkg/linter/test/rules/prefer_const_constructors_in_immutables_test.dart
@@ -392,6 +392,19 @@
     ]);
   }
 
+  test_macroConstructor() async {
+    await assertDiagnostics(r'''
+import 'package:meta/meta.dart';
+
+@immutable
+macro class M {
+  M();
+}
+''', [
+      // TODO(pq): add non-const constructor compilation error when implemented
+    ]);
+  }
+
   test_returnOfInvalidType() async {
     await assertDiagnostics(r'''
 import 'package:meta/meta.dart';