Merge branch 'master' into migrate-to-null-safety
# Conflicts:
# pubspec.yaml
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6e44179..19d2c55 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 2.0.0
+
+* Migrate to null safety.
+
# 1.3.14
* Add support for generic annotations.
diff --git a/bin/format.dart b/bin/format.dart
index c3cfee8..e757c00 100644
--- a/bin/format.dart
+++ b/bin/format.dart
@@ -1,7 +1,6 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// 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 'dart:io';
import 'package:args/args.dart';
@@ -40,7 +39,7 @@
usageError(parser, 'Can only use --verbose with --help.');
}
- List<int> selection;
+ List<int>? selection;
try {
selection = parseSelection(argResults, 'preserve');
} on FormatException catch (exception) {
@@ -145,12 +144,12 @@
}
/// Prints [error] and usage help then exits with exit code 64.
-void usageError(ArgParser parser, String error) {
+Never usageError(ArgParser parser, String error) {
printUsage(parser, error);
exit(64);
}
-void printUsage(ArgParser parser, [String error]) {
+void printUsage(ArgParser parser, [String? error]) {
var output = stdout;
var message = 'Idiomatically format Dart source code.';
diff --git a/example/format.dart b/example/format.dart
index ff1a7cd..77c79dc 100644
--- a/example/format.dart
+++ b/example/format.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.example.format;
-
import 'dart:io';
import 'dart:mirrors';
@@ -31,7 +28,8 @@
runFormatter(source, pageWidth, isCompilationUnit: true);
}
-void runFormatter(String source, int pageWidth, {bool isCompilationUnit}) {
+void runFormatter(String source, int pageWidth,
+ {required bool isCompilationUnit}) {
try {
var formatter = DartFormatter(pageWidth: pageWidth);
@@ -88,7 +86,7 @@
var leadingIndent = 0;
var indentMatch = indentPattern.firstMatch(description);
if (indentMatch != null) {
- leadingIndent = int.parse(indentMatch[1]);
+ leadingIndent = int.parse(indentMatch[1]!);
description = description.substring(indentMatch.end);
}
diff --git a/lib/dart_style.dart b/lib/dart_style.dart
index bc59401..4da21a8 100644
--- a/lib/dart_style.dart
+++ b/lib/dart_style.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style;
-
export 'src/dart_formatter.dart';
export 'src/exceptions.dart';
export 'src/style_fix.dart';
diff --git a/lib/src/argument_list_visitor.dart b/lib/src/argument_list_visitor.dart
index 45f8cd9..a22864f 100644
--- a/lib/src/argument_list_visitor.dart
+++ b/lib/src/argument_list_visitor.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.argument_list_visitor;
-
import 'dart:math' as math;
import 'package:analyzer/dart/ast/ast.dart';
@@ -36,12 +33,12 @@
/// The contiguous list of block function arguments, if any.
///
/// Otherwise, this is `null`.
- final List<Expression> _functions;
+ final List<Expression>? _functions;
/// If there are block function arguments, this is the arguments after them.
///
/// Otherwise, this is `null`.
- final ArgumentSublist _argumentsAfterFunctions;
+ final ArgumentSublist? _argumentsAfterFunctions;
/// Returns `true` if there is only a single positional argument.
bool get _isSingle =>
@@ -129,16 +126,17 @@
}
for (var i = 0; i < functionsStart; i++) {
- if (arguments[i] is! NamedExpression) continue;
+ var argument = arguments[i];
+ if (argument is! NamedExpression) continue;
- if (isArrow(arguments[i])) {
+ if (isArrow(argument)) {
functionsStart = null;
break;
}
}
for (var i = functionsEnd; i < arguments.length; i++) {
- if (isArrow(arguments[i])) {
+ if (isArrow(arguments[i] as NamedExpression)) {
functionsStart = null;
break;
}
@@ -174,7 +172,10 @@
this._allArguments,
this._arguments,
this._functions,
- this._argumentsAfterFunctions);
+ this._argumentsAfterFunctions) {
+ assert(_functions == null || _argumentsAfterFunctions != null,
+ 'If _functions is passed, _argumentsAfterFunctions must be too.');
+ }
/// Builds chunks for the argument list.
void visit() {
@@ -189,20 +190,21 @@
_visitor.builder.endSpan();
- if (_functions != null) {
+ var functions = _functions;
+ if (functions != null) {
// TODO(rnystrom): It might look better to treat the parameter list of the
// first function as if it were an argument in the preceding argument list
// instead of just having this little solo split here. That would try to
// keep the parameter list with other arguments when possible, and, I
// think, generally look nicer.
- if (_functions.first == _allArguments.first) {
+ if (functions.first == _allArguments.first) {
_visitor.soloZeroSplit();
} else {
_visitor.soloSplit();
}
- for (var argument in _functions) {
- if (argument != _functions.first) _visitor.space();
+ for (var argument in functions) {
+ if (argument != functions.first) _visitor.space();
_visitor.visit(argument);
@@ -213,7 +215,7 @@
}
_visitor.builder.startSpan();
- _argumentsAfterFunctions.visit(_visitor);
+ _argumentsAfterFunctions!.visit(_visitor);
_visitor.builder.endSpan();
}
@@ -225,9 +227,7 @@
/// Returns `true` if [expression] is a [FunctionExpression] with a non-empty
/// block body.
static bool _isBlockFunction(Expression expression) {
- if (expression is NamedExpression) {
- expression = (expression as NamedExpression).expression;
- }
+ if (expression is NamedExpression) expression = expression.expression;
// Allow functions wrapped in dotted method calls like "a.b.c(() { ... })".
if (expression is MethodInvocation) {
@@ -245,39 +245,37 @@
// Allow immediately-invoked functions like "() { ... }()".
if (expression is FunctionExpressionInvocation) {
- var invocation = expression as FunctionExpressionInvocation;
- if (invocation.argumentList.arguments.isNotEmpty) return false;
+ if (expression.argumentList.arguments.isNotEmpty) return false;
- expression = invocation.function;
+ expression = expression.function;
}
// Unwrap parenthesized expressions.
while (expression is ParenthesizedExpression) {
- expression = (expression as ParenthesizedExpression).expression;
+ expression = expression.expression;
}
// Must be a function.
if (expression is! FunctionExpression) return false;
// With a curly body.
- var function = expression as FunctionExpression;
- if (function.body is! BlockFunctionBody) return false;
+ if (expression.body is! BlockFunctionBody) return false;
// That isn't empty.
- var body = function.body as BlockFunctionBody;
+ var body = expression.body as BlockFunctionBody;
return body.block.statements.isNotEmpty ||
body.block.rightBracket.precedingComments != null;
}
/// Returns `true` if [expression] is a valid method invocation target for
/// an invocation that wraps a function literal argument.
- static bool _isValidWrappingTarget(Expression expression) {
+ static bool _isValidWrappingTarget(Expression? expression) {
// Allow bare function calls.
if (expression == null) return true;
// Allow property accesses.
while (expression is PropertyAccess) {
- expression = (expression as PropertyAccess).target;
+ expression = expression.target;
}
if (expression is PrefixedIdentifier) return true;
@@ -318,12 +316,12 @@
final int _trailingBlocks;
/// The rule used to split the bodies of all block arguments.
- Rule get blockRule => _blockRule;
- Rule _blockRule;
+ Rule? get blockRule => _blockRule;
+ Rule? _blockRule;
/// The most recent chunk that split before an argument.
- Chunk get previousSplit => _previousSplit;
- Chunk _previousSplit;
+ Chunk? get previousSplit => _previousSplit;
+ Chunk? _previousSplit;
factory ArgumentSublist(
List<Expression> allArguments, List<Expression> arguments) {
@@ -381,7 +379,7 @@
}
/// Writes the positional arguments, if any.
- PositionalRule _visitPositional(SourceVisitor visitor) {
+ PositionalRule? _visitPositional(SourceVisitor visitor) {
if (_positional.isEmpty) return null;
// Allow splitting after "(".
@@ -395,7 +393,7 @@
}
/// Writes the named arguments, if any.
- void _visitNamed(SourceVisitor visitor, PositionalRule positionalRule) {
+ void _visitNamed(SourceVisitor visitor, PositionalRule? positionalRule) {
if (_named.isEmpty) return;
// Only count the blocks in the named rule.
@@ -443,11 +441,12 @@
void _visitArgument(
SourceVisitor visitor, ArgumentRule rule, Expression argument) {
// If we're about to write a block argument, handle it specially.
- if (_blocks.containsKey(argument)) {
+ var argumentBlock = _blocks[argument];
+ if (argumentBlock != null) {
rule.disableSplitOnInnerRules();
// Tell it to use the rule we've already created.
- visitor.beforeBlock(_blocks[argument], blockRule, previousSplit);
+ visitor.beforeBlock(argumentBlock, blockRule!, previousSplit);
} else if (_allArguments.length > 1) {
// Edge case: Only bump the nesting if there are multiple arguments. This
// lets us avoid spurious indentation in cases like:
@@ -471,7 +470,7 @@
visitor.visit(argument);
}
- if (_blocks.containsKey(argument)) {
+ if (argumentBlock != null) {
rule.enableSplitOnInnerRules();
} else if (_allArguments.length > 1) {
visitor.builder.endBlockArgumentNesting();
@@ -490,9 +489,9 @@
///
/// Block-formatted arguments can get special indentation to make them look
/// more statement-like.
- static Token _blockToken(Expression expression) {
+ static Token? _blockToken(Expression expression) {
if (expression is NamedExpression) {
- expression = (expression as NamedExpression).expression;
+ expression = expression.expression;
}
// TODO(rnystrom): Should we step into parenthesized expressions?
diff --git a/lib/src/call_chain_visitor.dart b/lib/src/call_chain_visitor.dart
index 80b1b51..5af43f7 100644
--- a/lib/src/call_chain_visitor.dart
+++ b/lib/src/call_chain_visitor.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.call_chain_visitor;
-
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
@@ -81,7 +78,7 @@
/// })
/// .d()
/// .e();
- final List<_MethodSelector> _blockCalls;
+ final List<_MethodSelector>? _blockCalls;
/// If there is one or more block calls and a single chained expression after
/// that, this will be that expression.
@@ -96,7 +93,7 @@
/// need to split before its `.` and this accommodates the common pattern of
/// a trailing `toList()` or `toSet()` after a series of higher-order methods
/// on an iterable.
- final _Selector _hangingCall;
+ final _Selector? _hangingCall;
/// Whether or not a [Rule] is currently active for the call chain.
bool _ruleEnabled = false;
@@ -106,7 +103,7 @@
/// After the properties are visited (if there are any), this will be the
/// rule used to split between them.
- PositionalRule _propertyRule;
+ PositionalRule? _propertyRule;
/// Creates a new call chain visitor for [visitor] for the method chain
/// contained in [node].
@@ -135,15 +132,15 @@
calls.removeRange(0, properties.length);
// Separate out the block calls, if there are any.
- List<_MethodSelector> blockCalls;
- _Selector hangingCall;
+ List<_MethodSelector>? blockCalls;
+ _Selector? hangingCall;
var inBlockCalls = false;
for (var call in calls) {
if (call.isBlockCall(visitor)) {
inBlockCalls = true;
blockCalls ??= [];
- blockCalls.add(call);
+ blockCalls.add(call as _MethodSelector);
} else if (inBlockCalls) {
// We found a non-block call after a block call.
if (call == calls.last) {
@@ -181,7 +178,7 @@
/// created for the call chain and the caller must end it. Used by cascades
/// to force a cascade after a method chain to be more deeply nested than
/// the methods.
- void visit({bool unnest}) {
+ void visit({bool? unnest}) {
unnest ??= true;
_visitor.builder.nestExpression();
@@ -216,7 +213,7 @@
}
for (var property in _properties) {
- _propertyRule.beforeArgument(_visitor.zeroSplit());
+ _propertyRule!.beforeArgument(_visitor.zeroSplit());
property.write(this);
}
@@ -245,12 +242,13 @@
// If there are block calls, end the chain and write those without any
// extra indentation.
- if (_blockCalls != null) {
+ var blockCalls = _blockCalls;
+ if (blockCalls != null) {
_enableRule();
_visitor.zeroSplit();
_disableRule();
- for (var blockCall in _blockCalls) {
+ for (var blockCall in blockCalls) {
blockCall.write(this);
}
@@ -289,7 +287,7 @@
// Unwrap parentheses.
while (expression is ParenthesizedExpression) {
- expression = (expression as ParenthesizedExpression).expression;
+ expression = expression.expression;
}
// Don't split right after a collection literal.
@@ -305,7 +303,7 @@
// If the expression ends in an argument list, base the splitting on the
// last argument.
- ArgumentList argumentList;
+ ArgumentList? argumentList;
if (expression is MethodInvocation) {
argumentList = expression.argumentList;
} else if (expression is InstanceCreationExpression) {
@@ -324,7 +322,7 @@
if (_visitor.hasCommaAfter(argument)) return false;
if (argument is NamedExpression) {
- argument = (argument as NamedExpression).expression;
+ argument = argument.expression;
}
// TODO(rnystrom): This logic is similar (but not identical) to
@@ -386,7 +384,7 @@
// If the properties split, force the calls to split too.
var rule = Rule();
- if (_propertyRule != null) _propertyRule.setNamedArgsRule(rule);
+ _propertyRule?.setNamedArgsRule(rule);
if (lazy) {
_visitor.builder.startLazyRule(rule);
@@ -548,11 +546,11 @@
// Selectors.
if (node is MethodInvocation && node.target != null) {
- return _unwrapSelector(node.target, _MethodSelector(node), calls);
+ return _unwrapSelector(node.target!, _MethodSelector(node), calls);
}
if (node is PropertyAccess && node.target != null) {
- return _unwrapSelector(node.target, _PropertySelector(node), calls);
+ return _unwrapSelector(node.target!, _PropertySelector(node), calls);
}
if (node is PrefixedIdentifier) {
@@ -561,7 +559,7 @@
// Postfix expressions.
if (node is IndexExpression) {
- return _unwrapPostfix(node, node.target, calls);
+ return _unwrapPostfix(node, node.target!, calls);
}
if (node is FunctionExpressionInvocation) {
diff --git a/lib/src/chunk.dart b/lib/src/chunk.dart
index 30a6d92..02dbfb6 100644
--- a/lib/src/chunk.dart
+++ b/lib/src/chunk.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.chunk;
-
import 'fast_hash.dart';
import 'nesting_level.dart';
import 'rule/rule.dart';
@@ -16,13 +13,13 @@
/// The offset from the beginning of [text] where the selection starts, or
/// `null` if the selection does not start within this chunk.
- int get selectionStart => _selectionStart;
- int _selectionStart;
+ int? get selectionStart => _selectionStart;
+ int? _selectionStart;
/// The offset from the beginning of [text] where the selection ends, or
/// `null` if the selection does not start within this chunk.
- int get selectionEnd => _selectionEnd;
- int _selectionEnd;
+ int? get selectionEnd => _selectionEnd;
+ int? _selectionEnd;
/// Sets [selectionStart] to be [start] characters into [text].
void startSelection(int start) {
@@ -77,8 +74,8 @@
///
/// For top level chunks that are not inside any block, this also includes
/// leading indentation.
- int get indent => _indent;
- int _indent;
+ int? get indent => _indent;
+ int? _indent;
/// The expression nesting level following this chunk.
///
@@ -91,12 +88,14 @@
/// argument, anotherFunction(argument,
/// argument));
NestingLevel get nesting => _nesting;
- NestingLevel _nesting;
+ late NestingLevel _nesting;
/// If this chunk marks the beginning of a block, this contains the child
/// chunks and other data about that nested block.
- ChunkBlock get block => _block;
- ChunkBlock _block;
+ ///
+ /// This should only be accessed when [isBlock] is `true`.
+ ChunkBlock get block => _block!;
+ ChunkBlock? _block;
/// Whether this chunk has a [block].
bool get isBlock => _block != null;
@@ -112,8 +111,8 @@
/// The [Rule] that controls when a split should occur after this chunk.
///
/// Multiple splits may share a [Rule].
- Rule get rule => _rule;
- Rule _rule;
+ Rule? get rule => _rule;
+ Rule? _rule;
/// Whether or not an extra blank line should be output after this chunk if
/// it's split.
@@ -125,7 +124,7 @@
/// However, this getter does not expose that. It will return `false` if the
/// chunk is still indeterminate.
bool get isDouble => _isDouble ?? false;
- bool _isDouble;
+ bool? _isDouble;
/// If `true`, then the line after this chunk should always be at column
/// zero regardless of any indentation or expression nesting.
@@ -139,7 +138,7 @@
bool get flushLeftAfter {
if (!isBlock) return _flushLeft;
- return _block.chunks.last.flushLeftAfter;
+ return block.chunks.last.flushLeftAfter;
}
/// Whether this chunk should append an extra space if it does not split.
@@ -150,13 +149,10 @@
/// Whether this chunk marks the end of a range of chunks that can be line
/// split independently of the following chunks.
- bool get canDivide {
- // Have to call markDivide() before accessing this.
- assert(_canDivide != null);
- return _canDivide;
- }
-
- bool _canDivide;
+ ///
+ /// You must call markDivide() before accessing this.
+ bool get canDivide => _canDivide;
+ late final bool _canDivide;
/// The number of characters in this chunk when unsplit.
int get length => _text.length + (spaceWhenUnsplit ? 1 : 0);
@@ -166,10 +162,10 @@
/// Does not include this chunk's own length, just the length of its child
/// block chunks (recursively).
int get unsplitBlockLength {
- if (_block == null) return 0;
+ if (!isBlock) return 0;
var length = 0;
- for (var chunk in _block.chunks) {
+ for (var chunk in block.chunks) {
length += chunk.length + chunk.unsplitBlockLength;
}
@@ -201,7 +197,7 @@
/// preserved whitespace often overlap. When that happens, this has logic to
/// combine that information into a single split.
void applySplit(Rule rule, int indent, NestingLevel nesting,
- {bool flushLeft, bool isDouble, bool space}) {
+ {bool? flushLeft, bool? isDouble, bool? space}) {
flushLeft ??= false;
space ??= false;
if (rule.isHardened) {
@@ -223,7 +219,7 @@
}
/// Turns this chunk into one that can contain a block of child chunks.
- void makeBlock(Chunk blockArgument) {
+ void makeBlock(Chunk? blockArgument) {
assert(_block == null);
_block = ChunkBlock(blockArgument);
}
@@ -231,18 +227,16 @@
/// Returns `true` if the block body owned by this chunk should be expression
/// indented given a set of rule values provided by [getValue].
bool indentBlock(int Function(Rule) getValue) {
- if (_block == null) return false;
- if (_block.argument == null) return false;
+ if (!isBlock) return false;
- return _block.argument.rule
- .isSplit(getValue(_block.argument.rule), _block.argument);
+ var argument = block.argument;
+ if (argument == null) return false;
+
+ return argument.rule!.isSplit(getValue(argument.rule!), argument);
}
// Mark whether this chunk can divide the range of chunks.
- void markDivide(canDivide) {
- // Should only do this once.
- assert(_canDivide == null);
-
+ void markDivide(bool canDivide) {
_canDivide = canDivide;
}
@@ -257,14 +251,15 @@
if (_isDouble == true) parts.add('double');
if (_flushLeft == true) parts.add('flush');
- if (_rule == null) {
+ var rule = _rule;
+ if (rule == null) {
parts.add('(no split)');
} else {
parts.add(rule.toString());
if (rule.isHardened) parts.add('(hard)');
- if (_rule.constrainedRules.isNotEmpty) {
- parts.add("-> ${_rule.constrainedRules.join(' ')}");
+ if (rule.constrainedRules.isNotEmpty) {
+ parts.add("-> ${rule.constrainedRules.join(' ')}");
}
}
@@ -280,7 +275,7 @@
///
/// That chunk is owned by the argument list and if it splits, this collection
/// may need extra expression-level indentation.
- final Chunk argument;
+ final Chunk? argument;
/// The child chunks in this block.
final List<Chunk> chunks = [];
@@ -403,5 +398,5 @@
bool get isInline => linesBefore == 0 && !isLineComment;
SourceComment(this.text, this.linesBefore,
- {this.isLineComment, this.flushLeft});
+ {required this.isLineComment, required this.flushLeft});
}
diff --git a/lib/src/chunk_builder.dart b/lib/src/chunk_builder.dart
index ec1c589..a17c89a 100644
--- a/lib/src/chunk_builder.dart
+++ b/lib/src/chunk_builder.dart
@@ -39,7 +39,7 @@
/// The builder for the code surrounding the block that this writer is for, or
/// `null` if this is writing the top-level code.
- final ChunkBuilder _parent;
+ final ChunkBuilder? _parent;
final SourceCode _source;
@@ -181,7 +181,7 @@
/// If [nest] is `false`, ignores any current expression nesting. Otherwise,
/// uses the current nesting level. If unsplit, it expands to a space if
/// [space] is `true`.
- Chunk split({bool flushLeft, bool isDouble, bool nest, bool space}) {
+ Chunk? split({bool? flushLeft, bool? isDouble, bool? nest, bool? space}) {
space ??= false;
// If we are not allowed to split at all, don't. Returning null for the
@@ -243,9 +243,9 @@
// new // b
// Foo();
//
- // When that happens, we need to make sure the preserve the split at the
- // end of the first sequence of comments if there is one.
- if (_pendingWhitespace == null) {
+ // When that happens, we need to make sure to preserve the split at the end
+ // of the first sequence of comments if there is one.
+ if (_pendingWhitespace == Whitespace.afterHardSplit) {
comments.first.linesBefore = 1;
_pendingWhitespace = Whitespace.none;
}
@@ -305,11 +305,11 @@
_writeCommentText(comment);
if (comment.selectionStart != null) {
- startSelectionFromEnd(comment.text.length - comment.selectionStart);
+ startSelectionFromEnd(comment.text.length - comment.selectionStart!);
}
if (comment.selectionEnd != null) {
- endSelectionFromEnd(comment.text.length - comment.selectionEnd);
+ endSelectionFromEnd(comment.text.length - comment.selectionEnd!);
}
// Make sure there is at least one newline after a line comment and allow
@@ -359,7 +359,7 @@
return;
}
- var lines = match.group(1).split('\n').toList();
+ var lines = match[1]!.split('\n').toList();
var leastIndentation = comment.text.length;
for (var i = 0; i < lines.length; i++) {
@@ -370,13 +370,13 @@
if (i > 0 && i < lines.length - 1) {
var match = _javaDocLine.firstMatch(line);
if (match != null) {
- line = match.group(1);
+ line = match[1]!;
}
}
// Find the line with the least indentation.
if (line.isNotEmpty) {
- var indentation = _leadingIndentation.firstMatch(line).group(1).length;
+ var indentation = _leadingIndentation.firstMatch(line)![1]!.length;
leastIndentation = math.min(leastIndentation, indentation);
}
@@ -440,7 +440,7 @@
/// Creates a new indentation level [spaces] deeper than the current one.
///
/// If omitted, [spaces] defaults to [Indent.block].
- void indent([int spaces]) {
+ void indent([int? spaces]) {
_nesting.indent(spaces);
}
@@ -468,14 +468,14 @@
var span = Span(openSpan.cost);
for (var i = openSpan.start; i < end; i++) {
var chunk = _chunks[i];
- if (!chunk.rule.isHardened) chunk.spans.add(span);
+ if (!chunk.rule!.isHardened) chunk.spans.add(span);
}
}
/// Starts a new [Rule].
///
/// If omitted, defaults to a new [Rule].
- void startRule([Rule rule]) {
+ void startRule([Rule? rule]) {
rule ??= Rule();
// If there are any pending lazy rules, start them now so that the proper
@@ -503,7 +503,7 @@
/// entire expression.
///
/// If [rule] is omitted, defaults to a new [Rule].
- void startLazyRule([Rule rule]) {
+ void startLazyRule([Rule? rule]) {
rule ??= Rule();
_lazyRules.add(rule);
@@ -536,7 +536,7 @@
/// If [indent] is omitted, defaults to [Indent.expression]. If [now] is
/// `true`, commits the nesting change immediately instead of waiting until
/// after the next chunk of text is written.
- void nestExpression({int indent, bool now}) {
+ void nestExpression({int? indent, bool? now}) {
now ??= false;
_nesting.nest(indent);
@@ -550,7 +550,7 @@
///
/// If [now] is `false`, does not commit the nesting change until after the
/// next chunk of text is written.
- void unnest({bool now}) {
+ void unnest({bool? now}) {
now ??= true;
_nesting.unnest();
@@ -591,7 +591,7 @@
/// Starts a new block as a child of the current chunk.
///
/// Nested blocks are handled using their own independent [LineWriter].
- ChunkBuilder startBlock(Chunk argumentChunk) {
+ ChunkBuilder startBlock(Chunk? argumentChunk) {
var chunk = _chunks.last;
chunk.makeBlock(argumentChunk);
@@ -612,7 +612,7 @@
/// `true`, the block is considered to always split.
///
/// Returns the previous writer for the surrounding block.
- ChunkBuilder endBlock(Rule ignoredSplit, {bool forceSplit}) {
+ ChunkBuilder endBlock(Rule? ignoredSplit, {required bool forceSplit}) {
_divideChunks();
// If we don't already know if the block is going to split, see if it
@@ -627,7 +627,7 @@
}
if (chunk.rule != null &&
- chunk.rule.isHardened &&
+ chunk.rule!.isHardened &&
chunk.rule != ignoredSplit) {
forceSplit = true;
break;
@@ -635,14 +635,13 @@
}
}
- _parent._endChildBlock(
+ _parent!._endChildBlock(
firstFlushLeft: _firstFlushLeft, forceSplit: forceSplit);
-
- return _parent;
+ return _parent!;
}
/// Finishes off the last chunk in a child block of this parent.
- void _endChildBlock({bool firstFlushLeft, bool forceSplit}) {
+ void _endChildBlock({bool? firstFlushLeft, required bool forceSplit}) {
// If there is a hard newline within the block, force the surrounding rule
// for it so that we apply that constraint.
if (forceSplit) forceRules();
@@ -652,7 +651,7 @@
chunk.applySplit(rule, _nesting.indentation, _blockArgumentNesting.last,
flushLeft: firstFlushLeft);
- if (chunk.rule.isHardened) _handleHardSplit();
+ if (chunk.rule!.isHardened) _handleHardSplit();
}
/// Finishes writing and returns a [SourceCode] containing the final output
@@ -838,9 +837,9 @@
/// If [flushLeft] is `true`, then the split will always cause the next line
/// to be at column zero. Otherwise, it uses the normal indentation and
/// nesting behavior.
- void _writeHardSplit({bool isDouble, bool flushLeft, bool nest = false}) {
+ void _writeHardSplit({bool? isDouble, bool? flushLeft, bool nest = false}) {
// A hard split overrides any other whitespace.
- _pendingWhitespace = null;
+ _pendingWhitespace = Whitespace.afterHardSplit;
_writeSplit(Rule.hard(),
flushLeft: flushLeft, isDouble: isDouble, nest: nest);
}
@@ -848,8 +847,8 @@
/// Ends the current chunk (if any) with the given split information.
///
/// Returns the chunk.
- Chunk _writeSplit(Rule rule,
- {bool flushLeft, bool isDouble, bool nest, bool space}) {
+ Chunk? _writeSplit(Rule rule,
+ {bool? flushLeft, bool? isDouble, bool? nest, bool? space}) {
nest ??= true;
space ??= false;
@@ -863,7 +862,7 @@
rule, _nesting.indentation, nest ? _nesting.nesting : NestingLevel(),
flushLeft: flushLeft, isDouble: isDouble, space: space);
- if (_chunks.last.rule.isHardened) _handleHardSplit();
+ if (_chunks.last.rule!.isHardened) _handleHardSplit();
return _chunks.last;
}
@@ -884,7 +883,7 @@
if (i == _chunks.length - 1) return false;
var chunk = _chunks[i];
- if (!chunk.rule.isHardened) return false;
+ if (!chunk.rule!.isHardened) return false;
if (chunk.nesting.isNested) return false;
if (chunk.isBlock) return false;
@@ -950,7 +949,7 @@
// Discard spans in hardened chunks since we know for certain they will
// split anyway.
for (var chunk in _chunks) {
- if (chunk.rule != null && chunk.rule.isHardened) {
+ if (chunk.rule != null && chunk.rule!.isHardened) {
chunk.spans.clear();
}
}
diff --git a/lib/src/cli/format_command.dart b/lib/src/cli/format_command.dart
index 5b14a7e..6f6627e 100644
--- a/lib/src/cli/format_command.dart
+++ b/lib/src/cli/format_command.dart
@@ -22,7 +22,7 @@
@override
String get invocation =>
- '${runner.executableName} $name [options...] <files or directories...>';
+ '${runner!.executableName} $name [options...] <files or directories...>';
FormatCommand({bool verbose = false}) {
defineOptions(argParser, oldCli: false, verbose: verbose);
@@ -30,6 +30,8 @@
@override
Future<int> run() async {
+ var argResults = this.argResults!;
+
if (argResults['version']) {
print(dartStyleVersion);
return 0;
@@ -39,14 +41,14 @@
'all': Show.all,
'changed': Show.changed,
'none': Show.none
- }[argResults['show']];
+ }[argResults['show']]!;
var output = const {
'write': Output.write,
'show': Output.show,
'none': Output.none,
'json': Output.json,
- }[argResults['output']];
+ }[argResults['output']]!;
var summary = Summary.none;
switch (argResults['summary'] as String) {
@@ -114,7 +116,7 @@
}
}
- List<int> selection;
+ List<int>? selection;
try {
selection = parseSelection(argResults, 'selection');
} on FormatException catch (exception) {
diff --git a/lib/src/cli/formatter_options.dart b/lib/src/cli/formatter_options.dart
index d2972a8..4748aa4 100644
--- a/lib/src/cli/formatter_options.dart
+++ b/lib/src/cli/formatter_options.dart
@@ -28,7 +28,7 @@
final bool followLinks;
/// The style fixes to apply while formatting.
- final Iterable<StyleFix> fixes;
+ final List<StyleFix> fixes;
/// Which affected files should be shown.
final Show show;
@@ -45,14 +45,17 @@
{this.indent = 0,
this.pageWidth = 80,
this.followLinks = false,
- this.fixes,
+ Iterable<StyleFix>? fixes,
this.show = Show.changed,
this.output = Output.write,
this.summary = Summary.none,
- this.setExitIfChanged = false});
+ this.setExitIfChanged = false})
+ : fixes = [...?fixes];
/// Called when [file] is about to be formatted.
- void beforeFile(File file, String label) {
+ ///
+ /// If stdin is being formatted, then [file] is `null`.
+ void beforeFile(File? file, String label) {
summary.beforeFile(file, label);
}
@@ -60,8 +63,10 @@
///
/// If the contents of the file are the same as the formatted output,
/// [changed] will be false.
- void afterFile(File file, String displayPath, SourceCode result,
- {bool changed}) {
+ ///
+ /// If stdin is being formatted, then [file] is `null`.
+ void afterFile(File? file, String displayPath, SourceCode result,
+ {required bool changed}) {
summary.afterFile(this, file, displayPath, result, changed: changed);
// Save the results to disc.
diff --git a/lib/src/cli/options.dart b/lib/src/cli/options.dart
index 30ebcc8..94f999f 100644
--- a/lib/src/cli/options.dart
+++ b/lib/src/cli/options.dart
@@ -124,7 +124,7 @@
}
}
-List<int> parseSelection(ArgResults argResults, String optionName) {
+List<int>? parseSelection(ArgResults argResults, String optionName) {
var option = argResults[optionName];
if (option == null) return null;
diff --git a/lib/src/cli/output.dart b/lib/src/cli/output.dart
index da8d241..f7d9bd7 100644
--- a/lib/src/cli/output.dart
+++ b/lib/src/cli/output.dart
@@ -24,7 +24,9 @@
const Output._();
/// Write the file to disc.
- bool writeFile(File file, String displayPath, SourceCode result) => false;
+ ///
+ /// If stdin is being formatted, then [file] is `null`.
+ bool writeFile(File? file, String displayPath, SourceCode result) => false;
/// Print the file to the terminal in some way.
void showFile(String path, SourceCode result) {}
@@ -34,12 +36,12 @@
const _WriteOutput() : super._();
@override
- bool writeFile(File file, String displayPath, SourceCode result) {
+ bool writeFile(File? file, String displayPath, SourceCode result) {
try {
- file.writeAsStringSync(result.text);
+ file!.writeAsStringSync(result.text);
} on FileSystemException catch (err) {
stderr.writeln('Could not overwrite $displayPath: '
- '${err.osError.message} (error code ${err.osError.errorCode})');
+ '${err.osError!.message} (error code ${err.osError!.errorCode})');
}
return true;
diff --git a/lib/src/cli/show.dart b/lib/src/cli/show.dart
index 810759f..e3a8863 100644
--- a/lib/src/cli/show.dart
+++ b/lib/src/cli/show.dart
@@ -36,7 +36,8 @@
/// Describes a file that was processed.
///
/// Returns whether or not this file should be displayed.
- bool file(String path, {bool changed, bool overwritten}) => true;
+ bool file(String path, {required bool changed, required bool overwritten}) =>
+ true;
/// Describes the directory whose contents are about to be processed.
void directory(String path) {}
@@ -47,7 +48,7 @@
/// Describes the hidden [path] that wasn't processed.
void hiddenPath(String path) {}
- void _showFileChange(String path, {bool overwritten}) {
+ void _showFileChange(String path, {required bool overwritten}) {
if (overwritten) {
print('Formatted $path');
} else {
@@ -58,7 +59,7 @@
mixin _ShowFileMixin on Show {
@override
- bool file(String path, {bool changed, bool overwritten}) {
+ bool file(String path, {required bool changed, required bool overwritten}) {
if (changed) {
_showFileChange(path, overwritten: overwritten);
} else {
@@ -102,7 +103,7 @@
const _ChangedShow() : super._();
@override
- bool file(String path, {bool changed, bool overwritten}) {
+ bool file(String path, {required bool changed, required bool overwritten}) {
if (changed) _showFileChange(path, overwritten: overwritten);
return changed;
}
@@ -124,7 +125,7 @@
p.relative(file, from: directory);
@override
- bool file(String path, {bool changed, bool overwritten}) {
+ bool file(String path, {required bool changed, required bool overwritten}) {
if (changed) print(path);
return true;
}
diff --git a/lib/src/cli/summary.dart b/lib/src/cli/summary.dart
index 2d238ab..f1fc122 100644
--- a/lib/src/cli/summary.dart
+++ b/lib/src/cli/summary.dart
@@ -22,15 +22,19 @@
const Summary._();
/// Called when [file] is about to be formatted.
- void beforeFile(File file, String displayPath) {}
+ ///
+ /// If stdin is being formatted, then [file] is `null`.
+ void beforeFile(File? file, String displayPath) {}
/// Describe the processed file at [path] whose formatted result is [output].
///
/// If the contents of the file are the same as the formatted output,
/// [changed] will be false.
- void afterFile(FormatterOptions options, File file, String displayPath,
+ ///
+ /// If stdin is being formatted, then [file] is `null`.
+ void afterFile(FormatterOptions options, File? file, String displayPath,
SourceCode output,
- {bool changed}) {}
+ {required bool changed}) {}
void show() {}
}
@@ -52,9 +56,9 @@
/// If the contents of the file are the same as the formatted output,
/// [changed] will be false.
@override
- void afterFile(FormatterOptions options, File file, String displayPath,
+ void afterFile(FormatterOptions options, File? file, String displayPath,
SourceCode output,
- {bool changed}) {
+ {required bool changed}) {
_files++;
if (changed) _changed++;
}
@@ -96,7 +100,7 @@
assert(_ongoing.isEmpty);
var files = _elapsed.keys.toList();
- files.sort((a, b) => _elapsed[b].compareTo(_elapsed[a]));
+ files.sort((a, b) => _elapsed[b]!.compareTo(_elapsed[a]!));
for (var file in files) {
print('${_elapsed[file]}: $file');
@@ -110,7 +114,7 @@
/// Called when [file] is about to be formatted.
@override
- void beforeFile(File file, String displayPath) {
+ void beforeFile(File? file, String displayPath) {
_ongoing[displayPath] = DateTime.now();
}
@@ -119,10 +123,10 @@
/// If the contents of the file are the same as the formatted output,
/// [changed] will be false.
@override
- void afterFile(FormatterOptions options, File file, String displayPath,
+ void afterFile(FormatterOptions options, File? file, String displayPath,
SourceCode output,
- {bool changed}) {
- var elapsed = DateTime.now().difference(_ongoing.remove(displayPath));
+ {required bool changed}) {
+ var elapsed = DateTime.now().difference(_ongoing.remove(displayPath)!);
if (elapsed.inMilliseconds >= 10) {
_elapsed[displayPath] = elapsed;
} else {
diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart
index e842bb2..eac9377 100644
--- a/lib/src/dart_formatter.dart
+++ b/lib/src/dart_formatter.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.dart_formatter;
-
import 'dart:math' as math;
import 'package:analyzer/dart/analysis/features.dart';
@@ -29,7 +26,7 @@
/// If not explicitly provided, this is inferred from the source text. If the
/// first newline is `\r\n` (Windows), it will use that. Otherwise, it uses
/// Unix-style line endings (`\n`).
- String lineEnding;
+ String? lineEnding;
/// The number of characters allowed in a single line.
final int pageWidth;
@@ -37,7 +34,7 @@
/// The number of characters of indentation to prefix the output lines with.
final int indent;
- final Set<StyleFix> fixes = {};
+ final Set<StyleFix> fixes;
/// Creates a new formatter for Dart code.
///
@@ -50,11 +47,10 @@
///
/// While formatting, also applies any of the given [fixes].
DartFormatter(
- {this.lineEnding, int pageWidth, int indent, Iterable<StyleFix> fixes})
+ {this.lineEnding, int? pageWidth, int? indent, Iterable<StyleFix>? fixes})
: pageWidth = pageWidth ?? 80,
- indent = indent ?? 0 {
- if (fixes != null) this.fixes.addAll(fixes);
- }
+ indent = indent ?? 0,
+ fixes = {...?fixes};
/// Formats the given [source] string containing an entire Dart compilation
/// unit.
@@ -106,7 +102,7 @@
uri: source.uri,
isCompilationUnit: false,
selectionStart: source.selectionStart != null
- ? source.selectionStart + inputOffset
+ ? source.selectionStart! + inputOffset
: null,
selectionLength: source.selectionLength,
);
@@ -151,7 +147,7 @@
node = body.block.statements[0];
// Make sure we consumed all of the source.
- var token = node.endToken.next;
+ var token = node.endToken.next!;
if (token.type != TokenType.CLOSE_CURLY_BRACKET) {
var stringSource = StringSource(text, source.uri);
var error = AnalysisError(
diff --git a/lib/src/debug.dart b/lib/src/debug.dart
index 9068af9..5934afd 100644
--- a/lib/src/debug.dart
+++ b/lib/src/debug.dart
@@ -3,12 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
/// Internal debugging utilities.
-library dart_style.src.debug;
-
import 'dart:math' as math;
import 'chunk.dart';
import 'line_splitting/rule_set.dart';
+import 'rule/rule.dart';
/// Set this to `true` to turn on diagnostic output while building chunks.
bool traceChunkBuilder = false;
@@ -127,19 +126,19 @@
}
}
- if (chunk.rule == null) {
+ var rule = chunk.rule;
+ if (rule == null) {
row.add('');
row.add('(no rule)');
row.add('');
} else {
- writeIf(chunk.rule.cost != 0, () => '\$${chunk.rule.cost}');
+ writeIf(rule.cost != 0, () => '\$${rule.cost}');
- var ruleString = chunk.rule.toString();
- if (chunk.rule.isHardened) ruleString += '!';
+ var ruleString = rule.toString();
+ if (rule.isHardened) ruleString += '!';
row.add(ruleString);
- var constrainedRules =
- chunk.rule.constrainedRules.toSet().intersection(rules);
+ var constrainedRules = rule.constrainedRules.toSet().intersection(rules);
writeIf(constrainedRules.isNotEmpty,
() => "-> ${constrainedRules.join(" ")}");
}
@@ -147,10 +146,9 @@
writeIf(chunk.indent != null && chunk.indent != 0,
() => 'indent ${chunk.indent}');
- writeIf(chunk.nesting != null && chunk.nesting.indent != 0,
- () => 'nest ${chunk.nesting}');
+ writeIf(chunk.nesting.indent != 0, () => 'nest ${chunk.nesting}');
- writeIf(chunk.flushLeft != null && chunk.flushLeft, () => 'flush');
+ writeIf(chunk.flushLeft, () => 'flush');
writeIf(chunk.canDivide, () => 'divide');
@@ -193,8 +191,7 @@
/// Shows all of the constraints between the rules used by [chunks].
void dumpConstraints(List<Chunk> chunks) {
- var rules =
- chunks.map((chunk) => chunk.rule).where((rule) => rule != null).toSet();
+ var rules = chunks.map((chunk) => chunk.rule).whereType<Rule>().toSet();
for (var rule in rules) {
var constrainedValues = [];
diff --git a/lib/src/exceptions.dart b/lib/src/exceptions.dart
index 8e8dcfe..86488a4 100644
--- a/lib/src/exceptions.dart
+++ b/lib/src/exceptions.dart
@@ -17,7 +17,7 @@
const FormatterException(this.errors);
/// Creates a human-friendly representation of the analysis errors.
- String message({bool color}) {
+ String message({bool? color}) {
var buffer = StringBuffer();
buffer.writeln('Could not format because the source could not be parsed:');
diff --git a/lib/src/io.dart b/lib/src/io.dart
index 893ad95..c0064b4 100644
--- a/lib/src/io.dart
+++ b/lib/src/io.dart
@@ -14,8 +14,8 @@
import 'exceptions.dart';
import 'source_code.dart';
-/// Reads input from stdin until it's closed, and the formats it.
-void formatStdin(FormatterOptions options, List<int> selection, String name) {
+/// Reads and formats input from stdin until closed.
+void formatStdin(FormatterOptions options, List<int>? selection, String name) {
var selectionStart = 0;
var selectionLength = 0;
@@ -129,7 +129,7 @@
/// Runs the formatter on [file].
///
/// Returns `true` if successful or `false` if an error occurred.
-bool processFile(FormatterOptions options, File file, {String displayPath}) {
+bool processFile(FormatterOptions options, File file, {String? displayPath}) {
displayPath ??= file.path;
var formatter = DartFormatter(
diff --git a/lib/src/line_splitting/line_splitter.dart b/lib/src/line_splitting/line_splitter.dart
index 137c21e..8ef5926 100644
--- a/lib/src/line_splitting/line_splitter.dart
+++ b/lib/src/line_splitting/line_splitter.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.line_splitting.line_splitter;
-
import '../chunk.dart';
import '../debug.dart' as debug;
import '../line_writer.dart';
@@ -121,9 +118,6 @@
/// and can stop looking.
final _queue = SolveStateQueue();
- /// The lowest cost solution found so far.
- SolveState _bestSolution;
-
/// Creates a new splitter for [_writer] that tries to fit [chunks] into the
/// page width.
LineSplitter(this.writer, List<Chunk> chunks, int blockIndentation,
@@ -133,7 +127,7 @@
// Collect the set of rules that we need to select values for.
rules = chunks
.map((chunk) => chunk.rule)
- .where((rule) => rule != null)
+ .whereType<Rule>()
.toSet()
.toList(growable: false),
blockIndentation = blockIndentation,
@@ -165,20 +159,22 @@
// Start with a completely unbound, unsplit solution.
_queue.add(SolveState(this, RuleSet(rules.length)));
+ SolveState? bestSolution;
+
var attempts = 0;
while (_queue.isNotEmpty) {
var state = _queue.removeFirst();
- if (state.isBetterThan(_bestSolution)) {
- _bestSolution = state;
+ if (state.isBetterThan(bestSolution)) {
+ bestSolution = state;
// Since we sort solutions by cost the first solution we find that
// fits is the winner.
- if (_bestSolution.overflowChars == 0) break;
+ if (bestSolution.overflowChars == 0) break;
}
if (debug.traceSplitter) {
- var best = state == _bestSolution ? ' (best)' : '';
+ var best = state == bestSolution ? ' (best)' : '';
debug.log('$state$best');
debug.dumpLines(chunks, firstLineIndent, state.splits);
debug.log();
@@ -191,12 +187,12 @@
}
if (debug.traceSplitter) {
- debug.log('$_bestSolution (winner)');
- debug.dumpLines(chunks, firstLineIndent, _bestSolution.splits);
+ debug.log('$bestSolution (winner)');
+ debug.dumpLines(chunks, firstLineIndent, bestSolution!.splits);
debug.log();
}
- return _bestSolution.splits;
+ return bestSolution!.splits;
}
void enqueue(SolveState state) {
diff --git a/lib/src/line_splitting/rule_set.dart b/lib/src/line_splitting/rule_set.dart
index 2d365ab..acffb83 100644
--- a/lib/src/line_splitting/rule_set.dart
+++ b/lib/src/line_splitting/rule_set.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.line_splitting.rule_set;
-
import '../rule/rule.dart';
/// An optimized data structure for storing a set of values for some rules.
@@ -16,7 +13,7 @@
/// Internally, this then just stores the values in a sparse list whose indices
/// are the indices of the rules.
class RuleSet {
- List<int> _values;
+ List<int?> _values;
RuleSet(int numRules) : this._(List.filled(numRules, null));
@@ -27,7 +24,7 @@
// Treat hardened rules as implicitly bound.
if (rule.isHardened) return true;
- return _values[rule.index] != null;
+ return _values[rule.index!] != null;
}
/// Gets the bound value for [rule] or [Rule.unsplit] if it is not bound.
@@ -35,7 +32,7 @@
// Hardened rules are implicitly bound.
if (rule.isHardened) return rule.fullySplitValue;
- var value = _values[rule.index];
+ var value = _values[rule.index!];
if (value != null) return value;
return Rule.unsplit;
@@ -67,7 +64,7 @@
List<Rule> rules, Rule rule, int value, void Function(Rule) onSplitRule) {
assert(!rule.isHardened);
- _values[rule.index] = value;
+ _values[rule.index!] = value;
// Test this rule against the other rules being bound.
for (var other in rule.constrainedRules) {
@@ -76,7 +73,7 @@
if (other.isHardened) {
otherValue = other.fullySplitValue;
} else {
- otherValue = _values[other.index];
+ otherValue = _values[other.index!];
}
var constraint = rule.constrain(value, other);
@@ -127,18 +124,17 @@
/// chosen column is for the following line.
///
/// Internally, this uses a list where each element corresponds to the column
-/// of the chunk at that index in the chunk list, or `null` if that chunk did
-/// not split. This had about a 10% perf improvement over using a [Set] of
-/// splits.
+/// of the chunk at that index in the chunk list, or `-1` if that chunk did not
+/// split. This had about a 10% perf improvement over using a [Set] of splits.
class SplitSet {
final List<int> _columns;
/// The cost of the solution that led to these splits.
int get cost => _cost;
- int _cost;
+ late final int _cost;
/// Creates a new empty split set for a line with [numChunks].
- SplitSet(int numChunks) : _columns = List.filled(numChunks - 1, null);
+ SplitSet(int numChunks) : _columns = List.filled(numChunks - 1, -1);
/// Marks the line after chunk [index] as starting at [column].
void add(int index, int column) {
@@ -147,7 +143,7 @@
/// Returns `true` if the chunk at [splitIndex] should be split.
bool shouldSplitAt(int index) =>
- index < _columns.length && _columns[index] != null;
+ index < _columns.length && _columns[index] != -1;
/// Gets the zero-based starting column for the chunk at [index].
int getColumn(int index) => _columns[index];
@@ -156,7 +152,6 @@
///
/// This can only be called once.
void setCost(int cost) {
- assert(_cost == null);
_cost = cost;
}
@@ -164,7 +159,7 @@
String toString() {
var result = [];
for (var i = 0; i < _columns.length; i++) {
- if (_columns[i] != null) {
+ if (_columns[i] != -1) {
result.add('$i:${_columns[i]}');
}
}
diff --git a/lib/src/line_splitting/solve_state.dart b/lib/src/line_splitting/solve_state.dart
index 8f202a2..708353e 100644
--- a/lib/src/line_splitting/solve_state.dart
+++ b/lib/src/line_splitting/solve_state.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.line_splitting.solve_state;
-
import '../chunk.dart';
import '../debug.dart' as debug;
import '../nesting_level.dart';
@@ -31,12 +28,12 @@
/// The set of [Rule]s that are bound by [_ruleValues].
///
/// Cached by [_ensureConstraints] for use by [_ensureUnboundConstraints].
- Set<Rule> _boundRules;
+ late Set<Rule> _boundRules;
/// The set of [Rule]s that are not bound by [_ruleValues].
///
/// Cached by [_ensureConstraints] for use by [_ensureUnboundConstraints].
- Set<Rule> _unboundRules;
+ late Set<Rule> _unboundRules;
/// The unbound rules in this state that can be bound to produce new more
/// refined states.
@@ -68,12 +65,12 @@
/// The set of splits chosen for this state.
SplitSet get splits => _splits;
- SplitSet _splits;
+ late final SplitSet _splits;
/// The number of characters that do not fit inside the page with this set of
/// splits.
int get overflowChars => _overflowChars;
- int _overflowChars;
+ int _overflowChars = 0;
/// Whether we can treat this state as a complete solution by leaving its
/// unbound rules unsplit.
@@ -86,7 +83,7 @@
/// The constraints the bound rules in this state have on the remaining
/// unbound rules.
- Map<Rule, int> _constraints;
+ late final Map<Rule, int> _constraints = _initConstraints();
/// The unbound rule values that are disallowed because they would place
/// invalid constraints on the currently bound values.
@@ -99,14 +96,16 @@
///
/// It's important to track this, because we can't allow to states to overlap
/// if one permits more values for some unbound rule than the other does.
- Map<Rule, Set<int>> _unboundConstraints;
+ late final Map<Rule, Set<int>> _unboundConstraints =
+ _initUnboundConstraints();
/// The bound rules that appear inside lines also containing unbound rules.
///
/// By appearing in the same line, it means these bound rules may affect the
/// results of binding those unbound rules. This is used to tell if two
/// states may diverge by binding unbound rules or not.
- Set<Rule> _boundRulesInUnboundLines;
+ late final Set<Rule> _boundRulesInUnboundLines =
+ _initBoundRulesInUnboundLines();
SolveState(this._splitter, this._ruleValues) {
_calculateSplits();
@@ -119,7 +118,7 @@
/// Returns `true` if this state is a better solution to use as the final
/// result than [other].
- bool isBetterThan(SolveState other) {
+ bool isBetterThan(SolveState? other) {
// If this state contains an unbound rule that we know can't be left
// unsplit, we can't pick this as a solution.
if (!_isComplete) return false;
@@ -197,10 +196,10 @@
for (var value = 1; value < rule.numValues; value++) {
var boundRules = unsplitRules.clone();
- List<Rule> mustSplitRules;
+ List<Rule>? mustSplitRules;
var valid = boundRules.tryBind(_splitter.rules, rule, value, (rule) {
mustSplitRules ??= [];
- mustSplitRules.add(rule);
+ mustSplitRules!.add(rule);
});
// Make sure we don't violate the constraints of the bound rules.
@@ -211,7 +210,7 @@
// If some unbound rules are constrained to split, remember that.
if (mustSplitRules != null) {
state._isComplete = false;
- state._liveRules.addAll(mustSplitRules);
+ state._liveRules.addAll(mustSplitRules!);
}
_splitter.enqueue(state);
@@ -236,8 +235,6 @@
bool _isOverlapping(SolveState other) {
// Lines that contain both bound and unbound rules must have the same
// bound values.
- _ensureBoundRulesInUnboundLines();
- other._ensureBoundRulesInUnboundLines();
if (_boundRulesInUnboundLines.length !=
other._boundRulesInUnboundLines.length) {
return false;
@@ -250,23 +247,19 @@
}
}
- _ensureConstraints();
- other._ensureConstraints();
if (_constraints.length != other._constraints.length) return false;
for (var rule in _constraints.keys) {
if (_constraints[rule] != other._constraints[rule]) return false;
}
- _ensureUnboundConstraints();
- other._ensureUnboundConstraints();
if (_unboundConstraints.length != other._unboundConstraints.length) {
return false;
}
for (var rule in _unboundConstraints.keys) {
- var disallowed = _unboundConstraints[rule];
- var otherDisallowed = other._unboundConstraints[rule];
+ var disallowed = _unboundConstraints[rule]!;
+ var otherDisallowed = other._unboundConstraints[rule]!;
if (disallowed.length != otherDisallowed.length) return false;
for (var value in disallowed) {
@@ -285,7 +278,7 @@
var usedNestingLevels = <NestingLevel>{};
for (var i = 0; i < _splitter.chunks.length - 1; i++) {
var chunk = _splitter.chunks[i];
- if (chunk.rule.isSplit(getValue(chunk.rule), chunk)) {
+ if (chunk.rule!.isSplit(getValue(chunk.rule!), chunk)) {
usedNestingLevels.add(chunk.nesting);
chunk.nesting.clearTotalUsedIndent();
}
@@ -298,11 +291,11 @@
_splits = SplitSet(_splitter.chunks.length);
for (var i = 0; i < _splitter.chunks.length - 1; i++) {
var chunk = _splitter.chunks[i];
- if (chunk.rule.isSplit(getValue(chunk.rule), chunk)) {
+ if (chunk.rule!.isSplit(getValue(chunk.rule!), chunk)) {
var indent = 0;
if (!chunk.flushLeftAfter) {
// Add in the chunk's indent.
- indent = _splitter.blockIndentation + chunk.indent;
+ indent = _splitter.blockIndentation + chunk.indent!;
// And any expression nesting.
indent += chunk.nesting.totalUsedIndent;
@@ -318,13 +311,9 @@
/// Evaluates the cost (i.e. the relative "badness") of splitting the line
/// into [lines] physical lines based on the current set of rules.
void _calculateCost() {
- assert(_splits != null);
-
// Calculate the length of each line and apply the cost of any spans that
// get split.
var cost = 0;
- _overflowChars = 0;
-
var length = _splitter.firstLineIndent;
// The unbound rules in use by the current line. This will be null after
@@ -435,7 +424,7 @@
///
/// Only does this if [rule] is a valid soft rule. Returns `true` if any new
/// live rules were added.
- bool _addLiveRules(Rule rule) {
+ bool _addLiveRules(Rule? rule) {
if (rule == null) return false;
var added = false;
@@ -449,22 +438,19 @@
return added;
}
- /// Lazily initializes the [_boundInUnboundLines], which is needed to compare
+ /// Used to lazy initialize [_boundInUnboundLines], which is needed to compare
/// two states for overlap.
///
/// We do this lazily because the calculation is a bit slow, and is only
/// needed when we have two states with the same score.
- void _ensureBoundRulesInUnboundLines() {
- if (_boundRulesInUnboundLines != null) return;
-
- _boundRulesInUnboundLines = <Rule>{};
-
+ Set<Rule> _initBoundRulesInUnboundLines() {
+ var rules = <Rule>{};
var boundInLine = <Rule>{};
var hasUnbound = false;
for (var i = 0; i < _splitter.chunks.length - 1; i++) {
if (splits.shouldSplitAt(i)) {
- if (hasUnbound) _boundRulesInUnboundLines.addAll(boundInLine);
+ if (hasUnbound) rules.addAll(boundInLine);
boundInLine.clear();
hasUnbound = false;
@@ -480,17 +466,16 @@
}
}
- if (hasUnbound) _boundRulesInUnboundLines.addAll(boundInLine);
+ if (hasUnbound) rules.addAll(boundInLine);
+ return rules;
}
- /// Lazily initializes the [_constraints], which is needed to compare two
- /// states for overlap.
+ /// Used to lazy initializes the [_constraints], which is needed to compare
+ /// two states for overlap.
///
/// We do this lazily because the calculation is a bit slow, and is only
/// needed when we have two states with the same score.
- void _ensureConstraints() {
- if (_constraints != null) return;
-
+ Map<Rule, int> _initConstraints() {
_unboundRules = <Rule>{};
_boundRules = <Rule>{};
@@ -502,7 +487,7 @@
}
}
- _constraints = {};
+ var constraints = <Rule, int>{};
for (var bound in _boundRules) {
for (var unbound in bound.constrainedRules) {
@@ -511,28 +496,24 @@
var value = _ruleValues.getValue(bound);
var constraint = bound.constrain(value, unbound);
if (constraint != null) {
- _constraints[unbound] = constraint;
+ constraints[unbound] = constraint;
}
}
}
+
+ return constraints;
}
- /// Lazily initializes the [_unboundConstraints], which is needed to compare
- /// two states for overlap.
+ /// Used to lazy initialize the [_unboundConstraints], which is needed to
+ /// compare two states for overlap.
///
/// We do this lazily because the calculation is a bit slow, and is only
/// needed when we have two states with the same score.
- void _ensureUnboundConstraints() {
- if (_unboundConstraints != null) return;
-
- // _ensureConstraints should be called first which initializes these.
- assert(_boundRules != null);
- assert(_unboundRules != null);
-
- _unboundConstraints = {};
-
+ Map<Rule, Set<int>> _initUnboundConstraints() {
+ var unboundConstraints = <Rule, Set<int>>{};
for (var unbound in _unboundRules) {
- Set<int> disallowedValues;
+ // Lazily create and add the set to the constraints only if needed.
+ late final disallowedValues = unboundConstraints[unbound] = {};
for (var bound in unbound.constrainedRules) {
if (!_boundRules.contains(bound)) continue;
@@ -555,15 +536,12 @@
continue;
}
- if (disallowedValues == null) {
- disallowedValues = <int>{};
- _unboundConstraints[unbound] = disallowedValues;
- }
-
disallowedValues.add(value);
}
}
}
+
+ return unboundConstraints;
}
@override
@@ -592,7 +570,6 @@
if (overflowChars > 0) buffer.write(' (${overflowChars} over)');
if (!_isComplete) buffer.write(' (incomplete)');
- if (splits == null) buffer.write(' invalid');
return buffer.toString();
}
diff --git a/lib/src/line_splitting/solve_state_queue.dart b/lib/src/line_splitting/solve_state_queue.dart
index a299e15..c8efdbb 100644
--- a/lib/src/line_splitting/solve_state_queue.dart
+++ b/lib/src/line_splitting/solve_state_queue.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.line_splitting.solve_state_queue;
-
import 'line_splitter.dart';
import 'solve_state.dart';
@@ -22,10 +19,10 @@
/// number of "tree levels" in the heap is only done for aesthetic reasons.
static const int _initialCapacity = 7;
- LineSplitter _splitter;
+ late final LineSplitter _splitter;
/// List implementation of a heap.
- List<SolveState> _queue = List<SolveState>.filled(_initialCapacity, null);
+ List<SolveState?> _queue = List.filled(_initialCapacity, null);
/// Number of elements in queue.
/// The heap is implemented in the first [_length] entries of [_queue].
@@ -34,9 +31,6 @@
bool get isNotEmpty => _length != 0;
void bindSplitter(LineSplitter splitter) {
- // Only do this once.
- assert(_splitter == null);
-
_splitter = splitter;
}
@@ -50,7 +44,7 @@
var newCapacity = _queue.length * 2 + 1;
if (newCapacity < _initialCapacity) newCapacity = _initialCapacity;
- var newQueue = List<SolveState>.filled(newCapacity, null);
+ var newQueue = List<SolveState?>.filled(newCapacity, null);
newQueue.setRange(0, _length, _queue);
_queue = newQueue;
}
@@ -62,12 +56,12 @@
assert(_length > 0);
// Remove the highest priority state.
- var result = _queue[0];
+ var result = _queue[0]!;
_length--;
// Fill the gap with the one at the end of the list and re-heapify.
if (_length > 0) {
- var last = _queue[_length];
+ var last = _queue[_length]!;
_queue[_length] = null;
_bubbleDown(last, 0);
}
@@ -135,7 +129,7 @@
// also have lower priority.
do {
var index = position - 1;
- var enqueued = _queue[index];
+ var enqueued = _queue[index]!;
var comparison = _compareScore(enqueued, state);
@@ -185,7 +179,7 @@
void _bubbleUp(SolveState element, int index) {
while (index > 0) {
var parentIndex = (index - 1) ~/ 2;
- var parent = _queue[parentIndex];
+ var parent = _queue[parentIndex]!;
if (_compare(element, parent) > 0) break;
@@ -205,8 +199,8 @@
while (rightChildIndex < _length) {
var leftChildIndex = rightChildIndex - 1;
- var leftChild = _queue[leftChildIndex];
- var rightChild = _queue[rightChildIndex];
+ var leftChild = _queue[leftChildIndex]!;
+ var rightChild = _queue[rightChildIndex]!;
var comparison = _compare(leftChild, rightChild);
var minChildIndex;
@@ -234,7 +228,7 @@
var leftChildIndex = rightChildIndex - 1;
if (leftChildIndex < _length) {
- var child = _queue[leftChildIndex];
+ var child = _queue[leftChildIndex]!;
var comparison = _compare(element, child);
if (comparison > 0) {
diff --git a/lib/src/line_writer.dart b/lib/src/line_writer.dart
index 748bb9b..e8874a8 100644
--- a/lib/src/line_writer.dart
+++ b/lib/src/line_writer.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.line_writer;
-
import 'chunk.dart';
import 'dart_formatter.dart';
import 'debug.dart' as debug;
@@ -35,19 +32,19 @@
///
/// This will be `null` if there is no selection or the writer hasn't reached
/// the beginning of the selection yet.
- int _selectionStart;
+ int? _selectionStart;
/// The offset in [_buffer] where the selection ends in the formatted code.
///
/// This will be `null` if there is no selection or the writer hasn't reached
/// the end of the selection yet.
- int _selectionEnd;
+ int? _selectionEnd;
/// The number of characters that have been written to the output.
int get length => _buffer.length;
LineWriter(DartFormatter formatter, this._chunks)
- : _lineEnding = formatter.lineEnding,
+ : _lineEnding = formatter.lineEnding!,
pageWidth = formatter.pageWidth,
_blockIndentation = 0,
_blockCache = {};
@@ -114,7 +111,7 @@
// Get ready for the next line.
newlines = chunk.isDouble ? 2 : 1;
- indent = chunk.indent;
+ indent = chunk.indent!;
flushLeft = chunk.flushLeft;
start = i + 1;
}
@@ -134,7 +131,7 @@
/// Takes the chunks from [start] to [end] with leading [indent], removes
/// them, and runs the [LineSplitter] on them.
int _completeLine(int newlines, int indent, int start, int end,
- {bool flushLeft}) {
+ {required bool flushLeft}) {
// Write the newlines required by the previous line.
for (var j = 0; j < newlines; j++) {
_buffer.write(_lineEnding);
@@ -175,11 +172,11 @@
// If this block contains one of the selection markers, tell the
// writer where it ended up in the final output.
if (block.selectionStart != null) {
- _selectionStart = length + block.selectionStart;
+ _selectionStart = length + block.selectionStart!;
}
if (block.selectionEnd != null) {
- _selectionEnd = length + block.selectionEnd;
+ _selectionEnd = length + block.selectionEnd!;
}
_buffer.write(block.text);
@@ -220,11 +217,11 @@
/// contains a selection marker.
void _writeChunk(Chunk chunk) {
if (chunk.selectionStart != null) {
- _selectionStart = length + chunk.selectionStart;
+ _selectionStart = length + chunk.selectionStart!;
}
if (chunk.selectionEnd != null) {
- _selectionEnd = length + chunk.selectionEnd;
+ _selectionEnd = length + chunk.selectionEnd!;
}
_buffer.write(chunk.text);
@@ -269,13 +266,13 @@
/// if it was contained within this split list of chunks.
///
/// Otherwise, this is `null`.
- final int selectionStart;
+ final int? selectionStart;
/// Where in the resulting buffer the selection end point should appear if it
/// was contained within this split list of chunks.
///
/// Otherwise, this is `null`.
- final int selectionEnd;
+ final int? selectionEnd;
FormatResult(this.text, this.cost, this.selectionStart, this.selectionEnd);
}
diff --git a/lib/src/nesting_builder.dart b/lib/src/nesting_builder.dart
index 8ed62f1..4740114 100644
--- a/lib/src/nesting_builder.dart
+++ b/lib/src/nesting_builder.dart
@@ -51,7 +51,7 @@
///
/// Here, if we discard the expression nesting before we reach the "{", then
/// it won't get indented as it should.
- NestingLevel _pendingNesting;
+ NestingLevel? _pendingNesting;
/// The current number of characters of block indentation.
int get indentation => _stack.last;
@@ -66,7 +66,7 @@
/// Creates a new indentation level [spaces] deeper than the current one.
///
/// If omitted, [spaces] defaults to [Indent.block].
- void indent([int spaces]) {
+ void indent([int? spaces]) {
spaces ??= Indent.block;
// Indentation should only change outside of nesting.
@@ -95,11 +95,11 @@
/// if the previous line has a lower level of nesting.
///
/// If [indent] is omitted, defaults to [Indent.expression].
- void nest([int indent]) {
+ void nest([int? indent]) {
indent ??= Indent.expression;
if (_pendingNesting != null) {
- _pendingNesting = _pendingNesting.nest(indent);
+ _pendingNesting = _pendingNesting!.nest(indent);
} else {
_pendingNesting = _nesting.nest(indent);
}
@@ -108,7 +108,7 @@
/// Discards the most recent level of expression nesting.
void unnest() {
if (_pendingNesting != null) {
- _pendingNesting = _pendingNesting.parent;
+ _pendingNesting = _pendingNesting!.parent;
} else {
_pendingNesting = _nesting.parent;
}
@@ -121,7 +121,7 @@
void commitNesting() {
if (_pendingNesting == null) return;
- _nesting = _pendingNesting;
+ _nesting = _pendingNesting!;
_pendingNesting = null;
}
}
diff --git a/lib/src/nesting_level.dart b/lib/src/nesting_level.dart
index c1088c6..acbdfe3 100644
--- a/lib/src/nesting_level.dart
+++ b/lib/src/nesting_level.dart
@@ -24,8 +24,8 @@
class NestingLevel extends FastHash {
/// The nesting level surrounding this one, or `null` if this is represents
/// top level code in a block.
- NestingLevel get parent => _parent;
- NestingLevel _parent;
+ NestingLevel? get parent => _parent;
+ NestingLevel? _parent;
/// The number of characters that this nesting level is indented relative to
/// the containing level.
@@ -37,8 +37,8 @@
/// its parents, after determining which nesting levels are actually used.
///
/// This is only valid during line splitting.
- int get totalUsedIndent => _totalUsedIndent;
- int _totalUsedIndent;
+ int get totalUsedIndent => _totalUsedIndent!;
+ int? _totalUsedIndent;
bool get isNested => _parent != null;
@@ -53,22 +53,25 @@
/// Clears the previously calculated total indent of this nesting level.
void clearTotalUsedIndent() {
_totalUsedIndent = null;
- if (_parent != null) _parent.clearTotalUsedIndent();
+ _parent?.clearTotalUsedIndent();
}
/// Calculates the total amount of indentation from this nesting level and
/// all of its parents assuming only [usedNesting] levels are in use.
void refreshTotalUsedIndent(Set<NestingLevel> usedNesting) {
- if (_totalUsedIndent != null) return;
+ var totalIndent = _totalUsedIndent;
+ if (totalIndent != null) return;
- _totalUsedIndent = 0;
+ totalIndent = 0;
if (_parent != null) {
- _parent.refreshTotalUsedIndent(usedNesting);
- _totalUsedIndent += _parent.totalUsedIndent;
+ _parent!.refreshTotalUsedIndent(usedNesting);
+ totalIndent += _parent!.totalUsedIndent;
}
- if (usedNesting.contains(this)) _totalUsedIndent += indent;
+ if (usedNesting.contains(this)) totalIndent += indent;
+
+ _totalUsedIndent = totalIndent;
}
@override
diff --git a/lib/src/rule/argument.dart b/lib/src/rule/argument.dart
index a483e4e..7ff8378 100644
--- a/lib/src/rule/argument.dart
+++ b/lib/src/rule/argument.dart
@@ -1,19 +1,16 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.rule.argument;
-
import '../chunk.dart';
import 'rule.dart';
/// Base class for a rule that handles argument or parameter lists.
abstract class ArgumentRule extends Rule {
/// The chunks prior to each positional argument.
- final List<Chunk> _arguments = [];
+ final List<Chunk?> _arguments = [];
/// The rule used to split collections in the argument list, if any.
- Rule _collectionRule;
+ Rule? _collectionRule;
/// The number of leading collection arguments.
///
@@ -43,20 +40,18 @@
@override
void addConstrainedRules(Set<Rule> rules) {
super.addConstrainedRules(rules);
- if (_collectionRule != null) rules.add(_collectionRule);
+ if (_collectionRule != null) rules.add(_collectionRule!);
}
@override
void forgetUnusedRules() {
super.forgetUnusedRules();
- if (_collectionRule != null && _collectionRule.index == null) {
- _collectionRule = null;
- }
+ if (_collectionRule?.index == null) _collectionRule = null;
}
/// Remembers [chunk] as containing the split that occurs right before an
/// argument in the list.
- void beforeArgument(Chunk chunk) {
+ void beforeArgument(Chunk? chunk) {
_arguments.add(chunk);
}
@@ -93,14 +88,14 @@
class PositionalRule extends ArgumentRule {
/// If there are named arguments following these positional ones, this will
/// be their rule.
- Rule _namedArgsRule;
+ Rule? _namedArgsRule;
/// Creates a new rule for a positional argument list.
///
/// If [_collectionRule] is given, it is the rule used to split the collection
/// arguments in the list.
PositionalRule(
- Rule collectionRule, int leadingCollections, int trailingCollections)
+ Rule? collectionRule, int leadingCollections, int trailingCollections)
: super(collectionRule, leadingCollections, trailingCollections);
@override
@@ -126,15 +121,13 @@
@override
void addConstrainedRules(Set<Rule> rules) {
super.addConstrainedRules(rules);
- if (_namedArgsRule != null) rules.add(_namedArgsRule);
+ if (_namedArgsRule != null) rules.add(_namedArgsRule!);
}
@override
void forgetUnusedRules() {
super.forgetUnusedRules();
- if (_namedArgsRule != null && _namedArgsRule.index == null) {
- _namedArgsRule = null;
- }
+ if (_namedArgsRule?.index == null) _namedArgsRule = null;
}
@override
@@ -186,14 +179,14 @@
/// argument,
/// argument, named: argument);
@override
- int constrain(int value, Rule other) {
+ int? constrain(int value, Rule other) {
var constrained = super.constrain(value, other);
if (constrained != null) return constrained;
// Handle the relationship between the positional and named args.
if (other == _namedArgsRule) {
// If the positional args are one-per-line, the named args are too.
- if (value == fullySplitValue) return _namedArgsRule.fullySplitValue;
+ if (value == fullySplitValue) return _namedArgsRule!.fullySplitValue;
// Otherwise, if there is any split in the positional arguments, don't
// allow the named arguments on the same line as them.
@@ -257,7 +250,7 @@
int get numValues => 3;
NamedRule(
- Rule collectionRule, int leadingCollections, int trailingCollections)
+ Rule? collectionRule, int leadingCollections, int trailingCollections)
: super(collectionRule, leadingCollections, trailingCollections);
@override
@@ -270,7 +263,7 @@
}
@override
- int constrain(int value, Rule other) {
+ int? constrain(int value, Rule other) {
var constrained = super.constrain(value, other);
if (constrained != null) return constrained;
diff --git a/lib/src/rule/metadata.dart b/lib/src/rule/metadata.dart
index c552101..3d59e96 100644
--- a/lib/src/rule/metadata.dart
+++ b/lib/src/rule/metadata.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.rule.metadata;
-
import 'argument.dart';
import 'rule.dart';
@@ -17,8 +14,8 @@
/// Also, if the annotations split, we force the entire parameter list to fully
/// split, both named and positional.
class MetadataRule extends Rule {
- Rule _positionalRule;
- Rule _namedRule;
+ Rule? _positionalRule;
+ Rule? _namedRule;
/// Remembers that [rule] is the [PositionalRule] used by the argument list
/// containing the parameter metadata using this rule.
@@ -35,7 +32,7 @@
/// Constrains the surrounding argument list rules to fully split if the
/// metadata does.
@override
- int constrain(int value, Rule other) {
+ int? constrain(int value, Rule other) {
var constrained = super.constrain(value, other);
if (constrained != null) return constrained;
@@ -43,27 +40,22 @@
if (value == Rule.unsplit) return null;
// Otherwise, they have to split.
- if (other == _positionalRule) return _positionalRule.fullySplitValue;
- if (other == _namedRule) return _namedRule.fullySplitValue;
+ if (other == _positionalRule) return _positionalRule!.fullySplitValue;
+ if (other == _namedRule) return _namedRule!.fullySplitValue;
return null;
}
@override
void addConstrainedRules(Set<Rule> rules) {
- if (_positionalRule != null) rules.add(_positionalRule);
- if (_namedRule != null) rules.add(_namedRule);
+ if (_positionalRule != null) rules.add(_positionalRule!);
+ if (_namedRule != null) rules.add(_namedRule!);
}
@override
void forgetUnusedRules() {
super.forgetUnusedRules();
- if (_positionalRule != null && _positionalRule.index == null) {
- _positionalRule = null;
- }
-
- if (_namedRule != null && _namedRule.index == null) {
- _namedRule = null;
- }
+ if (_positionalRule?.index == null) _positionalRule = null;
+ if (_namedRule?.index == null) _namedRule = null;
}
}
diff --git a/lib/src/rule/rule.dart b/lib/src/rule/rule.dart
index 7813bf1..660b8d0 100644
--- a/lib/src/rule/rule.dart
+++ b/lib/src/rule/rule.dart
@@ -2,8 +2,6 @@
// 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.
-library dart_style.src.rule.rule;
-
import '../chunk.dart';
import '../fast_hash.dart';
@@ -40,7 +38,7 @@
/// During line splitting [LineSplitter] sets this to the index of this
/// rule in its list of rules.
- int index;
+ int? index;
/// If `true`, the rule has been "hardened" meaning it's been placed into a
/// permanent "must fully split" state.
@@ -75,7 +73,7 @@
/// rules.
bool get splitsOnInnerRules => true;
- Rule([int cost]) : _cost = cost ?? Cost.normal;
+ Rule([int? cost]) : _cost = cost ?? Cost.normal;
/// Creates a new rule that is already fully split.
Rule.hard() : _cost = 0 {
@@ -114,8 +112,8 @@
/// Allows relationships between rules like "if I split, then this should
/// split too". Returns a non-negative value to force [other] to take that
/// value. Returns -1 to allow [other] to take any non-zero value. Returns
- /// null to not constrain other.
- int constrain(int value, Rule other) {
+ /// `null` to not constrain other.
+ int? constrain(int value, Rule other) {
// By default, any containing rule will be fully split if this one is split.
if (value == Rule.unsplit) return null;
if (_implied.contains(other)) return other.fullySplitValue;
@@ -151,35 +149,40 @@
// Lazy initialize this on first use. Note: Assumes this is only called
// after the chunks have been written and any constraints have been wired
// up.
- if (_constrainedRules == null) {
- _constrainedRules = _implied.toSet();
- addConstrainedRules(_constrainedRules);
- }
+ var rules = _constrainedRules;
+ if (rules != null) return rules;
- return _constrainedRules;
+ rules = _implied.toSet();
+ addConstrainedRules(rules);
+ _constrainedRules = rules;
+ return rules;
}
- Set<Rule> _constrainedRules;
+ Set<Rule>? _constrainedRules;
/// The transitive closure of all of the rules this rule places constraints
/// on, directly or indirectly, including itself.
Set<Rule> get allConstrainedRules {
- if (_allConstrainedRules == null) {
- void visit(Rule rule) {
- if (_allConstrainedRules.contains(rule)) return;
+ var rules = _allConstrainedRules;
+ if (rules != null) return rules;
- _allConstrainedRules.add(rule);
- rule.constrainedRules.forEach(visit);
- }
-
- _allConstrainedRules = {};
- visit(this);
- }
-
- return _allConstrainedRules;
+ rules = {};
+ _traverseConstraints(rules, this);
+ _allConstrainedRules = rules;
+ return rules;
}
- Set<Rule> _allConstrainedRules;
+ /// Traverses the constraint graph of [rule] adding everything to [rules].
+ void _traverseConstraints(Set<Rule> rules, Rule rule) {
+ if (rules.contains(rule)) return;
+
+ rules.add(rule);
+ for (var rule in rule.constrainedRules) {
+ _traverseConstraints(rules, rule);
+ }
+ }
+
+ Set<Rule>? _allConstrainedRules;
@override
String toString() => '$id';
diff --git a/lib/src/source_code.dart b/lib/src/source_code.dart
index 949daff..87c5aa5 100644
--- a/lib/src/source_code.dart
+++ b/lib/src/source_code.dart
@@ -10,7 +10,7 @@
/// The [uri] where the source code is from.
///
/// Used in error messages if the code cannot be parsed.
- final String uri;
+ final String? uri;
/// The Dart source code text.
final String text;
@@ -20,10 +20,10 @@
/// The offset in [text] where the selection begins, or `null` if there is
/// no selection.
- final int selectionStart;
+ final int? selectionStart;
/// The number of selected characters or `null` if there is no selection.
- final int selectionLength;
+ final int? selectionLength;
/// Gets the source code before the beginning of the selection.
///
@@ -38,7 +38,7 @@
/// If there is no selection, returns an empty string.
String get selectedText {
if (selectionStart == null) return '';
- return text.substring(selectionStart, selectionStart + selectionLength);
+ return text.substring(selectionStart!, selectionStart! + selectionLength!);
}
/// Gets the source code following the selection.
@@ -46,7 +46,7 @@
/// If there is no selection, returns an empty string.
String get textAfterSelection {
if (selectionStart == null) return '';
- return text.substring(selectionStart + selectionLength);
+ return text.substring(selectionStart! + selectionLength!);
}
SourceCode(this.text,
@@ -61,21 +61,21 @@
}
if (selectionStart != null) {
- if (selectionStart < 0) {
+ if (selectionStart! < 0) {
throw ArgumentError('selectionStart must be non-negative.');
}
- if (selectionStart > text.length) {
+ if (selectionStart! > text.length) {
throw ArgumentError('selectionStart must be within text.');
}
}
if (selectionLength != null) {
- if (selectionLength < 0) {
+ if (selectionLength! < 0) {
throw ArgumentError('selectionLength must be non-negative.');
}
- if (selectionStart + selectionLength > text.length) {
+ if (selectionStart! + selectionLength! > text.length) {
throw ArgumentError('selectionLength must end within text.');
}
}
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index ebbae38..c7bc88c 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -1,9 +1,6 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// 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.
-
-library dart_style.src.source_visitor;
-
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/ast/token.dart';
@@ -52,14 +49,13 @@
/// splitting up named constructors.
static bool looksLikeStaticCall(Expression node) {
if (node is! MethodInvocation) return false;
- var invocation = node as MethodInvocation;
- if (invocation.target == null) return false;
+ if (node.target == null) return false;
// A prefixed unnamed constructor call:
//
// prefix.Foo();
- if (invocation.target is SimpleIdentifier &&
- _looksLikeClassName(invocation.methodName.name)) {
+ if (node.target is SimpleIdentifier &&
+ _looksLikeClassName(node.methodName.name)) {
return true;
}
@@ -67,10 +63,8 @@
//
// Foo.named();
// prefix.Foo.named();
- var target = invocation.target;
- if (target is PrefixedIdentifier) {
- target = (target as PrefixedIdentifier).identifier;
- }
+ var target = node.target;
+ if (target is PrefixedIdentifier) target = target.identifier;
return target is SimpleIdentifier && _looksLikeClassName(target.name);
}
@@ -142,7 +136,7 @@
/// The character offset of the end of the selection, if there is a selection.
///
/// This is calculated and cached by [_findSelectionEnd].
- int _selectionEnd;
+ int? _selectionEnd;
/// How many levels deep inside a constant context the visitor currently is.
int _constNesting = 0;
@@ -200,9 +194,8 @@
/// Initialize a newly created visitor to write source code representing
/// the visited nodes to the given [writer].
- SourceVisitor(this._formatter, this._lineInfo, this._source) {
- builder = ChunkBuilder(_formatter, _source);
- }
+ SourceVisitor(this._formatter, this._lineInfo, this._source)
+ : builder = ChunkBuilder(_formatter, _source);
/// Runs the visitor on [node], formatting its contents.
///
@@ -215,7 +208,7 @@
visit(node);
// Output trailing comments.
- writePrecedingCommentsAndNewlines(node.endToken.next);
+ writePrecedingCommentsAndNewlines(node.endToken.next!);
assert(_constNesting == 0, 'Should have exited all const contexts.');
@@ -306,7 +299,7 @@
if (node.arguments != null) {
// Metadata annotations are always const contexts.
_constNesting++;
- visitArgumentList(node.arguments, nestExpression: false);
+ visitArgumentList(node.arguments!, nestExpression: false);
_constNesting--;
}
@@ -369,7 +362,7 @@
token(node.assertKeyword);
var arguments = <Expression>[node.condition];
- if (node.message != null) arguments.add(node.message);
+ if (node.message != null) arguments.add(node.message!);
// If the argument list has a trailing comma, format it like a collection
// literal where each argument goes on its own line, they are indented +2,
@@ -393,7 +386,7 @@
token(node.assertKeyword);
var arguments = [node.condition];
- if (node.message != null) arguments.add(node.message);
+ if (node.message != null) arguments.add(node.message!);
// If the argument list has a trailing comma, format it like a collection
// literal where each argument goes on its own line, they are indented +2,
@@ -648,7 +641,7 @@
// If the target is a call with a trailing comma in the argument list,
// treat it like a collection literal.
- ArgumentList arguments;
+ ArgumentList? arguments;
if (expression is InvocationExpression) {
arguments = expression.argumentList;
} else if (expression is InstanceCreationExpression) {
@@ -907,7 +900,7 @@
// the parameter list gets more deeply indented.
if (node.redirectedConstructor != null) builder.nestExpression();
- _visitBody(null, node.parameters, node.body, () {
+ _visitBody(null, node.parameters, node.body!, () {
// Check for redirects or initializer lists.
if (node.redirectedConstructor != null) {
_visitConstructorRedirects(node);
@@ -945,7 +938,7 @@
space();
if (node.initializers.length > 1) {
_writeText(node.parameters.parameters.last.isOptional ? ' ' : ' ',
- node.separator.offset);
+ node.separator!.offset);
}
// ":".
@@ -1044,15 +1037,15 @@
if (_formatter.fixes.contains(StyleFix.namedDefaultSeparator)) {
// Change the separator to "=".
space();
- writePrecedingCommentsAndNewlines(node.separator);
- _writeText('=', node.separator.offset);
+ writePrecedingCommentsAndNewlines(node.separator!);
+ _writeText('=', node.separator!.offset);
} else {
// The '=' separator is preceded by a space, ":" is not.
- if (node.separator.type == TokenType.EQ) space();
+ if (node.separator!.type == TokenType.EQ) space();
token(node.separator);
}
- soloSplit(_assignmentCost(node.defaultValue));
+ soloSplit(_assignmentCost(node.defaultValue!));
visit(node.defaultValue);
builder.unnest();
@@ -1204,7 +1197,7 @@
if (expression is PropertyAccess) {
return expression.realTarget;
} else if (expression is MethodInvocation) {
- return expression.realTarget;
+ return expression.realTarget!;
} else if (expression is IndexExpression) {
return expression.realTarget;
}
@@ -1234,7 +1227,7 @@
_insertCascadeTargetIntoExpression(expressionTarget, cascadeTarget),
// If we've reached the end, replace the `..` operator with `.`
expressionTarget == cascadeTarget
- ? _synthesizeToken(TokenType.PERIOD, expression.operator)
+ ? _synthesizeToken(TokenType.PERIOD, expression.operator!)
: expression.operator,
expression.methodName,
expression.typeArguments,
@@ -1244,9 +1237,8 @@
// A null-aware cascade treats the `?` in `?..` as part of the token, but
// for a non-cascade index, it is a separate `?` token.
- if (expression.period != null &&
- expression.period.type == TokenType.QUESTION_PERIOD_PERIOD) {
- question = _synthesizeToken(TokenType.QUESTION, expression.period);
+ if (expression.period?.type == TokenType.QUESTION_PERIOD_PERIOD) {
+ question = _synthesizeToken(TokenType.QUESTION, expression.period!);
}
return astFactory.indexExpressionForTarget2(
@@ -1264,7 +1256,7 @@
/// Parenthesize the target of the given statement's expression (assumed to
/// be a CascadeExpression) before removing the cascade.
void _fixCascadeByParenthesizingTarget(ExpressionStatement statement) {
- CascadeExpression cascade = statement.expression;
+ var cascade = statement.expression as CascadeExpression;
assert(cascade.cascadeSections.length == 1);
// Write any leading comments and whitespace immediately, as they should
@@ -1736,7 +1728,7 @@
var oldConstNesting = _constNesting;
_constNesting = 0;
- _visitBody(node.typeParameters, node.parameters, node.body);
+ _visitBody(node.typeParameters, node.parameters, node.body!);
_constNesting = oldConstNesting;
}
@@ -1841,10 +1833,10 @@
// Treat a chain of if-else elements as a single unit so that we don't
// unnecessarily indent each subsequent section of the chain.
var ifElements = [
- for (CollectionElement thisNode = node;
+ for (CollectionElement? thisNode = node;
thisNode is IfElement;
- thisNode = (thisNode as IfElement).elseElement)
- thisNode as IfElement
+ thisNode = thisNode.elseElement)
+ thisNode
];
// If the body of the then or else branch is a spread of a collection
@@ -1884,7 +1876,7 @@
var elseSpreadBracket =
_findSpreadCollectionBracket(ifElements.last.elseElement);
if (elseSpreadBracket != null) {
- spreadBrackets[ifElements.last.elseElement] = elseSpreadBracket;
+ spreadBrackets[ifElements.last.elseElement!] = elseSpreadBracket;
beforeBlock(elseSpreadBracket, spreadRule, null);
}
@@ -2012,7 +2004,7 @@
}
token(node.elseKeyword);
- visitClause(node.elseStatement);
+ visitClause(node.elseStatement!);
}
}
@@ -2089,10 +2081,10 @@
var includeKeyword = true;
if (node.keyword != null) {
- if (node.keyword.keyword == Keyword.NEW &&
+ if (node.keyword!.keyword == Keyword.NEW &&
_formatter.fixes.contains(StyleFix.optionalNew)) {
includeKeyword = false;
- } else if (node.keyword.keyword == Keyword.CONST &&
+ } else if (node.keyword!.keyword == Keyword.CONST &&
_formatter.fixes.contains(StyleFix.optionalConst) &&
_constNesting > 0) {
includeKeyword = false;
@@ -2103,7 +2095,7 @@
token(node.keyword, after: space);
} else {
// Don't lose comments before the discarded keyword, if any.
- writePrecedingCommentsAndNewlines(node.keyword);
+ writePrecedingCommentsAndNewlines(node.keyword!);
}
builder.startSpan(Cost.constructorName);
@@ -2282,21 +2274,20 @@
// If there is only a single superclass constraint, format it like an
// "extends" in a class.
- if (node.onClause != null &&
- node.onClause.superclassConstraints.length == 1) {
+ var onClause = node.onClause;
+ if (onClause != null && onClause.superclassConstraints.length == 1) {
soloSplit();
- token(node.onClause.onKeyword);
+ token(onClause.onKeyword);
space();
- visit(node.onClause.superclassConstraints.single);
+ visit(onClause.superclassConstraints.single);
}
builder.startRule(CombinatorRule());
// If there are multiple superclass constraints, format them like the
// "implements" clause.
- if (node.onClause != null &&
- node.onClause.superclassConstraints.length > 1) {
- visit(node.onClause);
+ if (onClause != null && onClause.superclassConstraints.length > 1) {
+ visit(onClause);
}
visit(node.implementsClause);
@@ -2471,11 +2462,11 @@
// Parameters can use "var" instead of "dynamic". Since we are inserting
// "dynamic" in that case, remove the "var".
if (node.keyword != null) {
- if (node.keyword.type != Keyword.VAR) {
+ if (node.keyword!.type != Keyword.VAR) {
modifier(node.keyword);
} else {
// Keep any comment attached to "var".
- writePrecedingCommentsAndNewlines(node.keyword);
+ writePrecedingCommentsAndNewlines(node.keyword!);
}
}
@@ -2484,8 +2475,8 @@
// without a name. Add "dynamic" in that case.
// Ensure comments on the identifier comes before the inserted type.
- token(node.identifier.token, before: () {
- _writeText('dynamic', node.identifier.offset);
+ token(node.identifier!.token, before: () {
+ _writeText('dynamic', node.identifier!.offset);
split();
});
} else {
@@ -2599,7 +2590,7 @@
var components = node.components;
for (var component in components) {
// The '.' separator
- if (component.previous.lexeme == '.') {
+ if (component.previous!.lexeme == '.') {
token(component.previous);
}
token(component);
@@ -2690,7 +2681,8 @@
var hasMultipleVariables =
(node.parent as VariableDeclarationList).variables.length > 1;
- _visitAssignment(node.equals, node.initializer, nest: hasMultipleVariables);
+ _visitAssignment(node.equals!, node.initializer!,
+ nest: hasMultipleVariables);
}
@override
@@ -2764,7 +2756,7 @@
/// Visit a [node], and if not null, optionally preceded or followed by the
/// specified functions.
- void visit(AstNode node, {void Function() before, void Function() after}) {
+ void visit(AstNode? node, {void Function()? before, void Function()? after}) {
if (node == null) return;
if (before != null) before();
@@ -2801,7 +2793,7 @@
/// the parameter.
void visitParameterMetadata(
NodeList<Annotation> metadata, void Function() visitParameter) {
- if (metadata == null || metadata.isEmpty) {
+ if (metadata.isEmpty) {
visitParameter();
return;
}
@@ -2835,7 +2827,7 @@
/// the surrounding named argument rule. That way, this can ensure that a
/// split between the name and argument forces the argument list to split
/// too.
- void visitNamedArgument(NamedExpression node, [NamedRule rule]) {
+ void visitNamedArgument(NamedExpression node, [NamedRule? rule]) {
builder.nestExpression();
builder.startSpan();
visit(node.name);
@@ -2887,7 +2879,7 @@
builder.nestExpression();
token(leftBracket);
- rule.beforeArgument(zeroSplit());
+ rule.beforeArgument(zeroSplit()!);
for (var node in nodes) {
visit(node);
@@ -2895,7 +2887,7 @@
// Write the trailing comma.
if (node != nodes.last) {
token(node.endToken.next);
- rule.beforeArgument(split());
+ rule.beforeArgument(split()!);
}
}
@@ -2959,7 +2951,7 @@
visit(node.name);
builder.endSpan();
- TypeParameterList typeParameters;
+ TypeParameterList? typeParameters;
if (node is FunctionDeclaration) {
typeParameters = node.functionExpression.typeParameters;
} else {
@@ -2981,9 +2973,9 @@
/// space before it if it's not empty.
///
/// If [beforeBody] is provided, it is invoked before the body is visited.
- void _visitBody(TypeParameterList typeParameters,
- FormalParameterList parameters, FunctionBody body,
- [void Function() beforeBody]) {
+ void _visitBody(TypeParameterList? typeParameters,
+ FormalParameterList? parameters, FunctionBody body,
+ [void Function()? beforeBody]) {
// If the body is "=>", add an extra level of indentation around the
// parameters and a rule that spans the parameters and the "=>". This
// ensures that if the parameters wrap, they wrap more deeply than the "=>"
@@ -3025,7 +3017,7 @@
/// Visits the type parameters (if any) and formal parameters of a method
/// declaration, function declaration, or generic function type.
void _visitParameterSignature(
- TypeParameterList typeParameters, FormalParameterList parameters) {
+ TypeParameterList? typeParameters, FormalParameterList? parameters) {
// Start the nesting for the parameters here, so they indent past the
// type parameters too, if any.
builder.nestExpression();
@@ -3064,10 +3056,10 @@
/// Visit a list of [nodes] if not null, optionally separated and/or preceded
/// and followed by the given functions.
void visitNodes(Iterable<AstNode> nodes,
- {void Function() before,
- void Function() between,
- void Function() after}) {
- if (nodes == null || nodes.isEmpty) return;
+ {void Function()? before,
+ void Function()? between,
+ void Function()? after}) {
+ if (nodes.isEmpty) return;
if (before != null) before();
@@ -3082,8 +3074,8 @@
/// Visit a comma-separated list of [nodes] if not null.
void visitCommaSeparatedNodes(Iterable<AstNode> nodes,
- {void Function() between}) {
- if (nodes == null || nodes.isEmpty) return;
+ {void Function()? between}) {
+ if (nodes.isEmpty) return;
between ??= space;
@@ -3095,7 +3087,7 @@
visit(node);
// The comma after the node.
- if (node.endToken.next.lexeme == ',') token(node.endToken.next);
+ if (node.endToken.next!.lexeme == ',') token(node.endToken.next);
}
}
@@ -3104,16 +3096,16 @@
///
/// This is also used for argument lists with a trailing comma which are
/// considered "collection-like". In that case, [node] is `null`.
- void _visitCollectionLiteral(TypedLiteral node, Token leftBracket,
+ void _visitCollectionLiteral(TypedLiteral? node, Token leftBracket,
Iterable<AstNode> elements, Token rightBracket,
- [int cost]) {
+ [int? cost]) {
if (node != null) {
// See if `const` should be removed.
if (node.constKeyword != null &&
_constNesting > 0 &&
_formatter.fixes.contains(StyleFix.optionalConst)) {
// Don't lose comments before the discarded keyword, if any.
- writePrecedingCommentsAndNewlines(node.constKeyword);
+ writePrecedingCommentsAndNewlines(node.constKeyword!);
} else {
modifier(node.constKeyword);
}
@@ -3165,7 +3157,7 @@
if (element != elements.first) {
if (preserveNewlines) {
// See if the next element is on the next line.
- if (_endLine(element.beginToken.previous) !=
+ if (_endLine(element.beginToken.previous!) !=
_startLine(element.beginToken)) {
oneOrTwoNewlines();
@@ -3219,7 +3211,7 @@
// Find the parameter immediately preceding the optional parameters (if
// there are any).
- FormalParameter lastRequired;
+ FormalParameter? lastRequired;
for (var i = 0; i < parameters.parameters.length; i++) {
if (parameters.parameters[i] is DefaultFormalParameter) {
if (i > 0) lastRequired = parameters.parameters[i - 1];
@@ -3286,10 +3278,10 @@
/// In that case [functionKeywordPosition] should be the source position
/// used for the inserted "Function" text.
void _visitGenericFunctionType(
- AstNode returnType,
- Token functionKeyword,
- int functionKeywordPosition,
- TypeParameterList typeParameters,
+ AstNode? returnType,
+ Token? functionKeyword,
+ int? functionKeywordPosition,
+ TypeParameterList? typeParameters,
FormalParameterList parameters) {
builder.startLazyRule();
builder.nestExpression();
@@ -3298,7 +3290,7 @@
if (functionKeyword != null) {
token(functionKeyword);
} else {
- _writeText('Function', functionKeywordPosition);
+ _writeText('Function', functionKeywordPosition!);
}
builder.unnest();
@@ -3312,7 +3304,7 @@
/// If [equals] is `null`, then [equalsPosition] must be a
/// position to use for the inserted text "=".
void _visitGenericTypeAliasHeader(Token typedefKeyword, AstNode name,
- AstNode typeParameters, Token equals, int equalsPosition) {
+ AstNode? typeParameters, Token? equals, int? equalsPosition) {
token(typedefKeyword);
space();
@@ -3329,7 +3321,7 @@
if (equals != null) {
token(equals);
} else {
- _writeText('=', equalsPosition);
+ _writeText('=', equalsPosition!);
}
builder.endRule();
@@ -3362,7 +3354,7 @@
/// // ^
///
/// Otherwise, returns `null`.
- Token _findSpreadCollectionBracket(AstNode node) {
+ Token? _findSpreadCollectionBracket(AstNode? node) {
if (node is SpreadElement) {
var expression = node.expression;
if (expression is ListLiteral) {
@@ -3445,15 +3437,8 @@
// See if this literal is associated with an argument list or if element
// that wants to handle splitting and indenting it. If not, we'll use a
// default rule.
- Rule rule;
- if (_blockRules.containsKey(leftBracket)) {
- rule = _blockRules[leftBracket];
- }
-
- Chunk argumentChunk;
- if (_blockPreviousChunks.containsKey(leftBracket)) {
- argumentChunk = _blockPreviousChunks[leftBracket];
- }
+ var rule = _blockRules[leftBracket];
+ var argumentChunk = _blockPreviousChunks[leftBracket];
// Create a rule for whether or not to split the block contents.
builder.startRule(rule);
@@ -3468,7 +3453,7 @@
/// given, ignores that rule inside the body when determining if it should
/// split.
void _endLiteralBody(Token rightBracket,
- {Rule ignoredRule, bool forceSplit}) {
+ {Rule? ignoredRule, bool? forceSplit}) {
forceSplit ??= false;
// Put comments before the closing delimiter inside the block.
@@ -3508,26 +3493,26 @@
void _visitCombinator(Token keyword, Iterable<AstNode> nodes) {
// Allow splitting before the keyword.
var rule = builder.rule as CombinatorRule;
- rule.addCombinator(split());
+ rule.addCombinator(split()!);
builder.nestExpression();
token(keyword);
- rule.addName(split());
- visitCommaSeparatedNodes(nodes, between: () => rule.addName(split()));
+ rule.addName(split()!);
+ visitCommaSeparatedNodes(nodes, between: () => rule.addName(split()!));
builder.unnest();
}
/// If [keyword] is `const`, begins a new constant context.
- void _startPossibleConstContext(Token keyword) {
+ void _startPossibleConstContext(Token? keyword) {
if (keyword != null && keyword.keyword == Keyword.CONST) {
_constNesting++;
}
}
/// If [keyword] is `const`, ends the current outermost constant context.
- void _endPossibleConstContext(Token keyword) {
+ void _endPossibleConstContext(Token? keyword) {
if (keyword != null && keyword.keyword == Keyword.CONST) {
_constNesting--;
}
@@ -3554,7 +3539,7 @@
/// splitting rule for the block. These are used for handling block-like
/// expressions inside argument lists and spread collections inside if
/// elements.
- void beforeBlock(Token token, Rule rule, [Chunk previousChunk]) {
+ void beforeBlock(Token token, Rule rule, [Chunk? previousChunk]) {
_blockRules[token] = rule;
if (previousChunk != null) _blockPreviousChunks[token] = previousChunk;
}
@@ -3587,7 +3572,7 @@
/// [FunctionExpression].
bool _isInLambda(AstNode node) =>
node.parent is FunctionExpression &&
- node.parent.parent is! FunctionDeclaration;
+ node.parent!.parent is! FunctionDeclaration;
/// Writes the string literal [string] to the output.
///
@@ -3599,7 +3584,7 @@
writePrecedingCommentsAndNewlines(string);
// Split each line of a multiline string into separate chunks.
- var lines = string.lexeme.split(_formatter.lineEnding);
+ var lines = string.lexeme.split(_formatter.lineEnding!);
var offset = string.offset;
_writeText(lines.first, offset);
@@ -3622,16 +3607,14 @@
bool hasCommaAfter(AstNode node) => _commaAfter(node) != null;
/// The comma token immediately following [node] if there is one, or `null`.
- Token _commaAfter(AstNode node) {
- if (node.endToken.next.type == TokenType.COMMA) {
- return node.endToken.next;
- }
+ Token? _commaAfter(AstNode node) {
+ var next = node.endToken.next!;
+ if (next.type == TokenType.COMMA) return next;
// TODO(sdk#38990): endToken doesn't include the "?" on a nullable
// function-typed formal, so check for that case and handle it.
- if (node.endToken.next.type == TokenType.QUESTION &&
- node.endToken.next.next.type == TokenType.COMMA) {
- return node.endToken.next.next;
+ if (next.type == TokenType.QUESTION && next.next!.type == TokenType.COMMA) {
+ return next.next;
}
return null;
@@ -3639,7 +3622,7 @@
/// Emit the given [modifier] if it's non null, followed by non-breaking
/// whitespace.
- void modifier(Token modifier) {
+ void modifier(Token? modifier) {
token(modifier, after: space);
}
@@ -3682,15 +3665,15 @@
/// Writes a single space split owned by the current rule.
///
/// Returns the chunk the split was applied to.
- Chunk split() => builder.split(space: true);
+ Chunk? split() => builder.split(space: true);
/// Writes a zero-space split owned by the current rule.
///
/// Returns the chunk the split was applied to.
- Chunk zeroSplit() => builder.split();
+ Chunk? zeroSplit() => builder.split();
/// Writes a single space split with its own rule.
- Rule soloSplit([int cost]) {
+ Rule soloSplit([int? cost]) {
var rule = Rule(cost);
builder.startRule(rule);
split();
@@ -3711,7 +3694,7 @@
/// Does nothing if [token] is `null`. If [before] is given, it will be
/// executed before the token is outout. Likewise, [after] will be called
/// after the token is output.
- void token(Token token, {void Function() before, void Function() after}) {
+ void token(Token? token, {void Function()? before, void Function()? after}) {
if (token == null) return;
writePrecedingCommentsAndNewlines(token);
@@ -3725,13 +3708,13 @@
/// Writes all formatted whitespace and comments that appear before [token].
bool writePrecedingCommentsAndNewlines(Token token) {
- var comment = token.precedingComments;
+ Token? comment = token.precedingComments;
// For performance, avoid calculating newlines between tokens unless
// actually needed.
if (comment == null) {
if (builder.needsToPreserveNewlines) {
- builder.preserveNewlines(_startLine(token) - _endLine(token.previous));
+ builder.preserveNewlines(_startLine(token) - _endLine(token.previous!));
}
return false;
@@ -3740,14 +3723,14 @@
// If the token's comments are being moved by a fix, do not write them here.
if (_suppressPrecedingCommentsAndNewLines.contains(token)) return false;
- var previousLine = _endLine(token.previous);
+ var previousLine = _endLine(token.previous!);
var tokenLine = _startLine(token);
// Edge case: The analyzer includes the "\n" in the script tag's lexeme,
// which confuses some of these calculations. We don't want to allow a
// blank line between the script tag and a following comment anyway, so
// just override the script tag's line.
- if (token.previous.type == TokenType.SCRIPT_TAG) previousLine = tokenLine;
+ if (token.previous!.type == TokenType.SCRIPT_TAG) previousLine = tokenLine;
var comments = <SourceComment>[];
while (comment != null) {
@@ -3755,7 +3738,7 @@
// Don't preserve newlines at the top of the file.
if (comment == token.precedingComments &&
- token.previous.type == TokenType.EOF) {
+ token.previous!.type == TokenType.EOF) {
previousLine = commentLine;
}
@@ -3824,14 +3807,14 @@
///
/// Returns `null` if the selection start has already been processed or is
/// not within that range.
- int _getSelectionStartWithin(int offset, int length) {
+ int? _getSelectionStartWithin(int offset, int length) {
// If there is no selection, do nothing.
if (_source.selectionStart == null) return null;
// If we've already passed it, don't consider it again.
if (_passedSelectionStart) return null;
- var start = _source.selectionStart - offset;
+ var start = _source.selectionStart! - offset;
// If it started in whitespace before this text, push it forward to the
// beginning of the non-whitespace text.
@@ -3851,7 +3834,7 @@
///
/// Returns `null` if the selection endpoint has already been processed or is
/// not within that range.
- int _getSelectionEndWithin(int offset, int length) {
+ int? _getSelectionEndWithin(int offset, int length) {
// If there is no selection, do nothing.
if (_source.selectionLength == null) return null;
@@ -3882,28 +3865,32 @@
///
/// Removes any trailing whitespace from the selection.
int _findSelectionEnd() {
- if (_selectionEnd != null) return _selectionEnd;
+ if (_selectionEnd != null) return _selectionEnd!;
- _selectionEnd = _source.selectionStart + _source.selectionLength;
+ var end = _source.selectionStart! + _source.selectionLength!;
// If the selection bumps to the end of the source, pin it there.
- if (_selectionEnd == _source.text.length) return _selectionEnd;
+ if (end == _source.text.length) {
+ _selectionEnd = end;
+ return end;
+ }
// Trim off any trailing whitespace. We want the selection to "rubberband"
// around the selected non-whitespace tokens since the whitespace will
// be munged by the formatter itself.
- while (_selectionEnd > _source.selectionStart) {
+ while (end > _source.selectionStart!) {
// Stop if we hit anything other than space, tab, newline or carriage
// return.
- var char = _source.text.codeUnitAt(_selectionEnd - 1);
+ var char = _source.text.codeUnitAt(end - 1);
if (char != 0x20 && char != 0x09 && char != 0x0a && char != 0x0d) {
break;
}
- _selectionEnd--;
+ end--;
}
- return _selectionEnd;
+ _selectionEnd = end;
+ return end;
}
/// Gets the 1-based line number that the beginning of [token] lies on.
diff --git a/lib/src/whitespace.dart b/lib/src/whitespace.dart
index bf7eab2..d9f226d 100644
--- a/lib/src/whitespace.dart
+++ b/lib/src/whitespace.dart
@@ -71,6 +71,10 @@
/// less prescriptive over the user's whitespace.
static const oneOrTwoNewlines = Whitespace._('oneOrTwoNewlines');
+ /// A hard split was just written whose whitespace takes precedence over any
+ /// previous pending whitespace.
+ static const afterHardSplit = Whitespace._('afterHardSplit');
+
final String name;
/// Gets the minimum number of newlines contained in this whitespace.
diff --git a/pubspec.lock b/pubspec.lock
index 2981e21..bed7945 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -84,7 +84,7 @@
name: file
url: "https://pub.dartlang.org"
source: hosted
- version: "6.0.0"
+ version: "6.1.0"
glob:
dependency: transitive
description:
@@ -224,7 +224,7 @@
name: shelf_web_socket
url: "https://pub.dartlang.org"
source: hosted
- version: "0.2.4"
+ version: "0.2.4+1"
source_map_stack_trace:
dependency: transitive
description:
@@ -280,7 +280,7 @@
name: test
url: "https://pub.dartlang.org"
source: hosted
- version: "1.16.2"
+ version: "1.16.3"
test_api:
dependency: transitive
description:
@@ -301,14 +301,14 @@
name: test_descriptor
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.1"
+ version: "2.0.0"
test_process:
dependency: "direct dev"
description:
name: test_process
url: "https://pub.dartlang.org"
source: hosted
- version: "1.0.5"
+ version: "2.0.0"
typed_data:
dependency: transitive
description:
@@ -322,7 +322,7 @@
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
- version: "6.0.1"
+ version: "6.1.0+1"
watcher:
dependency: transitive
description:
@@ -336,7 +336,7 @@
name: web_socket_channel
url: "https://pub.dartlang.org"
source: hosted
- version: "1.2.0"
+ version: "2.0.0"
webkit_inspection_protocol:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index e387681..4ad9d21 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,13 +1,13 @@
name: dart_style
# Note: See tool/grind.dart for how to bump the version.
-version: 1.3.14
+version: 2.0.0-dev
description: >-
Opinionated, automatic Dart source code formatter.
Provides an API and a CLI tool.
repository: https://github.com/dart-lang/dart_style
environment:
- sdk: '>=2.11.99 <3.0.0'
+ sdk: '>=2.12.0-0 <3.0.0'
dependencies:
analyzer: ^1.0.0
@@ -22,8 +22,8 @@
node_preamble: ^1.0.0
pedantic: ^1.0.0
test: ^1.16.0
- test_descriptor: ^1.0.0
- test_process: ^1.0.0
+ test_descriptor: ^2.0.0
+ test_process: ^2.0.0
yaml: '>=2.0.0 <4.0.0'
executables:
diff --git a/test/utils.dart b/test/utils.dart
index b22f73f..926841f 100644
--- a/test/utils.dart
+++ b/test/utils.dart
@@ -27,10 +27,10 @@
/// If tool/command_shell.dart has been compiled to a snapshot, this is the path
/// to it.
-String _commandExecutablePath;
+String? _commandExecutablePath;
/// If bin/format.dart has been compiled to a snapshot, this is the path to it.
-String _formatterExecutablePath;
+String? _formatterExecutablePath;
/// Compiles format.dart to a native executable for tests to use.
///
@@ -42,7 +42,7 @@
});
tearDownAll(() async {
- await _deleteSnapshot(_formatterExecutablePath);
+ await _deleteSnapshot(_formatterExecutablePath!);
_formatterExecutablePath = null;
});
}
@@ -57,7 +57,7 @@
});
tearDownAll(() async {
- await _deleteSnapshot(_commandExecutablePath);
+ await _deleteSnapshot(_commandExecutablePath!);
_commandExecutablePath = null;
});
}
@@ -108,41 +108,41 @@
}
/// Runs the command line formatter, passing it [args].
-Future<TestProcess> runFormatter([List<String> args]) {
+Future<TestProcess> runFormatter([List<String>? args]) {
if (_formatterExecutablePath == null) {
fail('Must call createFormatterExecutable() before running commands.');
}
return TestProcess.start(
- Platform.resolvedExecutable, [_formatterExecutablePath, ...?args],
+ Platform.resolvedExecutable, [_formatterExecutablePath!, ...?args],
workingDirectory: d.sandbox);
}
/// Runs the command line formatter, passing it the test directory followed by
/// [args].
-Future<TestProcess> runFormatterOnDir([List<String> args]) {
+Future<TestProcess> runFormatterOnDir([List<String>? args]) {
return runFormatter(['.', ...?args]);
}
/// Runs the test shell for the [Command]-based formatter, passing it [args].
-Future<TestProcess> runCommand([List<String> args]) {
+Future<TestProcess> runCommand([List<String>? args]) {
if (_commandExecutablePath == null) {
fail('Must call createCommandExecutable() before running commands.');
}
- return TestProcess.start(
- Platform.resolvedExecutable, [_commandExecutablePath, 'format', ...?args],
+ return TestProcess.start(Platform.resolvedExecutable,
+ [_commandExecutablePath!, 'format', ...?args],
workingDirectory: d.sandbox);
}
/// Runs the test shell for the [Command]-based formatter, passing it the test
/// directory followed by [args].
-Future<TestProcess> runCommandOnDir([List<String> args]) {
+Future<TestProcess> runCommandOnDir([List<String>? args]) {
return runCommand(['.', ...?args]);
}
/// Run tests defined in "*.unit" and "*.stmt" files inside directory [name].
-void testDirectory(String name, [Iterable<StyleFix> fixes]) {
+void testDirectory(String name, [Iterable<StyleFix>? fixes]) {
// Locate the "test" directory. Use mirrors so that this works with the test
// package, which loads this suite into an isolate.
// TODO(rnystrom): Investigate using Isolate.resolvePackageUri instead.
@@ -164,7 +164,7 @@
}
}
-void testFile(String path, [Iterable<StyleFix> fixes]) {
+void testFile(String path, [Iterable<StyleFix>? fixes]) {
// Locate the "test" directory. Use mirrors so that this works with the test
// package, which loads this suite into an isolate.
var testDir = p.dirname(currentMirrorSystem()
@@ -175,9 +175,8 @@
_testFile(p.dirname(path), p.join(testDir, path), fixes);
}
-void _testFile(String name, String path, Iterable<StyleFix> baseFixes) {
- var fixes = <StyleFix>[];
- if (baseFixes != null) fixes.addAll(baseFixes);
+void _testFile(String name, String path, Iterable<StyleFix>? baseFixes) {
+ var fixes = [...?baseFixes];
group('$name ${p.basename(path)}', () {
// Explicitly create a File, in case the entry is a Link.
@@ -198,7 +197,7 @@
// regression tests which often come from a chunk of nested code.
var leadingIndent = 0;
description = description.replaceAllMapped(_indentPattern, (match) {
- leadingIndent = int.parse(match[1]);
+ leadingIndent = int.parse(match[1]!);
return '';
});
@@ -294,7 +293,7 @@
/// accidentally modify the Dart code being formatted.
String _unescapeUnicode(String input) {
return input.replaceAllMapped(_unicodePattern, (match) {
- var codePoint = int.parse(match[1], radix: 16);
+ var codePoint = int.parse(match[1]!, radix: 16);
return String.fromCharCode(codePoint);
});
}