mirror of
https://github.com/dart-lang/sdk
synced 2024-10-04 16:35:01 +00:00
DartEditBuilder
to have canWriteType()
Bug: 46911 Change-Id: Icf8cdb3af6f2c34fe2eff75f1aeb1dac4aa8aac3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/210463 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
86c660faaa
commit
86898c2ee6
|
@ -12,7 +12,6 @@ import 'package:analyzer/dart/ast/visitor.dart';
|
|||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/dart/element/type_system.dart';
|
||||
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core.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/fixes/fixes.dart';
|
||||
|
@ -63,27 +62,23 @@ class AddTypeAnnotation extends CorrectionProducer {
|
|||
|
||||
Future<void> _applyChange(
|
||||
ChangeBuilder builder, Token? keyword, int offset, DartType type) async {
|
||||
Future<bool> tryToApplyChange(ChangeBuilder builder) async {
|
||||
var validChange = true;
|
||||
await builder.addDartFileEdit(file, (builder) {
|
||||
|
||||
_configureTargetLocation(node);
|
||||
|
||||
await builder.addDartFileEdit(file, (builder) {
|
||||
if (builder.canWriteType(type)) {
|
||||
if (keyword != null && keyword.keyword == Keyword.VAR) {
|
||||
builder.addReplacement(range.token(keyword), (builder) {
|
||||
validChange = builder.writeType(type);
|
||||
builder.writeType(type);
|
||||
});
|
||||
} else {
|
||||
builder.addInsertion(offset, (builder) {
|
||||
validChange = builder.writeType(type);
|
||||
builder.writeType(type);
|
||||
builder.write(' ');
|
||||
});
|
||||
}
|
||||
});
|
||||
return validChange;
|
||||
}
|
||||
|
||||
_configureTargetLocation(node);
|
||||
if (await tryToApplyChange(_temporaryBuilder(builder))) {
|
||||
await tryToApplyChange(builder);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Configure the [utils] using the given [target].
|
||||
|
@ -158,9 +153,6 @@ class AddTypeAnnotation extends CorrectionProducer {
|
|||
await _applyChange(builder, declarationList.keyword, variable.offset, type);
|
||||
}
|
||||
|
||||
ChangeBuilder _temporaryBuilder(ChangeBuilder builder) =>
|
||||
ChangeBuilder(workspace: (builder as ChangeBuilderImpl).workspace);
|
||||
|
||||
DartType? _typeForVariable(VariableDeclaration variable) {
|
||||
var initializer = variable.initializer;
|
||||
if (initializer != null) {
|
||||
|
|
|
@ -6,7 +6,6 @@ import 'package:_fe_analyzer_shared/src/scanner/token.dart';
|
|||
import 'package:analysis_server/src/services/correction/assist.dart';
|
||||
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core.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/range_factory.dart';
|
||||
|
@ -51,34 +50,26 @@ class SplitVariableDeclaration extends CorrectionProducer {
|
|||
return;
|
||||
}
|
||||
|
||||
Future<bool> tryToApplyChange(ChangeBuilder builder) async {
|
||||
var validChange = true;
|
||||
await builder.addDartFileEdit(file, (builder) {
|
||||
if (variableList.type == null) {
|
||||
final type = variable.declaredElement!.type;
|
||||
if (!type.isDynamic && keyword != null) {
|
||||
builder.addReplacement(range.token(keyword), (builder) {
|
||||
validChange = builder.writeType(type);
|
||||
});
|
||||
await builder.addDartFileEdit(file, (builder) {
|
||||
if (variableList.type == null) {
|
||||
final type = variable.declaredElement!.type;
|
||||
if (!type.isDynamic && keyword != null) {
|
||||
if (!builder.canWriteType(type)) {
|
||||
return;
|
||||
}
|
||||
builder.addReplacement(range.token(keyword), (builder) {
|
||||
builder.writeType(type);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var indent = utils.getNodePrefix(statement);
|
||||
var name = variable.name.name;
|
||||
builder.addSimpleInsertion(
|
||||
variable.name.end, ';' + eol + indent + name);
|
||||
});
|
||||
return validChange;
|
||||
}
|
||||
|
||||
if (await tryToApplyChange(_temporaryBuilder(builder))) {
|
||||
await tryToApplyChange(builder);
|
||||
}
|
||||
var indent = utils.getNodePrefix(statement);
|
||||
var name = variable.name.name;
|
||||
builder.addSimpleInsertion(
|
||||
variable.name.end, ';' + eol + indent + name);
|
||||
});
|
||||
}
|
||||
|
||||
ChangeBuilder _temporaryBuilder(ChangeBuilder builder) =>
|
||||
ChangeBuilder(workspace: (builder as ChangeBuilderImpl).workspace);
|
||||
|
||||
/// Return an instance of this class. Used as a tear-off in `AssistProcessor`.
|
||||
static SplitVariableDeclaration newInstance() => SplitVariableDeclaration();
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ main() {
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_unknownType() async {
|
||||
Future<void> test_privateType() async {
|
||||
addSource('/home/test/lib/a.dart', '''
|
||||
class A {
|
||||
_B b => _B();
|
||||
|
|
|
@ -56,6 +56,12 @@ class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
|
|||
super.addLinkedEdit(groupName,
|
||||
(builder) => buildLinkedEdit(builder as DartLinkedEditBuilder));
|
||||
|
||||
@override
|
||||
bool canWriteType(DartType? type, {ExecutableElement? methodBeingCopied}) =>
|
||||
type != null && !type.isDynamic
|
||||
? _canWriteType(type, methodBeingCopied: methodBeingCopied)
|
||||
: false;
|
||||
|
||||
@override
|
||||
LinkedEditBuilderImpl createLinkedEditBuilder() {
|
||||
return DartLinkedEditBuilderImpl(this);
|
||||
|
@ -838,6 +844,60 @@ class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Check if the code to reference [type] in this compilation unit can be
|
||||
/// written.
|
||||
///
|
||||
/// See also [_writeType]
|
||||
bool _canWriteType(DartType? type,
|
||||
{ExecutableElement? methodBeingCopied, bool required = false}) {
|
||||
type = _getVisibleType(type, methodBeingCopied: methodBeingCopied);
|
||||
|
||||
// If not a useful type, don't write it.
|
||||
if (type == null) {
|
||||
return false;
|
||||
}
|
||||
if (type.isDynamic) {
|
||||
if (required) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (type.isBottom) {
|
||||
var library = dartFileEditBuilder.resolvedUnit.libraryElement;
|
||||
if (library.isNonNullableByDefault) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var alias = type.alias;
|
||||
if (alias != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type is FunctionType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type is InterfaceType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type is NeverType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type is TypeParameterType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type is VoidType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw UnimplementedError('(${type.runtimeType}) $type');
|
||||
}
|
||||
|
||||
/// Generate a name that does not occur in [existingNames] that begins with
|
||||
/// the given [prefix].
|
||||
String _generateUniqueName(Set<String> existingNames, String prefix) {
|
||||
|
@ -1300,6 +1360,12 @@ class DartFileEditBuilderImpl extends FileEditBuilderImpl
|
|||
super.addReplacement(
|
||||
range, (builder) => buildEdit(builder as DartEditBuilder));
|
||||
|
||||
@override
|
||||
bool canWriteType(DartType? type, {ExecutableElement? methodBeingCopied}) {
|
||||
var builder = createEditBuilder(0, 0);
|
||||
return builder.canWriteType(type, methodBeingCopied: methodBeingCopied);
|
||||
}
|
||||
|
||||
@override
|
||||
void convertFunctionFromSyncToAsync(
|
||||
FunctionBody? body, TypeProvider typeProvider) {
|
||||
|
|
|
@ -20,6 +20,17 @@ abstract class DartEditBuilder implements EditBuilder {
|
|||
void addLinkedEdit(String groupName,
|
||||
void Function(DartLinkedEditBuilder builder) buildLinkedEdit);
|
||||
|
||||
/// Check if the code for a type annotation for the given [type] can be
|
||||
/// written.
|
||||
///
|
||||
/// If a [methodBeingCopied] is provided, then type parameters defined by that
|
||||
/// method are assumed to be part of what is being written and hence valid
|
||||
/// types.
|
||||
///
|
||||
/// The logic is the same as the one used in [writeType]
|
||||
bool canWriteType(DartType? type,
|
||||
{ExecutableElement? methodBeingCopied});
|
||||
|
||||
/// Write the code for a declaration of a class with the given [name]. If a
|
||||
/// list of [interfaces] is provided, then the class will implement those
|
||||
/// interfaces. If [isAbstract] is `true`, then the class will be abstract. If
|
||||
|
@ -299,6 +310,15 @@ abstract class DartFileEditBuilder implements FileEditBuilder {
|
|||
void addReplacement(
|
||||
SourceRange range, void Function(DartEditBuilder builder) buildEdit);
|
||||
|
||||
/// Check if the code for a type annotation for the given [type] can be
|
||||
/// written.
|
||||
///
|
||||
/// If a [methodBeingCopied] is provided, then type parameters defined by that
|
||||
/// method are assumed to be part of what is being written and hence valid
|
||||
/// types.
|
||||
bool canWriteType(DartType? type,
|
||||
{ExecutableElement? methodBeingCopied});
|
||||
|
||||
/// Create one or more edits that will convert the given function [body] from
|
||||
/// being synchronous to be asynchronous. This includes adding the `async`
|
||||
/// modifier to the body as well as potentially replacing the return type of
|
||||
|
|
Loading…
Reference in a new issue