DAS: Simplify public API of CorrectionProducer and friends
* CorrectionProducer:
* Remove `errorMessage`; unused.
* Make `configure` abstract; it is only here for the doc comment.
* MultiCorrectionProducer: remove `typeProvider`, `typeSystem`.
* ResolvedCorrectionProducer: make `coreTypeBool` private.
* _AbstractCorrectionProducer:
* Move `invalidNodes`; only used once.
* Remove `strictCasts`; unused.
* Remove `displayStringForType`; unnecessary convenience.
* Move `mightBeImplicitConstructor` to be a private extension
getter.
* Move `nameOfType` to be a private extension getter.
* Move `shouldWrapParenthesisBeforeAnd` to be a public extension
getter.
* Move DartFileEditBuilderExtension to be a private extension.
Change-Id: Icd1e17ccf398fafd1d9fee88d4b6a430a2deb50a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/367363
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
index 8bdbc27..595f694 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
@@ -25,9 +25,7 @@
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
-import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
-import 'package:analyzer_plugin/utilities/range_factory.dart';
import 'package:meta/meta.dart';
/// How broadly a [CorrectionProducer] can be applied.
@@ -117,17 +115,12 @@
bool get canBeAppliedAutomatically =>
applicability == CorrectionApplicability.automatically;
- /// The length of the error message being fixed, or `null` if there is no
- /// diagnostic.
+ /// The length of the source range associated with the error message being
+ /// fixed, or `null` if there is no diagnostic.
int? get errorLength => diagnostic?.problemMessage.length;
- /// The text of the error message being fixed, or `null` if there is no
- /// diagnostic.
- String? get errorMessage =>
- diagnostic?.problemMessage.messageText(includeUrl: true);
-
- /// The offset of the error message being fixed, or `null` if there is no
- /// diagnostic.
+ /// The offset of the source range associated with the error message being
+ /// fixed, or `null` if there is no diagnostic.
int? get errorOffset => diagnostic?.problemMessage.offset;
/// The arguments that should be used when composing the message for a fix, or
@@ -162,9 +155,7 @@
///
/// If the fix needs to dynamically set [fixKind], it should be done here.
@override
- void configure(CorrectionProducerContext<T> context) {
- super.configure(context);
- }
+ void configure(CorrectionProducerContext<T> context);
}
class CorrectionProducerContext<UnitResult extends ParsedUnitResult> {
@@ -176,11 +167,10 @@
final AnalysisSessionHelper _sessionHelper;
final UnitResult _unitResult;
- // TODO(migration): Make it non-nullable, specialize "fix" context?
final DartFixContext? dartFixContext;
- /// A flag indicating whether the correction producers will be run in the
- /// context of applying bulk fixes.
+ /// Whether the correction producers are run in the context of applying bulk
+ /// fixes.
final bool _applyingBulkFixes;
final Diagnostic? _diagnostic;
@@ -191,13 +181,13 @@
CorrectionProducerContext._({
required UnitResult unitResult,
- bool applyingBulkFixes = false,
- this.dartFixContext,
- Diagnostic? diagnostic,
+ required bool applyingBulkFixes,
+ required this.dartFixContext,
+ required Diagnostic? diagnostic,
required AstNode node,
required Token token,
- int selectionOffset = -1,
- int selectionLength = 0,
+ required int selectionOffset,
+ required int selectionLength,
}) : _unitResult = unitResult,
_sessionHelper = AnalysisSessionHelper(unitResult.session),
_utils = CorrectionUtils(unitResult),
@@ -301,12 +291,6 @@
/// The individual producers generated by this producer.
Future<List<ResolvedCorrectionProducer>> get producers;
-
- TypeProvider get typeProvider => unitResult.typeProvider;
-
- /// The type system appropriate to the library in which the correction is
- /// requested.
- TypeSystem get typeSystem => unitResult.typeSystem;
}
/// An object that can compute a correction (fix or assist) in a Dart file using
@@ -322,9 +306,6 @@
sessionHelper.session.analysisContext
.getAnalysisOptionsForFile(unitResult.file) as AnalysisOptionsImpl;
- /// The type for the class `bool` from `dart:core`.
- DartType get coreTypeBool => unitResult.typeProvider.boolType;
-
/// Whether [node] is in a static context.
bool get inStaticContext {
// Constructor initializers cannot reference `this`.
@@ -351,6 +332,9 @@
/// requested.
TypeSystem get typeSystem => unitResult.typeSystem;
+ /// The type for the class `bool` from `dart:core`.
+ DartType get _coreTypeBool => typeProvider.boolType;
+
/// Returns the class declaration for the given [element], or `null` if there
/// is no such class.
Future<ClassDeclaration?> getClassDeclaration(ClassElement element) async {
@@ -486,35 +470,35 @@
if (parent is AssertStatement) {
var statement = parent;
if (statement.condition == expression) {
- return coreTypeBool;
+ return _coreTypeBool;
}
}
// `if ( myFunction() ) {}`.
if (parent is IfStatement) {
var statement = parent;
if (statement.expression == expression) {
- return coreTypeBool;
+ return _coreTypeBool;
}
}
// `while ( myFunction() ) {}`.
if (parent is WhileStatement) {
var statement = parent;
if (statement.condition == expression) {
- return coreTypeBool;
+ return _coreTypeBool;
}
}
// `do {} while ( myFunction() );`.
if (parent is DoStatement) {
var statement = parent;
if (statement.condition == expression) {
- return coreTypeBool;
+ return _coreTypeBool;
}
}
// `!myFunction()`.
if (parent is PrefixExpression) {
var prefixExpression = parent;
if (prefixExpression.operator.type == TokenType.BANG) {
- return coreTypeBool;
+ return _coreTypeBool;
}
}
// Binary expression `&&` or `||`.
@@ -523,7 +507,7 @@
var operatorType = binaryExpression.operator.type;
if (operatorType == TokenType.AMPERSAND_AMPERSAND ||
operatorType == TokenType.BAR_BAR) {
- return coreTypeBool;
+ return _coreTypeBool;
}
}
}
@@ -577,11 +561,6 @@
String get file => _context.path;
- /// See [CompilationUnitImpl.invalidNodes].
- List<AstNode> get invalidNodes {
- return (unit as CompilationUnitImpl).invalidNodes;
- }
-
AstNode get node => _context._node;
ResourceProvider get resourceProvider => unitResult.session.resourceProvider;
@@ -594,15 +573,6 @@
AnalysisSessionHelper get sessionHelper => _context._sessionHelper;
- bool get strictCasts {
- var file = _context.dartFixContext?.resolvedResult.file;
- // TODO(pq): can this ever happen?
- if (file == null) return false;
- var analysisOptions = _context._unitResult.session.analysisContext
- .getAnalysisOptionsForFile(file) as AnalysisOptionsImpl;
- return analysisOptions.strictCasts;
- }
-
Token get token => _context._token;
CompilationUnit get unit => _context._unitResult.unit;
@@ -611,16 +581,12 @@
CorrectionUtils get utils => _context._utils;
- /// Configure this producer based on the [context].
+ /// Configures this producer based on the [context].
@mustCallSuper
void configure(CorrectionProducerContext<T> context) {
_context = context;
}
- /// Returns the text that should be displayed to users when referring to the
- /// given [type].
- String displayStringForType(DartType type) => type.getDisplayString();
-
CodeStyleOptions getCodeStyleOptions(File file) =>
sessionHelper.session.analysisContext
.getAnalysisOptionsForFile(file)
@@ -650,19 +616,17 @@
}
/// Returns the text of the given [range] in the unit.
- String getRangeText(SourceRange range) {
- return utils.getRangeText(range);
- }
+ String getRangeText(SourceRange range) => utils.getRangeText(range);
/// Returns the mapping from a library (that is available to this context) to
/// a top-level declaration that is exported (not necessary declared) by this
- /// library, and has the requested base name. For getters and setters the
- /// corresponding top-level variable is returned.
+ /// library, and has the requested base name.
+ ///
+ /// For getters and setters the corresponding top-level variable is returned.
Future<Map<LibraryElement, Element>> getTopLevelDeclarations(
String baseName,
- ) {
- return _context.dartFixContext!.getTopLevelDeclarations(baseName);
- }
+ ) =>
+ _context.dartFixContext!.getTopLevelDeclarations(baseName);
/// Returns whether the selection covers an operator of the given
/// [binaryExpression].
@@ -686,73 +650,9 @@
return false;
}
- /// Return libraries with extensions that declare non-static public
+ /// Returns libraries with extensions that declare non-static public
/// extension members with the [memberName].
Stream<LibraryElement> librariesWithExtensions(String memberName) {
return _context.dartFixContext!.librariesWithExtensions(memberName);
}
-
- /// Return `true` if the given [node] is in a location where an implicit
- /// constructor invocation would be allowed.
- bool mightBeImplicitConstructor(AstNode node) {
- if (node is SimpleIdentifier) {
- var parent = node.parent;
- if (parent is MethodInvocation) {
- return parent.realTarget == null;
- }
- }
- return false;
- }
-
- /// If the [node] might be a type name, return its name.
- String? nameOfType(AstNode node) {
- if (node is SimpleIdentifier) {
- var name = node.name;
- if (node.parent is NamedType || _isNameOfType(name)) {
- return name;
- }
- }
- return null;
- }
-
- /// Return `true` if the given [expression] should be wrapped with parenthesis
- /// when we want to use it as operand of a logical `and` expression.
- bool shouldWrapParenthesisBeforeAnd(Expression expression) {
- if (expression is BinaryExpression) {
- var binary = expression;
- var precedence = binary.operator.type.precedence;
- return precedence < TokenClass.LOGICAL_AND_OPERATOR.precedence;
- }
- return false;
- }
-
- /// Return `true` if the [name] is capitalized.
- bool _isNameOfType(String name) {
- if (name.isEmpty) {
- return false;
- }
- var firstLetter = name.substring(0, 1);
- if (firstLetter.toUpperCase() != firstLetter) {
- return false;
- }
- return true;
- }
-}
-
-extension DartFileEditBuilderExtension on DartFileEditBuilder {
- /// Add edits to the [builder] to remove any parentheses enclosing the
- /// [expression].
- // TODO(brianwilkerson): Consider moving this to DartFileEditBuilder.
- void removeEnclosingParentheses(Expression expression) {
- var precedence = getExpressionPrecedence(expression);
- while (expression.parent is ParenthesizedExpression) {
- var parenthesized = expression.parent as ParenthesizedExpression;
- if (getExpressionParentPrecedence(parenthesized) > precedence) {
- break;
- }
- addDeletion(range.token(parenthesized.leftParenthesis));
- addDeletion(range.token(parenthesized.rightParenthesis));
- expression = parenthesized;
- }
- }
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/change_type_annotation.dart b/pkg/analysis_server/lib/src/services/correction/dart/change_type_annotation.dart
index c264f2c..a256c59 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/change_type_annotation.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/change_type_annotation.dart
@@ -48,8 +48,8 @@
if (newType is InterfaceType ||
newType is FunctionType ||
newType is RecordType) {
- _oldAnnotation = displayStringForType(typeNode.typeOrThrow);
- _newAnnotation = displayStringForType(newType);
+ _oldAnnotation = typeNode.typeOrThrow.getDisplayString();
+ _newAnnotation = newType.getDisplayString();
await builder.addDartFileEdit(file, (builder) {
if (builder.canWriteType(newType)) {
builder.addReplacement(range.node(typeNode), (builder) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/create_class.dart b/pkg/analysis_server/lib/src/services/correction/dart/create_class.dart
index 45a4a1b..417f37f 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/create_class.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/create_class.dart
@@ -55,14 +55,14 @@
className = targetNode.name2.lexeme;
requiresConstConstructor |= _requiresConstConstructor(targetNode);
} else if (targetNode is SimpleIdentifier) {
- className = nameOfType(targetNode);
+ className = targetNode.nameOfType;
requiresConstConstructor |= _requiresConstConstructor(targetNode);
} else if (targetNode is PrefixedIdentifier) {
prefixElement = targetNode.prefix.staticElement;
if (prefixElement == null) {
return;
}
- className = nameOfType(targetNode.identifier);
+ className = targetNode.identifier.nameOfType;
} else {
return;
}
@@ -159,3 +159,29 @@
return false;
}
}
+
+extension on AstNode {
+ /// If this might be a type name, return its name.
+ String? get nameOfType {
+ var self = this;
+ if (self is SimpleIdentifier) {
+ var name = self.name;
+ if (self.parent is NamedType || _isNameOfType(name)) {
+ return name;
+ }
+ }
+ return null;
+ }
+
+ /// Return `true` if the [name] is capitalized.
+ static bool _isNameOfType(String name) {
+ if (name.isEmpty) {
+ return false;
+ }
+ var firstLetter = name.substring(0, 1);
+ if (firstLetter.toUpperCase() != firstLetter) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
index 97f1604..b21c67b 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
@@ -137,7 +137,7 @@
ElementKind.MIXIN,
ElementKind.TYPE_ALIAS,
]);
- } else if (mightBeImplicitConstructor(targetNode)) {
+ } else if (targetNode.mightBeImplicitConstructor) {
var typeName = (targetNode as SimpleIdentifier).name;
await _importLibraryForElement(producers, typeName, const [
ElementKind.CLASS,
@@ -147,7 +147,6 @@
return producers;
}
- @override
String? nameOfType(AstNode node) {
var parent = node.parent;
switch (node) {
@@ -584,3 +583,17 @@
});
}
}
+
+extension on AstNode {
+ /// Whether this [AstNode] is in a location where an implicit constructor
+ /// invocation would be allowed.
+ bool get mightBeImplicitConstructor {
+ if (this is SimpleIdentifier) {
+ var parent = this.parent;
+ if (parent is MethodInvocation) {
+ return parent.realTarget == null;
+ }
+ }
+ return false;
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_inner.dart b/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_inner.dart
index f0b4744..b24b285 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_inner.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_inner.dart
@@ -47,10 +47,10 @@
var innerCondition = innerIfStatement.expression;
var targetConditionSource = utils.getNodeText(targetCondition);
var innerConditionSource = utils.getNodeText(innerCondition);
- if (shouldWrapParenthesisBeforeAnd(targetCondition)) {
+ if (targetCondition.shouldWrapParenthesisBeforeAnd) {
targetConditionSource = '($targetConditionSource)';
}
- if (shouldWrapParenthesisBeforeAnd(innerCondition)) {
+ if (innerCondition.shouldWrapParenthesisBeforeAnd) {
innerConditionSource = '($innerConditionSource)';
}
var condition = '$targetConditionSource && $innerConditionSource';
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_outer.dart b/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_outer.dart
index 4a3a812..45dd05f 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_outer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/join_if_with_outer.dart
@@ -53,10 +53,10 @@
var outerCondition = outerIfStatement.expression;
var targetConditionSource = utils.getNodeText(targetCondition);
var outerConditionSource = utils.getNodeText(outerCondition);
- if (shouldWrapParenthesisBeforeAnd(targetCondition)) {
+ if (targetCondition.shouldWrapParenthesisBeforeAnd) {
targetConditionSource = '($targetConditionSource)';
}
- if (shouldWrapParenthesisBeforeAnd(outerCondition)) {
+ if (outerCondition.shouldWrapParenthesisBeforeAnd) {
outerConditionSource = '($outerConditionSource)';
}
var condition = '$outerConditionSource && $targetConditionSource';
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_constructor.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_constructor.dart
index fdb62ba..21b39f6 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/remove_constructor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_constructor.dart
@@ -4,8 +4,8 @@
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/ast.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';
@@ -51,8 +51,9 @@
return null;
}
+ var invalidNodes = (unit as CompilationUnitImpl).invalidNodes;
for (var constructor in invalidNodes) {
- if (constructor is ConstructorDeclaration) {
+ if (constructor is ConstructorDeclarationImpl) {
if (range.node(constructor).contains(errorOffset)) {
return constructor;
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_unnecessary_cast.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_unnecessary_cast.dart
index fc8b40f..052dbcf 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/remove_unnecessary_cast.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_unnecessary_cast.dart
@@ -4,8 +4,10 @@
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
@@ -35,3 +37,20 @@
});
}
}
+
+extension on DartFileEditBuilder {
+ /// Adds edits to this [DartFileEditBuilder] to remove any parentheses
+ /// enclosing the [expression].
+ void removeEnclosingParentheses(Expression expression) {
+ var precedence = getExpressionPrecedence(expression);
+ while (expression.parent is ParenthesizedExpression) {
+ var parenthesized = expression.parent as ParenthesizedExpression;
+ if (getExpressionParentPrecedence(parenthesized) > precedence) {
+ break;
+ }
+ addDeletion(range.token(parenthesized.leftParenthesis));
+ addDeletion(range.token(parenthesized.rightParenthesis));
+ expression = parenthesized;
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/ast.dart b/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
index 35140cd..320ffaf 100644
--- a/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
+++ b/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
@@ -8,6 +8,7 @@
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/source/source.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/utilities/extensions/collection.dart';
@@ -350,6 +351,17 @@
}
return false;
}
+
+ /// Whether this [Expression] should be wrapped with parentheses when we want
+ /// to use it as operand of a logical and-expression.
+ bool get shouldWrapParenthesisBeforeAnd {
+ var self = this;
+ if (self is! BinaryExpression) {
+ return false;
+ }
+ var precedence = self.operator.type.precedence;
+ return precedence < TokenClass.LOGICAL_AND_OPERATOR.precedence;
+ }
}
extension FunctionBodyExtension on FunctionBody {