analyzer: expose canBeConst and computeConstantValue as public API

Work towards https://github.com/dart-lang/sdk/issues/50986

These utilities are used by a handful of lint rules, and the analysis
server, which makes me think they could be offered as public API.

Change-Id: I12415c2b86ca6fb96b03def4a304da73c6fb4cae
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/430300
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
diff --git a/pkg/analysis_server/lib/src/computer/computer_color.dart b/pkg/analysis_server/lib/src/computer/computer_color.dart
index 19061c1..0d8294e 100644
--- a/pkg/analysis_server/lib/src/computer/computer_color.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_color.dart
@@ -9,7 +9,6 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/constant/value.dart' show GenericState;
-import 'package:analyzer/src/lint/constants.dart';
 import 'package:analyzer/src/utilities/extensions/flutter.dart';
 import 'package:collection/collection.dart';
 import 'package:path/path.dart' as path;
@@ -51,8 +50,12 @@
 
     // Try to evaluate the constant target.
     var colorConstResult = target.computeConstantValue();
-    var colorConst = colorConstResult.value;
-    if (colorConstResult.errors.isNotEmpty || colorConst == null) return false;
+    var colorConst = colorConstResult?.value;
+    if (colorConstResult == null ||
+        colorConstResult.diagnostics.isNotEmpty ||
+        colorConst == null) {
+      return false;
+    }
 
     // If we want a specific member or swatch index, read that.
     if (memberName != null) {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/custom/editable_arguments/handler_editable_arguments.dart b/pkg/analysis_server/lib/src/lsp/handlers/custom/editable_arguments/handler_editable_arguments.dart
index 7394ae8..1b60b1f 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/custom/editable_arguments/handler_editable_arguments.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/custom/editable_arguments/handler_editable_arguments.dart
@@ -16,7 +16,6 @@
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/lint/constants.dart';
 
 /// Information about the values for a parameter/argument.
 typedef _Values = ({DartObject? parameterValue, DartObject? argumentValue});
@@ -147,7 +146,7 @@
     Expression? argumentExpression,
   ) {
     var parameterValue = parameter.computeConstantValue();
-    var argumentValue = argumentExpression?.computeConstantValue().value;
+    var argumentValue = argumentExpression?.computeConstantValue()?.value;
 
     return (parameterValue: parameterValue, argumentValue: argumentValue);
   }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart
index 145d59a..a325889 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_const.dart
@@ -9,7 +9,6 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/source/source_range.dart';
-import 'package:analyzer/src/lint/constants.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/replace_with_decorated_box.dart b/pkg/analysis_server/lib/src/services/correction/dart/replace_with_decorated_box.dart
index 311f854..97cb76f 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/replace_with_decorated_box.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/replace_with_decorated_box.dart
@@ -7,7 +7,6 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/lint/constants.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
diff --git a/pkg/analyzer/api.txt b/pkg/analyzer/api.txt
index 4f3d512..26a14d6 100644
--- a/pkg/analyzer/api.txt
+++ b/pkg/analyzer/api.txt
@@ -1058,12 +1058,14 @@
     exportKeyword (getter: Token)
     libraryExport (getter: LibraryExport?, experimental)
   Expression (class extends Object implements CollectionElement):
+    canBeConst (getter: bool)
     correspondingParameter (getter: FormalParameterElement?, experimental)
     inConstantContext (getter: bool)
     isAssignable (getter: bool)
     precedence (getter: Precedence)
     staticType (getter: DartType?)
     unParenthesized (getter: Expression)
+    computeConstantValue (method: AttemptedConstantEvaluationResult? Function())
   ExpressionFunctionBody (class extends Object implements FunctionBody):
     expression (getter: Expression)
     functionDefinition (getter: Token)
@@ -5106,6 +5108,10 @@
     status (getter: FeatureStatus)
     stringForValue (method: String Function(bool))
     toString (method: String Function())
+package:analyzer/src/dart/ast/ast.dart:
+  AttemptedConstantEvaluationResult (class extends Object):
+    diagnostics (getter: List<Diagnostic>)
+    value (getter: DartObject?)
 package:analyzer/src/dart/constant/evaluation.dart:
   ConstantEvaluationTarget (class extends Object):
     new (constructor: ConstantEvaluationTarget Function())
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index bb023ac..004133a 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -19,21 +19,31 @@
 import 'package:analyzer/dart/ast/precedence.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/constant/value.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/scope.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/diagnostic/diagnostic.dart';
+import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer/src/dart/ast/to_source_visitor.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/constant/compute.dart';
+import 'package:analyzer/src/dart/constant/evaluation.dart';
+import 'package:analyzer/src/dart/constant/utilities.dart';
+import 'package:analyzer/src/dart/constant/value.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_schema.dart';
 import 'package:analyzer/src/dart/resolver/body_inference_context.dart';
 import 'package:analyzer/src/dart/resolver/typed_literal_resolver.dart';
+import 'package:analyzer/src/error/codes.g.dart';
 import 'package:analyzer/src/fasta/token_utils.dart' as util show findPrevious;
 import 'package:analyzer/src/generated/inference_log.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/lint/constants.dart';
 import 'package:analyzer/src/utilities/extensions/object.dart';
 import 'package:collection/collection.dart';
 import 'package:meta/meta.dart';
@@ -1865,6 +1875,21 @@
   R? visitYieldStatement(YieldStatement node);
 }
 
+/// The result of attempting to evaluate an expression as a constant.
+@AnalyzerPublicApi(message: 'exported by lib/dart/ast/ast.dart')
+final class AttemptedConstantEvaluationResult {
+  /// The value of the expression, or `null` if has [diagnostics].
+  ///
+  /// If evaluating a constant expression yields diagnostics, then the value of
+  /// the constant expression cannot be calculated.
+  final DartObject? value;
+
+  /// The diagnostics reported during the evaluation.
+  final List<Diagnostic> diagnostics;
+
+  AttemptedConstantEvaluationResult._(this.value, this.diagnostics);
+}
+
 /// The augmented expression.
 ///
 /// It is created only inside an augmentation.
@@ -8007,6 +8032,12 @@
 ///      | [ThrowExpression]
 @AnalyzerPublicApi(message: 'exported by lib/dart/ast/ast.dart')
 abstract final class Expression implements CollectionElement {
+  /// Whether it would be valid for this expression to have a `const` keyword.
+  ///
+  /// Note that this method can cause constant evaluation to occur, which can be
+  /// computationally expensive.
+  bool get canBeConst;
+
   /// The parameter element representing the parameter to which the value of
   /// this expression is bound.
   ///
@@ -8064,6 +8095,14 @@
   /// unwrapping the expression inside the parentheses. Otherwise, returns this
   /// expression.
   Expression get unParenthesized;
+
+  /// Computes the constant value of this expression, if it has one.
+  ///
+  /// Returns a [AttemptedConstantEvaluationResult], containing both the computed
+  /// constant value, and a list of errors that occurred during the computation.
+  ///
+  /// Returns `null` if this expression is not a constant expression.
+  AttemptedConstantEvaluationResult? computeConstantValue();
 }
 
 /// A function body consisting of a single expression.
@@ -8215,6 +8254,9 @@
     implements CollectionElementImpl, Expression {
   TypeImpl? _staticType;
 
+  @override
+  bool get canBeConst => false;
+
   @experimental
   @override
   FormalParameterElementMixin? get correspondingParameter {
@@ -8264,6 +8306,53 @@
   @override
   ExpressionImpl get unParenthesized => this;
 
+  @override
+  AttemptedConstantEvaluationResult? computeConstantValue() {
+    var unitNode = thisOrAncestorOfType<CompilationUnitImpl>();
+    var unitFragment = unitNode?.declaredFragment;
+    if (unitFragment == null) {
+      throw ArgumentError('This AST structure has not yet been resolved.');
+    }
+
+    var libraryElement = unitFragment.element;
+    var declaredVariables = libraryElement.session.declaredVariables;
+
+    var evaluationEngine = ConstantEvaluationEngine(
+      declaredVariables: declaredVariables,
+      configuration: ConstantEvaluationConfiguration(),
+    );
+
+    var dependencies = <ConstantEvaluationTarget>[];
+    accept(ReferenceFinder(dependencies.add));
+
+    computeConstants(
+      declaredVariables: declaredVariables,
+      constants: dependencies,
+      featureSet: libraryElement.featureSet,
+      configuration: ConstantEvaluationConfiguration(),
+    );
+
+    var errorListener = RecordingErrorListener();
+    var visitor = ConstantVisitor(
+      evaluationEngine,
+      libraryElement,
+      ErrorReporter(errorListener, unitFragment.source),
+    );
+
+    var constant = visitor.evaluateAndReportInvalidConstant(this);
+    var isInvalidConstant = errorListener.errors.any(
+      (e) => e.errorCode == CompileTimeErrorCode.INVALID_CONSTANT,
+    );
+    if (isInvalidConstant) {
+      return null;
+    }
+
+    return AttemptedConstantEvaluationResult._(
+      constant is DartObjectImpl ? constant : null,
+      errorListener.errors,
+    );
+  }
+
   /// Returns the [AstNode] that puts node into the constant context, and
   /// the explicit `const` keyword of that node. The keyword might be absent
   /// if the constness is implicit.
@@ -14057,6 +14146,25 @@
     return constructorName.beginToken;
   }
 
+  @override
+  bool get canBeConst {
+    var element = constructorName.element;
+    if (element == null || !element.isConst) return false;
+
+    // Ensure that dependencies (e.g. default parameter values) are computed.
+    element.baseElement.computeConstantDependencies();
+
+    // Verify that the evaluation of the constructor would not produce an
+    // exception.
+    var oldKeyword = keyword;
+    try {
+      keyword = KeywordToken(Keyword.CONST, offset);
+      return !hasConstantVerifierError;
+    } finally {
+      keyword = oldKeyword;
+    }
+  }
+
   @generated
   @override
   ConstructorNameImpl get constructorName => _constructorName;
@@ -24541,6 +24649,17 @@
   }
 
   @override
+  bool get canBeConst {
+    var oldKeyword = constKeyword;
+    try {
+      constKeyword = KeywordToken(Keyword.CONST, offset);
+      return !hasConstantVerifierError;
+    } finally {
+      constKeyword = oldKeyword;
+    }
+  }
+
+  @override
   bool get isConst {
     return constKeyword != null || inConstantContext;
   }
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index b1360ee..6c1639f 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -33,7 +33,6 @@
 import 'package:analyzer/src/error/must_call_super_verifier.dart';
 import 'package:analyzer/src/error/null_safe_api_verifier.dart';
 import 'package:analyzer/src/error/widget_preview_verifier.dart';
-import 'package:analyzer/src/lint/constants.dart';
 import 'package:analyzer/src/utilities/extensions/ast.dart';
 import 'package:analyzer/src/utilities/extensions/element.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
@@ -873,7 +872,7 @@
     var alreadySeen = <DartObject>{};
     for (var expression in expressions) {
       var constEvaluation = expression.computeConstantValue();
-      if (constEvaluation.errors.isEmpty) {
+      if (constEvaluation != null && constEvaluation.diagnostics.isEmpty) {
         var value = constEvaluation.value;
         if (value != null && !alreadySeen.add(value)) {
           var errorCode =
diff --git a/pkg/analyzer/lib/src/lint/constants.dart b/pkg/analyzer/lib/src/lint/constants.dart
index 9f2aae2..1bbe1b8 100644
--- a/pkg/analyzer/lib/src/lint/constants.dart
+++ b/pkg/analyzer/lib/src/lint/constants.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/dart/constant/value.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/diagnostic/diagnostic.dart';
 import 'package:analyzer/error/error.dart';
@@ -15,21 +14,8 @@
 import 'package:analyzer/src/dart/constant/evaluation.dart';
 import 'package:analyzer/src/dart/constant/potentially_constant.dart';
 import 'package:analyzer/src/dart/constant/utilities.dart';
-import 'package:analyzer/src/dart/constant/value.dart';
 import 'package:analyzer/src/error/codes.dart';
 
-/// The result of attempting to evaluate an expression as a constant.
-final class LinterConstantEvaluationResult {
-  /// The value of the expression, or `null` if has [errors].
-  final DartObject? value;
-
-  /// The errors reported during the evaluation.
-  // TODO(srawlins): Rename to `diagnostics`.
-  final List<Diagnostic> errors;
-
-  LinterConstantEvaluationResult._(this.value, this.errors);
-}
-
 /// An error listener that only records whether any constant related errors have
 /// been reported.
 class _ConstantAnalysisErrorListener extends AnalysisErrorListener {
@@ -39,9 +25,9 @@
 
   @override
   void onError(Diagnostic error) {
-    DiagnosticCode errorCode = error.errorCode;
-    if (errorCode is CompileTimeErrorCode) {
-      switch (errorCode) {
+    DiagnosticCode diagnosticCode = error.errorCode;
+    if (diagnosticCode is CompileTimeErrorCode) {
+      switch (diagnosticCode) {
         case CompileTimeErrorCode
             .CONST_CONSTRUCTOR_CONSTANT_FROM_DEFERRED_LIBRARY:
         case CompileTimeErrorCode
@@ -85,7 +71,7 @@
   }
 }
 
-extension on AstNode {
+extension AstNodeExtension on AstNode {
   /// Whether [ConstantVerifier] reports an error when computing the value of
   /// `this` as a constant.
   bool get hasConstantVerifierError {
@@ -134,88 +120,3 @@
     }
   }
 }
-
-extension ExpressionExtension on Expression {
-  /// Whether it would be valid for this expression to have a `const` keyword.
-  ///
-  /// Note that this method can cause constant evaluation to occur, which can be
-  /// computationally expensive.
-  bool get canBeConst {
-    var self = this;
-    return switch (self) {
-      InstanceCreationExpressionImpl() => _canBeConstInstanceCreation(self),
-      TypedLiteralImpl() => _canBeConstTypedLiteral(self),
-      _ => false,
-    };
-  }
-
-  /// Computes the constant value of `this`, if it has one.
-  ///
-  /// Returns a [LinterConstantEvaluationResult], containing both the computed
-  /// constant value, and a list of errors that occurred during the computation.
-  LinterConstantEvaluationResult computeConstantValue() {
-    var unitNode = thisOrAncestorOfType<CompilationUnitImpl>();
-    var unitFragment = unitNode?.declaredFragment;
-    if (unitFragment == null) {
-      return LinterConstantEvaluationResult._(null, []);
-    }
-
-    var libraryElement = unitFragment.element;
-    var declaredVariables = libraryElement.session.declaredVariables;
-
-    var evaluationEngine = ConstantEvaluationEngine(
-      declaredVariables: declaredVariables,
-      configuration: ConstantEvaluationConfiguration(),
-    );
-
-    var dependencies = <ConstantEvaluationTarget>[];
-    accept(ReferenceFinder(dependencies.add));
-
-    computeConstants(
-      declaredVariables: declaredVariables,
-      constants: dependencies,
-      featureSet: libraryElement.featureSet,
-      configuration: ConstantEvaluationConfiguration(),
-    );
-
-    var errorListener = RecordingErrorListener();
-    var visitor = ConstantVisitor(
-      evaluationEngine,
-      libraryElement,
-      ErrorReporter(errorListener, unitFragment.source),
-    );
-
-    var constant = visitor.evaluateAndReportInvalidConstant(this);
-    var dartObject = constant is DartObjectImpl ? constant : null;
-    return LinterConstantEvaluationResult._(dartObject, errorListener.errors);
-  }
-
-  bool _canBeConstInstanceCreation(InstanceCreationExpressionImpl node) {
-    var element = node.constructorName.element;
-    if (element == null || !element.isConst) return false;
-
-    // Ensure that dependencies (e.g. default parameter values) are computed.
-    var implElement = element.baseElement;
-    implElement.computeConstantDependencies();
-
-    // Verify that the evaluation of the constructor would not produce an
-    // exception.
-    var oldKeyword = node.keyword;
-    try {
-      node.keyword = KeywordToken(Keyword.CONST, offset);
-      return !hasConstantVerifierError;
-    } finally {
-      node.keyword = oldKeyword;
-    }
-  }
-
-  bool _canBeConstTypedLiteral(TypedLiteralImpl node) {
-    var oldKeyword = node.constKeyword;
-    try {
-      node.constKeyword = KeywordToken(Keyword.CONST, offset);
-      return !hasConstantVerifierError;
-    } finally {
-      node.constKeyword = oldKeyword;
-    }
-  }
-}
diff --git a/pkg/analyzer/lib/utilities/extensions/ast.dart b/pkg/analyzer/lib/utilities/extensions/ast.dart
index 9edf319..9a90ef7 100644
--- a/pkg/analyzer/lib/utilities/extensions/ast.dart
+++ b/pkg/analyzer/lib/utilities/extensions/ast.dart
@@ -2,7 +2,7 @@
 // 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 
 @Deprecated('Use the method defined on `CompilationUnit` instead.')
 extension AstNodeExtension on AstNode {
diff --git a/pkg/analyzer/test/src/dart/ast/ast_test.dart b/pkg/analyzer/test/src/dart/ast/ast_test.dart
index fc46945..926e521 100644
--- a/pkg/analyzer/test/src/dart/ast/ast_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/ast_test.dart
@@ -13,6 +13,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(CompilationUnitImplTest);
+    defineReflectiveTests(EvaluateExpressionTest);
     defineReflectiveTests(ExpressionImplTest);
     defineReflectiveTests(InstanceCreationExpressionImplTest);
     defineReflectiveTests(IntegerLiteralImplTest);
@@ -108,6 +109,108 @@
 }
 
 @reflectiveTest
+class EvaluateExpressionTest extends PubPackageResolutionTest {
+  test_hasError_listLiteral_forElement() async {
+    await resolveTestCode('''
+var x = const [for (var i = 0; i < 4; i++) i];
+''');
+    var result = _evaluateX();
+    expect(result, isNotNull);
+    expect(result!.diagnostics, isNotEmpty);
+    expect(result.value, isNull);
+  }
+
+  test_hasError_mapLiteral_forElement() async {
+    await resolveTestCode('''
+var x = const {for (var i = 0; i < 4; i++) i: 0};
+''');
+    var result = _evaluateX();
+    expect(result, isNotNull);
+    expect(result?.diagnostics, isNotEmpty);
+    expect(result?.value, isNull);
+  }
+
+  test_hasError_methodInvocation() async {
+    await resolveTestCode('''
+var x = 42.abs();
+''');
+    var result = _evaluateX();
+    expect(result, isNotNull);
+    expect(result!.diagnostics, isNotEmpty);
+    expect(result.value, isNull);
+  }
+
+  test_hasError_setLiteral_forElement() async {
+    await resolveTestCode('''
+var x = const {for (var i = 0; i < 4; i++) i};
+''');
+    var result = _evaluateX();
+    expect(result, isNotNull);
+    expect(result!.diagnostics, isNotEmpty);
+    expect(result.value, isNull);
+  }
+
+  test_hasValue_binaryExpression() async {
+    await resolveTestCode('''
+var x = 1 + 2;
+''');
+    var result = _evaluateX();
+    expect(result, isNotNull);
+    expect(result!.diagnostics, isEmpty);
+    expect(result.value!.toIntValue(), 3);
+  }
+
+  test_hasValue_constantReference() async {
+    await resolveTestCode('''
+const a = 42;
+var x = a;
+''');
+    var result = _evaluateX();
+    expect(result, isNotNull);
+    expect(result!.diagnostics, isEmpty);
+    expect(result.value!.toIntValue(), 42);
+  }
+
+  test_hasValue_constantReference_imported() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+const a = 42;
+''');
+    await resolveTestCode('''
+import 'a.dart';
+var x = a;
+''');
+    var result = _evaluateX();
+    expect(result, isNotNull);
+    expect(result!.diagnostics, isEmpty);
+    expect(result.value!.toIntValue(), 42);
+  }
+
+  test_hasValue_intLiteral() async {
+    await resolveTestCode('''
+var x = 42;
+''');
+    var result = _evaluateX();
+    expect(result, isNotNull);
+    expect(result!.diagnostics, isEmpty);
+    expect(result.value!.toIntValue(), 42);
+  }
+
+  test_nonConstant() async {
+    await resolveTestCode('''
+var a = 42;
+var x = a;
+''');
+    var result = _evaluateX();
+    expect(result, isNull);
+  }
+
+  AttemptedConstantEvaluationResult? _evaluateX() {
+    var node = findNode.topVariableDeclarationByName('x').initializer!;
+    return node.computeConstantValue();
+  }
+}
+
+@reflectiveTest
 class ExpressionImplTest extends ParserTestCase {
   late final String testSource;
   late final CompilationUnitImpl testUnit;
diff --git a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
index 13878ec..dc1a9bb 100644
--- a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
+++ b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
@@ -19,7 +19,6 @@
     defineReflectiveTests(CanBeConstConstructorTest);
     defineReflectiveTests(CanBeConstInstanceCreationTest);
     defineReflectiveTests(CanBeConstTypedLiteralTest);
-    defineReflectiveTests(EvaluateExpressionTest);
     defineReflectiveTests(PubDependencyTest);
   });
 }
@@ -512,91 +511,6 @@
 }
 
 @reflectiveTest
-class EvaluateExpressionTest extends AbstractLinterContextTest {
-  test_hasError_listLiteral_forElement() async {
-    await resolve('''
-var x = const [for (var i = 0; i < 4; i++) i];
-''');
-    var result = _evaluateX();
-    expect(result.errors, isNotEmpty);
-    expect(result.value, isNull);
-  }
-
-  test_hasError_mapLiteral_forElement() async {
-    await resolve('''
-var x = const {for (var i = 0; i < 4; i++) i: 0};
-''');
-    var result = _evaluateX();
-    expect(result.errors, isNotEmpty);
-    expect(result.value, isNull);
-  }
-
-  test_hasError_methodInvocation() async {
-    await resolve('''
-var x = 42.abs();
-''');
-    var result = _evaluateX();
-    expect(result.errors, isNotEmpty);
-    expect(result.value, isNull);
-  }
-
-  test_hasError_setLiteral_forElement() async {
-    await resolve('''
-var x = const {for (var i = 0; i < 4; i++) i};
-''');
-    var result = _evaluateX();
-    expect(result.errors, isNotEmpty);
-    expect(result.value, isNull);
-  }
-
-  test_hasValue_binaryExpression() async {
-    await resolve('''
-var x = 1 + 2;
-''');
-    var result = _evaluateX();
-    expect(result.errors, isEmpty);
-    expect(result.value!.toIntValue(), 3);
-  }
-
-  test_hasValue_constantReference() async {
-    await resolve('''
-const a = 42;
-var x = a;
-''');
-    var result = _evaluateX();
-    expect(result.errors, isEmpty);
-    expect(result.value!.toIntValue(), 42);
-  }
-
-  test_hasValue_constantReference_imported() async {
-    newFile('$testPackageLibPath/a.dart', r'''
-const a = 42;
-''');
-    await resolve('''
-import 'a.dart';
-var x = a;
-''');
-    var result = _evaluateX();
-    expect(result.errors, isEmpty);
-    expect(result.value!.toIntValue(), 42);
-  }
-
-  test_hasValue_intLiteral() async {
-    await resolve('''
-var x = 42;
-''');
-    var result = _evaluateX();
-    expect(result.errors, isEmpty);
-    expect(result.value!.toIntValue(), 42);
-  }
-
-  LinterConstantEvaluationResult _evaluateX() {
-    var node = findNode.topVariableDeclarationByName('x').initializer!;
-    return node.computeConstantValue();
-  }
-}
-
-@reflectiveTest
 class PubDependencyTest extends AbstractLinterContextTest {
   test_dependencies() async {
     newPubspecYamlFile(testPackageRootPath, '''
diff --git a/pkg/linter/lib/src/ast.dart b/pkg/linter/lib/src/ast.dart
index 64a4731..5063ecd 100644
--- a/pkg/linter/lib/src/ast.dart
+++ b/pkg/linter/lib/src/ast.dart
@@ -12,8 +12,6 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/visitor2.dart';
 import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/lint/constants.dart' // ignore: implementation_imports
-    show ExpressionExtension;
 import 'package:analyzer/workspace/workspace.dart';
 import 'package:path/path.dart' as path;
 
@@ -125,7 +123,7 @@
     _getWriteElement(node) ?? node.element;
 
 bool hasConstantError(Expression node) =>
-    node.computeConstantValue().errors.isNotEmpty;
+    node.computeConstantValue()?.diagnostics.isNotEmpty ?? true;
 
 /// Returns `true` if this element is the `==` method declaration.
 bool isEquals(ClassMember element) =>
@@ -317,7 +315,7 @@
   if (expression is IntegerLiteral) {
     value = expression.value;
   } else if (expression is SimpleIdentifier && context != null) {
-    value = expression.computeConstantValue().value?.toIntValue();
+    value = expression.computeConstantValue()?.value?.toIntValue();
   }
   if (value is! int) return null;
 
diff --git a/pkg/linter/lib/src/rules/avoid_redundant_argument_values.dart b/pkg/linter/lib/src/rules/avoid_redundant_argument_values.dart
index 79643e1..6c7fe0e 100644
--- a/pkg/linter/lib/src/rules/avoid_redundant_argument_values.dart
+++ b/pkg/linter/lib/src/rules/avoid_redundant_argument_values.dart
@@ -7,8 +7,6 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/lint/constants.dart' // ignore: implementation_imports
-    show ExpressionExtension;
 import 'package:collection/collection.dart';
 
 import '../analyzer.dart';
@@ -76,7 +74,7 @@
     //   rule.reportLint(arg);
     // } else ...
     if (value != null && value.hasKnownValue) {
-      var expressionValue = arg.computeConstantValue().value;
+      var expressionValue = arg.computeConstantValue()?.value;
       if ((expressionValue?.hasKnownValue ?? false) &&
           expressionValue == value) {
         rule.reportAtNode(arg);
diff --git a/pkg/linter/lib/src/rules/no_duplicate_case_values.dart b/pkg/linter/lib/src/rules/no_duplicate_case_values.dart
index 8de516a..1f86c20 100644
--- a/pkg/linter/lib/src/rules/no_duplicate_case_values.dart
+++ b/pkg/linter/lib/src/rules/no_duplicate_case_values.dart
@@ -7,7 +7,6 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/constant/value.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/lint/constants.dart'; // ignore: implementation_imports
 
 import '../analyzer.dart';
 
@@ -41,7 +40,7 @@
         var expression = member.expression;
 
         var result = expression.computeConstantValue();
-        var value = result.value;
+        var value = result?.value;
 
         if (value == null || !value.hasKnownValue) {
           continue;
diff --git a/pkg/linter/lib/src/rules/prefer_const_constructors.dart b/pkg/linter/lib/src/rules/prefer_const_constructors.dart
index df87946..054a79f 100644
--- a/pkg/linter/lib/src/rules/prefer_const_constructors.dart
+++ b/pkg/linter/lib/src/rules/prefer_const_constructors.dart
@@ -8,7 +8,6 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/lint/constants.dart'; // ignore: implementation_imports
 
 import '../analyzer.dart';
 import '../extensions.dart';
diff --git a/pkg/linter/lib/src/rules/prefer_const_literals_to_create_immutables.dart b/pkg/linter/lib/src/rules/prefer_const_literals_to_create_immutables.dart
index 2844d6f..ec84223 100644
--- a/pkg/linter/lib/src/rules/prefer_const_literals_to_create_immutables.dart
+++ b/pkg/linter/lib/src/rules/prefer_const_literals_to_create_immutables.dart
@@ -7,7 +7,6 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/lint/constants.dart'; // ignore: implementation_imports
 
 import '../analyzer.dart';
 
diff --git a/pkg/linter/lib/src/rules/use_build_context_synchronously.dart b/pkg/linter/lib/src/rules/use_build_context_synchronously.dart
index 26e73fb..a56f6ad 100644
--- a/pkg/linter/lib/src/rules/use_build_context_synchronously.dart
+++ b/pkg/linter/lib/src/rules/use_build_context_synchronously.dart
@@ -9,7 +9,6 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/src/dart/resolver/exit_detector.dart'; // ignore: implementation_imports
-import 'package:analyzer/src/lint/constants.dart'; // ignore: implementation_imports
 import 'package:analyzer/src/lint/linter.dart'; // ignore: implementation_imports
 import 'package:collection/collection.dart';
 import 'package:meta/meta.dart';
@@ -1445,7 +1444,7 @@
 }
 
 extension on Expression {
-  bool? get constantBoolValue => computeConstantValue().value?.toBoolValue();
+  bool? get constantBoolValue => computeConstantValue()?.value?.toBoolValue();
 }
 
 @visibleForTesting
diff --git a/pkg/linter/lib/src/rules/use_named_constants.dart b/pkg/linter/lib/src/rules/use_named_constants.dart
index 709d8d8..27c0169 100644
--- a/pkg/linter/lib/src/rules/use_named_constants.dart
+++ b/pkg/linter/lib/src/rules/use_named_constants.dart
@@ -8,7 +8,6 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/lint/constants.dart'; // ignore: implementation_imports
 
 import '../analyzer.dart';
 
@@ -57,7 +56,7 @@
         var library =
             (node.root as CompilationUnit).declaredFragment?.element.library2;
         if (library == null) return;
-        var value = node.computeConstantValue().value;
+        var value = node.computeConstantValue()?.value;
         for (var field in element.fields.where(
           (e) => e.isStatic && e.isConst,
         )) {