blob: 14bad20b6e7c6e3c04c80b24a42cc8fc301ebd54 [file] [log] [blame]
import 'package:analysis_server/src/edit/edit_dartfix.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
class NonNullableFix {
final EditDartFix dartFix;
/// The current source being "fixed"
Source source;
/// The source file change or `null` if none
SourceFileEdit fileEdit;
int firstOffset;
int firstLength;
NonNullableFix(this.dartFix);
void addEdit(int offset, int length, String replacementText) {
fileEdit ??= new SourceFileEdit(source.fullName, 0);
fileEdit.edits.add(new SourceEdit(offset, length, replacementText));
}
/// Update the source to be non-nullable by
/// 1) adding trailing '?' to type references of nullable variables, and
/// 2) removing trailing '?' from type references of non-nullable variables.
void applyLocalFixes(ResolvedUnitResult result) {
final context = result.session.analysisContext;
AnalysisOptionsImpl options = context.analysisOptions;
if (!options.experimentStatus.non_nullable) {
return;
}
final unit = result.unit;
source = unit.declaredElement.source;
// find and fix types
unit.accept(new _NonNullableTypeVisitor(this));
// add source changes to the collection of fixes
source = null;
if (fileEdit != null) {
dartFix.addSourceFileEdit('Update non-nullable type references',
dartFix.locationFor(result, firstOffset, firstLength), fileEdit);
}
}
}
class _NonNullableTypeVisitor extends RecursiveAstVisitor<void> {
final NonNullableFix fix;
_NonNullableTypeVisitor(this.fix);
@override
void visitConstructorName(ConstructorName node) {
// skip the type name associated with the constructor
node.type?.typeArguments?.accept(this);
}
@override
void visitTypeName(TypeName node) {
// TODO(danrubel): Replace this braindead implementation
// with something that determines whether or not the type should be nullable
// and adds or removes the trailing `?` to match.
if (node.question == null) {
final identifier = node.name;
if (identifier is SimpleIdentifier) {
if (identifier.name == 'void') {
return;
}
}
fix.addEdit(node.end, 0, '?');
fix.firstOffset ??= node.offset;
fix.firstLength ??= node.length;
}
super.visitTypeName(node);
}
}