Version 2.15.0-20.0.dev
Merge commit 'cfb057ddca6b90ed2b25296c295e73e5ce895076' into 'dev'
diff --git a/DEPS b/DEPS
index 0656dad..ee3a819 100644
--- a/DEPS
+++ b/DEPS
@@ -172,7 +172,7 @@
"web_components_rev": "8f57dac273412a7172c8ade6f361b407e2e4ed02",
"web_socket_channel_rev": "6448ce532445a8a458fa191d9346df071ae0acad",
"WebCore_rev": "fb11e887f77919450e497344da570d780e078bc8",
- "webdev_rev": "b0aae7b6944d484722e6af164abedd864a2a0afa",
+ "webdev_rev": "50fe70a3137d9665fbe94cd34af5277b65d95079",
"webkit_inspection_protocol_rev": "dd6fb5d8b536e19cedb384d0bbf1f5631923f1e8",
"yaml_rev": "b4c4411631bda556ce9a45af1ab0eecaf9f3ac53",
"zlib_rev": "bf44340d1b6be1af8950bbdf664fec0cf5a831cc",
diff --git a/benchmarks/EventLoopLatencyRegexp/dart/EventLoopLatencyRegexp.dart b/benchmarks/EventLoopLatencyRegexp/dart/EventLoopLatencyRegexp.dart
new file mode 100644
index 0000000..5ffe53f
--- /dev/null
+++ b/benchmarks/EventLoopLatencyRegexp/dart/EventLoopLatencyRegexp.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2021, 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:isolate';
+
+import 'regexp_benchmark.dart';
+import '../../EventLoopLatencyJson/dart/latency.dart';
+
+main() async {
+ final exitPort = ReceivePort();
+ final exitFuture = exitPort.first;
+ final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort);
+
+ // Measure event loop latency.
+ const tickDuration = const Duration(milliseconds: 1);
+ const numberOfTicks = 8 * 1000; // min 8 seconds.
+ final EventLoopLatencyStats stats =
+ await measureEventLoopLatency(tickDuration, numberOfTicks);
+
+ // Kill isolate & wait until it's dead.
+ isolate.kill(priority: Isolate.immediate);
+ await exitFuture;
+
+ // Report event loop latency statistics.
+ stats.report('EventLoopLatencyRegexp');
+}
+
+void run(dynamic msg) {
+ while (true) {
+ RegexpBenchmark().run();
+ }
+}
diff --git a/benchmarks/EventLoopLatencyRegexp/dart/regexp_benchmark.dart b/benchmarks/EventLoopLatencyRegexp/dart/regexp_benchmark.dart
new file mode 100644
index 0000000..e3389a8
--- /dev/null
+++ b/benchmarks/EventLoopLatencyRegexp/dart/regexp_benchmark.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2021, 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:math';
+import 'dart:convert';
+
+class RegexpBenchmark {
+ void run() {
+ final re = RegExp(r'(x+)*y');
+ final s = 'x' * 26 + '';
+ re.allMatches(s).iterator.moveNext();
+ }
+}
diff --git a/benchmarks/EventLoopLatencyRegexp/dart2/EventLoopLatencyRegexp.dart b/benchmarks/EventLoopLatencyRegexp/dart2/EventLoopLatencyRegexp.dart
new file mode 100644
index 0000000..dec8cb2
--- /dev/null
+++ b/benchmarks/EventLoopLatencyRegexp/dart2/EventLoopLatencyRegexp.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2020, 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.
+
+// @dart=2.9
+
+import 'dart:isolate';
+
+import 'json_benchmark.dart';
+import '../../EventLoopLatencyJson/dart2/latency.dart';
+
+main() async {
+ final exitPort = ReceivePort();
+ final exitFuture = exitPort.first;
+ final isolate = await Isolate.spawn(run, null, onExit: exitPort.sendPort);
+
+ // Measure event loop latency.
+ const tickDuration = const Duration(milliseconds: 1);
+ const numberOfTicks = 8 * 1000; // min 8 seconds.
+ final EventLoopLatencyStats stats =
+ await measureEventLoopLatency(tickDuration, numberOfTicks);
+
+ // Kill isolate & wait until it's dead.
+ isolate.kill(priority: Isolate.immediate);
+ await exitFuture;
+
+ // Report event loop latency statistics.
+ stats.report('EventLoopLatencyRegexp');
+}
+
+void run(dynamic msg) {
+ while (true) {
+ RegexpBenchmark().run();
+ }
+}
diff --git a/benchmarks/EventLoopLatencyRegexp/dart2/regexp_benchmark.dart b/benchmarks/EventLoopLatencyRegexp/dart2/regexp_benchmark.dart
new file mode 100644
index 0000000..6047117
--- /dev/null
+++ b/benchmarks/EventLoopLatencyRegexp/dart2/regexp_benchmark.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2021, 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.
+
+// @dart=2.9
+
+import 'dart:math';
+import 'dart:convert';
+
+class RegexpBenchmark {
+ void run() {
+ final re = RegExp(r'(x+)*y');
+ final s = 'x' * 26 + '';
+ re.allMatches(s).iterator.moveNext();
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index d5fd17e..c5d1271 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -942,9 +942,6 @@
AddNullCheck.newInstance,
ReplaceWithNullAware.single,
],
- CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE: [
- AddNullCheck.newInstance,
- ],
CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION: [
AddNullCheck.newInstance,
],
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index f96a7ee..d315c84 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -419,7 +419,6 @@
CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE,
CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
- CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE,
CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR,
CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD,
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 53fdfae..d8b80ca 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -80,7 +80,7 @@
/// TODO(scheglov) Clean up the list of implicitly analyzed files.
class AnalysisDriver implements AnalysisDriverGeneric {
/// The version of data format, should be incremented on every format change.
- static const int DATA_VERSION = 168;
+ static const int DATA_VERSION = 169;
/// The number of exception contexts allowed to write. Once this field is
/// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
index 26339f7..f80a744 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
@@ -20,6 +20,7 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/summary2/bundle_reader.dart';
+import 'package:analyzer/src/summary2/informative_data.dart';
import 'package:analyzer/src/summary2/link.dart' as link2;
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/reference.dart';
@@ -109,10 +110,13 @@
cycle.directDependencies.forEach(loadBundle);
- var unitsInformativeBytes = <Uri, Uint8List>{};
+ var unitsInformativeData = <Uri, InformativeUnitData>{};
for (var library in cycle.libraries) {
for (var file in library.libraryFiles) {
- unitsInformativeBytes[file.uri] = file.getInformativeBytes();
+ unitsInformativeData[file.uri] = InformativeUnitData(
+ content: file.content,
+ bytes: file.getInformativeBytes(),
+ );
}
}
@@ -191,7 +195,7 @@
elementFactory.addBundle(
BundleReader(
elementFactory: elementFactory,
- unitsInformativeBytes: unitsInformativeBytes,
+ unitsInformativeData: unitsInformativeData,
resolutionBytes: resolutionBytes,
),
);
@@ -240,7 +244,7 @@
BundleReader(
elementFactory: elementFactory,
resolutionBytes: bundle.resolutionBytes,
- unitsInformativeBytes: {},
+ unitsInformativeData: {},
),
);
}
diff --git a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
index bbec62f..d8eaf00 100644
--- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
@@ -18,178 +18,69 @@
/// visited nodes to the given [sink].
ToSourceVisitor(this.sink);
- /// Visit the given function [body], printing the [prefix] before if the body
- /// is not empty.
- @protected
- void safelyVisitFunctionWithPrefix(String prefix, FunctionBody body) {
- if (body is! EmptyFunctionBody) {
- sink.write(prefix);
- }
- safelyVisitNode(body);
- }
-
- /// Safely visit the given [node].
- @protected
- void safelyVisitNode(AstNode? node) {
- if (node != null) {
- node.accept(this);
- }
- }
-
- /// Print a list of [nodes] without any separation.
- @protected
- void safelyVisitNodeList(NodeList<AstNode> nodes) {
- safelyVisitNodeListWithSeparator(nodes, "");
- }
-
- /// Print a list of [nodes], separated by the given [separator].
- @protected
- void safelyVisitNodeListWithSeparator(
- NodeList<AstNode> nodes, String separator) {
- int size = nodes.length;
- for (int i = 0; i < size; i++) {
- if (i > 0) {
- sink.write(separator);
- }
- nodes[i].accept(this);
- }
- }
-
- /// Print a list of [nodes], prefixed by the given [prefix] if the list is not
- /// empty, and separated by the given [separator].
- @protected
- void safelyVisitNodeListWithSeparatorAndPrefix(
- String prefix, NodeList<AstNode> nodes, String separator) {
- int size = nodes.length;
- if (size > 0) {
- sink.write(prefix);
- for (int i = 0; i < size; i++) {
- if (i > 0) {
- sink.write(separator);
- }
- nodes[i].accept(this);
- }
- }
- }
-
- /// Print a list of [nodes], separated by the given [separator], followed by
- /// the given [suffix] if the list is not empty.
- @protected
- void safelyVisitNodeListWithSeparatorAndSuffix(
- NodeList<AstNode> nodes, String separator, String suffix) {
- int size = nodes.length;
- if (size > 0) {
- for (int i = 0; i < size; i++) {
- if (i > 0) {
- sink.write(separator);
- }
- nodes[i].accept(this);
- }
- sink.write(suffix);
- }
- }
-
- /// Safely visit the given [node], printing the [prefix] before the node if it
- /// is non-`null`.
- @protected
- void safelyVisitNodeWithPrefix(String prefix, AstNode? node) {
- if (node != null) {
- sink.write(prefix);
- node.accept(this);
- }
- }
-
- /// Safely visit the given [node], printing the [suffix] after the node if it
- /// is non-`null`.
- @protected
- void safelyVisitNodeWithSuffix(AstNode? node, String suffix) {
- if (node != null) {
- node.accept(this);
- sink.write(suffix);
- }
- }
-
- /// Safely visit the given [token].
- @protected
- void safelyVisitToken(Token? token) {
- if (token != null) {
- sink.write(token.lexeme);
- }
- }
-
- /// Safely visit the given [token], printing the [suffix] after the token if
- /// it is non-`null`.
- @protected
- void safelyVisitTokenWithSuffix(Token? token, String suffix) {
- if (token != null) {
- sink.write(token.lexeme);
- sink.write(suffix);
- }
- }
-
@override
void visitAdjacentStrings(AdjacentStrings node) {
- safelyVisitNodeListWithSeparator(node.strings, " ");
+ _visitNodeList(node.strings, separator: ' ');
}
@override
void visitAnnotation(Annotation node) {
sink.write('@');
- safelyVisitNode(node.name);
- safelyVisitNode(node.typeArguments);
- safelyVisitNodeWithPrefix(".", node.constructorName);
- safelyVisitNode(node.arguments);
+ _visitNode(node.name);
+ _visitNode(node.typeArguments);
+ _visitNode(node.constructorName, prefix: '.');
+ _visitNode(node.arguments);
}
@override
void visitArgumentList(ArgumentList node) {
sink.write('(');
- safelyVisitNodeListWithSeparator(node.arguments, ", ");
+ _visitNodeList(node.arguments, separator: ', ');
sink.write(')');
}
@override
void visitAsExpression(AsExpression node) {
- safelyVisitNode(node.expression);
- sink.write(" as ");
- safelyVisitNode(node.type);
+ _visitNode(node.expression);
+ sink.write(' as ');
+ _visitNode(node.type);
}
@override
void visitAssertInitializer(AssertInitializer node) {
- sink.write("assert (");
- safelyVisitNode(node.condition);
+ sink.write('assert (');
+ _visitNode(node.condition);
if (node.message != null) {
sink.write(', ');
- safelyVisitNode(node.message);
+ _visitNode(node.message);
}
- sink.write(");");
+ sink.write(');');
}
@override
void visitAssertStatement(AssertStatement node) {
- sink.write("assert (");
- safelyVisitNode(node.condition);
+ sink.write('assert (');
+ _visitNode(node.condition);
if (node.message != null) {
sink.write(', ');
- safelyVisitNode(node.message);
+ _visitNode(node.message);
}
- sink.write(");");
+ sink.write(');');
}
@override
void visitAssignmentExpression(AssignmentExpression node) {
- safelyVisitNode(node.leftHandSide);
+ _visitNode(node.leftHandSide);
sink.write(' ');
sink.write(node.operator.lexeme);
sink.write(' ');
- safelyVisitNode(node.rightHandSide);
+ _visitNode(node.rightHandSide);
}
@override
void visitAwaitExpression(AwaitExpression node) {
- sink.write("await ");
- safelyVisitNode(node.expression);
+ sink.write('await ');
+ _visitNode(node.expression);
}
@override
@@ -204,7 +95,7 @@
@override
void visitBlock(Block node) {
sink.write('{');
- safelyVisitNodeListWithSeparator(node.statements, " ");
+ _visitNodeList(node.statements, separator: ' ');
sink.write('}');
}
@@ -218,7 +109,7 @@
}
sink.write(' ');
}
- safelyVisitNode(node.block);
+ _visitNode(node.block);
}
@override
@@ -228,63 +119,63 @@
@override
void visitBreakStatement(BreakStatement node) {
- sink.write("break");
- safelyVisitNodeWithPrefix(" ", node.label);
- sink.write(";");
+ sink.write('break');
+ _visitNode(node.label, prefix: ' ');
+ sink.write(';');
}
@override
void visitCascadeExpression(CascadeExpression node) {
- safelyVisitNode(node.target);
- safelyVisitNodeList(node.cascadeSections);
+ _visitNode(node.target);
+ _visitNodeList(node.cascadeSections);
}
@override
void visitCatchClause(CatchClause node) {
- safelyVisitNodeWithPrefix("on ", node.exceptionType);
+ _visitNode(node.exceptionType, prefix: 'on ');
if (node.catchKeyword != null) {
if (node.exceptionType != null) {
sink.write(' ');
}
- sink.write("catch (");
- safelyVisitNode(node.exceptionParameter);
- safelyVisitNodeWithPrefix(", ", node.stackTraceParameter);
- sink.write(") ");
+ sink.write('catch (');
+ _visitNode(node.exceptionParameter);
+ _visitNode(node.stackTraceParameter, prefix: ', ');
+ sink.write(') ');
} else {
- sink.write(" ");
+ sink.write(' ');
}
- safelyVisitNode(node.body);
+ _visitNode(node.body);
}
@override
void visitClassDeclaration(ClassDeclaration node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- safelyVisitTokenWithSuffix(node.abstractKeyword, " ");
- sink.write("class ");
- safelyVisitNode(node.name);
- safelyVisitNode(node.typeParameters);
- safelyVisitNodeWithPrefix(" ", node.extendsClause);
- safelyVisitNodeWithPrefix(" ", node.withClause);
- safelyVisitNodeWithPrefix(" ", node.implementsClause);
- sink.write(" {");
- safelyVisitNodeListWithSeparator(node.members, " ");
- sink.write("}");
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitToken(node.abstractKeyword, suffix: ' ');
+ sink.write('class ');
+ _visitNode(node.name);
+ _visitNode(node.typeParameters);
+ _visitNode(node.extendsClause, prefix: ' ');
+ _visitNode(node.withClause, prefix: ' ');
+ _visitNode(node.implementsClause, prefix: ' ');
+ sink.write(' {');
+ _visitNodeList(node.members, separator: ' ');
+ sink.write('}');
}
@override
void visitClassTypeAlias(ClassTypeAlias node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
if (node.abstractKeyword != null) {
- sink.write("abstract ");
+ sink.write('abstract ');
}
- sink.write("class ");
- safelyVisitNode(node.name);
- safelyVisitNode(node.typeParameters);
- sink.write(" = ");
- safelyVisitNode(node.superclass);
- safelyVisitNodeWithPrefix(" ", node.withClause);
- safelyVisitNodeWithPrefix(" ", node.implementsClause);
- sink.write(";");
+ sink.write('class ');
+ _visitNode(node.name);
+ _visitNode(node.typeParameters);
+ sink.write(' = ');
+ _visitNode(node.superclass);
+ _visitNode(node.withClause, prefix: ' ');
+ _visitNode(node.implementsClause, prefix: ' ');
+ sink.write(';');
}
@override
@@ -297,103 +188,103 @@
void visitCompilationUnit(CompilationUnit node) {
var scriptTag = node.scriptTag;
NodeList<Directive> directives = node.directives;
- safelyVisitNode(scriptTag);
- String prefix = scriptTag == null ? "" : " ";
- safelyVisitNodeListWithSeparatorAndPrefix(prefix, directives, " ");
- prefix = scriptTag == null && directives.isEmpty ? "" : " ";
- safelyVisitNodeListWithSeparatorAndPrefix(prefix, node.declarations, " ");
+ _visitNode(scriptTag);
+ String prefix = scriptTag == null ? '' : ' ';
+ _visitNodeList(directives, prefix: prefix, separator: ' ');
+ prefix = scriptTag == null && directives.isEmpty ? '' : ' ';
+ _visitNodeList(node.declarations, prefix: prefix, separator: ' ');
}
@override
void visitConditionalExpression(ConditionalExpression node) {
- safelyVisitNode(node.condition);
- sink.write(" ? ");
- safelyVisitNode(node.thenExpression);
- sink.write(" : ");
- safelyVisitNode(node.elseExpression);
+ _visitNode(node.condition);
+ sink.write(' ? ');
+ _visitNode(node.thenExpression);
+ sink.write(' : ');
+ _visitNode(node.elseExpression);
}
@override
void visitConfiguration(Configuration node) {
sink.write('if (');
- safelyVisitNode(node.name);
- safelyVisitNodeWithPrefix(" == ", node.value);
+ _visitNode(node.name);
+ _visitNode(node.value, prefix: ' == ');
sink.write(') ');
- safelyVisitNode(node.uri);
+ _visitNode(node.uri);
}
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- safelyVisitTokenWithSuffix(node.externalKeyword, " ");
- safelyVisitTokenWithSuffix(node.constKeyword, " ");
- safelyVisitTokenWithSuffix(node.factoryKeyword, " ");
- safelyVisitNode(node.returnType);
- safelyVisitNodeWithPrefix(".", node.name);
- safelyVisitNode(node.parameters);
- safelyVisitNodeListWithSeparatorAndPrefix(" : ", node.initializers, ", ");
- safelyVisitNodeWithPrefix(" = ", node.redirectedConstructor);
- safelyVisitFunctionWithPrefix(" ", node.body);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitToken(node.externalKeyword, suffix: ' ');
+ _visitToken(node.constKeyword, suffix: ' ');
+ _visitToken(node.factoryKeyword, suffix: ' ');
+ _visitNode(node.returnType);
+ _visitNode(node.name, prefix: '.');
+ _visitNode(node.parameters);
+ _visitNodeList(node.initializers, prefix: ' : ', separator: ', ');
+ _visitNode(node.redirectedConstructor, prefix: ' = ');
+ _visitFunctionBody(node.body);
}
@override
void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
- safelyVisitTokenWithSuffix(node.thisKeyword, ".");
- safelyVisitNode(node.fieldName);
- sink.write(" = ");
- safelyVisitNode(node.expression);
+ _visitToken(node.thisKeyword, suffix: '.');
+ _visitNode(node.fieldName);
+ sink.write(' = ');
+ _visitNode(node.expression);
}
@override
void visitConstructorName(ConstructorName node) {
- safelyVisitNode(node.type);
- safelyVisitNodeWithPrefix(".", node.name);
+ _visitNode(node.type);
+ _visitNode(node.name, prefix: '.');
}
@override
void visitConstructorReference(ConstructorReference node) {
- safelyVisitNode(node.constructorName);
+ _visitNode(node.constructorName);
}
@override
void visitContinueStatement(ContinueStatement node) {
- sink.write("continue");
- safelyVisitNodeWithPrefix(" ", node.label);
- sink.write(";");
+ sink.write('continue');
+ _visitNode(node.label, prefix: ' ');
+ sink.write(';');
}
@override
void visitDeclaredIdentifier(DeclaredIdentifier node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- safelyVisitTokenWithSuffix(node.keyword, " ");
- safelyVisitNodeWithSuffix(node.type, " ");
- safelyVisitNode(node.identifier);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitToken(node.keyword, suffix: ' ');
+ _visitNode(node.type, suffix: ' ');
+ _visitNode(node.identifier);
}
@override
void visitDefaultFormalParameter(DefaultFormalParameter node) {
- safelyVisitNode(node.parameter);
+ _visitNode(node.parameter);
if (node.separator != null) {
- if (node.separator!.lexeme != ":") {
- sink.write(" ");
+ if (node.separator!.lexeme != ':') {
+ sink.write(' ');
}
sink.write(node.separator!.lexeme);
- safelyVisitNodeWithPrefix(" ", node.defaultValue);
+ _visitNode(node.defaultValue, prefix: ' ');
}
}
@override
void visitDoStatement(DoStatement node) {
- sink.write("do ");
- safelyVisitNode(node.body);
- sink.write(" while (");
- safelyVisitNode(node.condition);
- sink.write(");");
+ sink.write('do ');
+ _visitNode(node.body);
+ sink.write(' while (');
+ _visitNode(node.condition);
+ sink.write(');');
}
@override
void visitDottedName(DottedName node) {
- safelyVisitNodeListWithSeparator(node.components, ".");
+ _visitNodeList(node.components, separator: '.');
}
@override
@@ -413,26 +304,27 @@
@override
void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- safelyVisitNode(node.name);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitNode(node.name);
}
@override
void visitEnumDeclaration(EnumDeclaration node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- sink.write("enum ");
- safelyVisitNode(node.name);
- sink.write(" {");
- safelyVisitNodeListWithSeparator(node.constants, ", ");
- sink.write("}");
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ sink.write('enum ');
+ _visitNode(node.name);
+ sink.write(' {');
+ _visitNodeList(node.constants, separator: ', ');
+ sink.write('}');
}
@override
void visitExportDirective(ExportDirective node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- sink.write("export ");
- safelyVisitNode(node.uri);
- safelyVisitNodeListWithSeparatorAndPrefix(" ", node.combinators, " ");
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ sink.write('export ');
+ _visitNode(node.uri);
+ _visitNodeList(node.configurations, prefix: ' ', separator: ' ');
+ _visitNodeList(node.combinators, prefix: ' ', separator: ' ');
sink.write(';');
}
@@ -444,7 +336,7 @@
sink.write(' ');
}
sink.write('${node.functionDefinition.lexeme} ');
- safelyVisitNode(node.expression);
+ _visitNode(node.expression);
if (node.semicolon != null) {
sink.write(';');
}
@@ -452,83 +344,83 @@
@override
void visitExpressionStatement(ExpressionStatement node) {
- safelyVisitNode(node.expression);
+ _visitNode(node.expression);
sink.write(';');
}
@override
void visitExtendsClause(ExtendsClause node) {
- sink.write("extends ");
- safelyVisitNode(node.superclass);
+ sink.write('extends ');
+ _visitNode(node.superclass);
}
@override
void visitExtensionDeclaration(ExtensionDeclaration node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, ' ', ' ');
- safelyVisitTokenWithSuffix(node.extensionKeyword, ' ');
- safelyVisitTokenWithSuffix(node.typeKeyword, ' ');
- safelyVisitNode(node.name);
- safelyVisitNode(node.typeParameters);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitToken(node.extensionKeyword, suffix: ' ');
+ _visitToken(node.typeKeyword, suffix: ' ');
+ _visitNode(node.name);
+ _visitNode(node.typeParameters);
sink.write(' ');
- safelyVisitToken(node.onKeyword);
+ _visitToken(node.onKeyword);
sink.write(' ');
- safelyVisitNodeWithSuffix(node.extendedType, ' ');
- safelyVisitToken(node.leftBracket);
- safelyVisitNodeListWithSeparator(node.members, ' ');
- safelyVisitToken(node.rightBracket);
+ _visitNode(node.extendedType, suffix: ' ');
+ _visitToken(node.leftBracket);
+ _visitNodeList(node.members, separator: ' ');
+ _visitToken(node.rightBracket);
}
@override
void visitExtensionOverride(ExtensionOverride node) {
- safelyVisitNode(node.extensionName);
- safelyVisitNode(node.typeArguments);
- safelyVisitNode(node.argumentList);
+ _visitNode(node.extensionName);
+ _visitNode(node.typeArguments);
+ _visitNode(node.argumentList);
}
@override
void visitFieldDeclaration(FieldDeclaration node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- safelyVisitTokenWithSuffix(node.abstractKeyword, " ");
- safelyVisitTokenWithSuffix(node.externalKeyword, " ");
- safelyVisitTokenWithSuffix(node.staticKeyword, " ");
- safelyVisitNode(node.fields);
- sink.write(";");
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitToken(node.abstractKeyword, suffix: ' ');
+ _visitToken(node.externalKeyword, suffix: ' ');
+ _visitToken(node.staticKeyword, suffix: ' ');
+ _visitNode(node.fields);
+ sink.write(';');
}
@override
void visitFieldFormalParameter(FieldFormalParameter node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, ' ', ' ');
- safelyVisitTokenWithSuffix(node.requiredKeyword, " ");
- safelyVisitTokenWithSuffix(node.covariantKeyword, ' ');
- safelyVisitTokenWithSuffix(node.keyword, " ");
- safelyVisitNodeWithSuffix(node.type, " ");
- sink.write("this.");
- safelyVisitNode(node.identifier);
- safelyVisitNode(node.typeParameters);
- safelyVisitNode(node.parameters);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitToken(node.requiredKeyword, suffix: ' ');
+ _visitToken(node.covariantKeyword, suffix: ' ');
+ _visitToken(node.keyword, suffix: ' ');
+ _visitNode(node.type, suffix: ' ');
+ sink.write('this.');
+ _visitNode(node.identifier);
+ _visitNode(node.typeParameters);
+ _visitNode(node.parameters);
}
@override
void visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
- safelyVisitNode(node.loopVariable);
+ _visitNode(node.loopVariable);
sink.write(' in ');
- safelyVisitNode(node.iterable);
+ _visitNode(node.iterable);
}
@override
void visitForEachPartsWithIdentifier(ForEachPartsWithIdentifier node) {
- safelyVisitNode(node.identifier);
+ _visitNode(node.identifier);
sink.write(' in ');
- safelyVisitNode(node.iterable);
+ _visitNode(node.iterable);
}
@override
void visitForElement(ForElement node) {
- safelyVisitTokenWithSuffix(node.awaitKeyword, ' ');
+ _visitToken(node.awaitKeyword, suffix: ' ');
sink.write('for (');
- safelyVisitNode(node.forLoopParts);
+ _visitNode(node.forLoopParts);
sink.write(') ');
- safelyVisitNode(node.body);
+ _visitNode(node.body);
}
@override
@@ -540,14 +432,14 @@
for (int i = 0; i < size; i++) {
FormalParameter parameter = parameters[i];
if (i > 0) {
- sink.write(", ");
+ sink.write(', ');
}
if (groupEnd == null && parameter is DefaultFormalParameter) {
if (parameter.isNamed) {
- groupEnd = "}";
+ groupEnd = '}';
sink.write('{');
} else {
- groupEnd = "]";
+ groupEnd = ']';
sink.write('[');
}
}
@@ -561,20 +453,20 @@
@override
void visitForPartsWithDeclarations(ForPartsWithDeclarations node) {
- safelyVisitNode(node.variables);
+ _visitNode(node.variables);
sink.write(';');
- safelyVisitNodeWithPrefix(' ', node.condition);
+ _visitNode(node.condition, prefix: ' ');
sink.write(';');
- safelyVisitNodeListWithSeparatorAndPrefix(' ', node.updaters, ', ');
+ _visitNodeList(node.updaters, prefix: ' ', separator: ', ');
}
@override
void visitForPartsWithExpression(ForPartsWithExpression node) {
- safelyVisitNode(node.initialization);
+ _visitNode(node.initialization);
sink.write(';');
- safelyVisitNodeWithPrefix(' ', node.condition);
+ _visitNode(node.condition, prefix: ' ');
sink.write(';');
- safelyVisitNodeListWithSeparatorAndPrefix(" ", node.updaters, ', ');
+ _visitNodeList(node.updaters, prefix: ' ', separator: ', ');
}
@override
@@ -583,69 +475,66 @@
sink.write('await ');
}
sink.write('for (');
- safelyVisitNode(node.forLoopParts);
+ _visitNode(node.forLoopParts);
sink.write(') ');
- safelyVisitNode(node.body);
+ _visitNode(node.body);
}
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- safelyVisitTokenWithSuffix(node.externalKeyword, " ");
- safelyVisitNodeWithSuffix(node.returnType, " ");
- safelyVisitTokenWithSuffix(node.propertyKeyword, " ");
- safelyVisitNode(node.name);
- safelyVisitNode(node.functionExpression);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitToken(node.externalKeyword, suffix: ' ');
+ _visitNode(node.returnType, suffix: ' ');
+ _visitToken(node.propertyKeyword, suffix: ' ');
+ _visitNode(node.name);
+ _visitNode(node.functionExpression);
}
@override
void visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
- safelyVisitNode(node.functionDeclaration);
+ _visitNode(node.functionDeclaration);
}
@override
void visitFunctionExpression(FunctionExpression node) {
- safelyVisitNode(node.typeParameters);
- safelyVisitNode(node.parameters);
- if (node.body is! EmptyFunctionBody) {
- sink.write(' ');
- }
- safelyVisitNode(node.body);
+ _visitNode(node.typeParameters);
+ _visitNode(node.parameters);
+ _visitFunctionBody(node.body);
}
@override
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
- safelyVisitNode(node.function);
- safelyVisitNode(node.typeArguments);
- safelyVisitNode(node.argumentList);
+ _visitNode(node.function);
+ _visitNode(node.typeArguments);
+ _visitNode(node.argumentList);
}
@override
void visitFunctionReference(FunctionReference node) {
- safelyVisitNode(node.function);
- safelyVisitNode(node.typeArguments);
+ _visitNode(node.function);
+ _visitNode(node.typeArguments);
}
@override
void visitFunctionTypeAlias(FunctionTypeAlias node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- sink.write("typedef ");
- safelyVisitNodeWithSuffix(node.returnType, " ");
- safelyVisitNode(node.name);
- safelyVisitNode(node.typeParameters);
- safelyVisitNode(node.parameters);
- sink.write(";");
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ sink.write('typedef ');
+ _visitNode(node.returnType, suffix: ' ');
+ _visitNode(node.name);
+ _visitNode(node.typeParameters);
+ _visitNode(node.parameters);
+ sink.write(';');
}
@override
void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, ' ', ' ');
- safelyVisitTokenWithSuffix(node.requiredKeyword, ' ');
- safelyVisitTokenWithSuffix(node.covariantKeyword, ' ');
- safelyVisitNodeWithSuffix(node.returnType, " ");
- safelyVisitNode(node.identifier);
- safelyVisitNode(node.typeParameters);
- safelyVisitNode(node.parameters);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitToken(node.requiredKeyword, suffix: ' ');
+ _visitToken(node.covariantKeyword, suffix: ' ');
+ _visitNode(node.returnType, suffix: ' ');
+ _visitNode(node.identifier);
+ _visitNode(node.typeParameters);
+ _visitNode(node.parameters);
if (node.question != null) {
sink.write('?');
}
@@ -653,10 +542,10 @@
@override
void visitGenericFunctionType(GenericFunctionType node) {
- safelyVisitNode(node.returnType);
+ _visitNode(node.returnType);
sink.write(' Function');
- safelyVisitNode(node.typeParameters);
- safelyVisitNode(node.parameters);
+ _visitNode(node.typeParameters);
+ _visitNode(node.parameters);
if (node.question != null) {
sink.write('?');
}
@@ -664,75 +553,76 @@
@override
void visitGenericTypeAlias(GenericTypeAlias node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- sink.write("typedef ");
- safelyVisitNode(node.name);
- safelyVisitNode(node.typeParameters);
- sink.write(" = ");
- safelyVisitNode(node.type);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ sink.write('typedef ');
+ _visitNode(node.name);
+ _visitNode(node.typeParameters);
+ sink.write(' = ');
+ _visitNode(node.type);
}
@override
void visitHideCombinator(HideCombinator node) {
- sink.write("hide ");
- safelyVisitNodeListWithSeparator(node.hiddenNames, ", ");
+ sink.write('hide ');
+ _visitNodeList(node.hiddenNames, separator: ', ');
}
@override
void visitIfElement(IfElement node) {
sink.write('if (');
- safelyVisitNode(node.condition);
+ _visitNode(node.condition);
sink.write(') ');
- safelyVisitNode(node.thenElement);
- safelyVisitNodeWithPrefix(' else ', node.elseElement);
+ _visitNode(node.thenElement);
+ _visitNode(node.elseElement, prefix: ' else ');
}
@override
void visitIfStatement(IfStatement node) {
- sink.write("if (");
- safelyVisitNode(node.condition);
- sink.write(") ");
- safelyVisitNode(node.thenStatement);
- safelyVisitNodeWithPrefix(" else ", node.elseStatement);
+ sink.write('if (');
+ _visitNode(node.condition);
+ sink.write(') ');
+ _visitNode(node.thenStatement);
+ _visitNode(node.elseStatement, prefix: ' else ');
}
@override
void visitImplementsClause(ImplementsClause node) {
- sink.write("implements ");
- safelyVisitNodeListWithSeparator(node.interfaces, ", ");
+ sink.write('implements ');
+ _visitNodeList(node.interfaces, separator: ', ');
}
@override
void visitImportDirective(ImportDirective node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- sink.write("import ");
- safelyVisitNode(node.uri);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ sink.write('import ');
+ _visitNode(node.uri);
+ _visitNodeList(node.configurations, prefix: ' ', separator: ' ');
if (node.deferredKeyword != null) {
- sink.write(" deferred");
+ sink.write(' deferred');
}
- safelyVisitNodeWithPrefix(" as ", node.prefix);
- safelyVisitNodeListWithSeparatorAndPrefix(" ", node.combinators, " ");
+ _visitNode(node.prefix, prefix: ' as ');
+ _visitNodeList(node.combinators, prefix: ' ', separator: ' ');
sink.write(';');
}
@override
void visitIndexExpression(IndexExpression node) {
if (node.isCascaded) {
- safelyVisitToken(node.period);
+ _visitToken(node.period);
} else {
- safelyVisitNode(node.target);
+ _visitNode(node.target);
}
- safelyVisitToken(node.question);
- safelyVisitToken(node.leftBracket);
- safelyVisitNode(node.index);
- safelyVisitToken(node.rightBracket);
+ _visitToken(node.question);
+ _visitToken(node.leftBracket);
+ _visitNode(node.index);
+ _visitToken(node.rightBracket);
}
@override
void visitInstanceCreationExpression(InstanceCreationExpression node) {
- safelyVisitTokenWithSuffix(node.keyword, " ");
- safelyVisitNode(node.constructorName);
- safelyVisitNode(node.argumentList);
+ _visitToken(node.keyword, suffix: ' ');
+ _visitNode(node.constructorName);
+ _visitNode(node.argumentList);
}
@override
@@ -743,12 +633,12 @@
@override
void visitInterpolationExpression(InterpolationExpression node) {
if (node.rightBracket != null) {
- sink.write("\${");
- safelyVisitNode(node.expression);
- sink.write("}");
+ sink.write('\${');
+ _visitNode(node.expression);
+ sink.write('}');
} else {
- sink.write("\$");
- safelyVisitNode(node.expression);
+ sink.write('\$');
+ _visitNode(node.expression);
}
}
@@ -759,32 +649,32 @@
@override
void visitIsExpression(IsExpression node) {
- safelyVisitNode(node.expression);
+ _visitNode(node.expression);
if (node.notOperator == null) {
- sink.write(" is ");
+ sink.write(' is ');
} else {
- sink.write(" is! ");
+ sink.write(' is! ');
}
- safelyVisitNode(node.type);
+ _visitNode(node.type);
}
@override
void visitLabel(Label node) {
- safelyVisitNode(node.label);
- sink.write(":");
+ _visitNode(node.label);
+ sink.write(':');
}
@override
void visitLabeledStatement(LabeledStatement node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.labels, " ", " ");
- safelyVisitNode(node.statement);
+ _visitNodeList(node.labels, separator: ' ', suffix: ' ');
+ _visitNode(node.statement);
}
@override
void visitLibraryDirective(LibraryDirective node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- sink.write("library ");
- safelyVisitNode(node.name);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ sink.write('library ');
+ _visitNode(node.name);
sink.write(';');
}
@@ -795,34 +685,34 @@
@override
void visitListLiteral(ListLiteral node) {
- safelyVisitTokenWithSuffix(node.constKeyword, ' ');
- safelyVisitNode(node.typeArguments);
+ _visitToken(node.constKeyword, suffix: ' ');
+ _visitNode(node.typeArguments);
sink.write('[');
- safelyVisitNodeListWithSeparator(node.elements, ', ');
+ _visitNodeList(node.elements, separator: ', ');
sink.write(']');
}
@override
void visitMapLiteralEntry(MapLiteralEntry node) {
- safelyVisitNode(node.key);
- sink.write(" : ");
- safelyVisitNode(node.value);
+ _visitNode(node.key);
+ sink.write(' : ');
+ _visitNode(node.value);
}
@override
void visitMethodDeclaration(MethodDeclaration node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- safelyVisitTokenWithSuffix(node.externalKeyword, " ");
- safelyVisitTokenWithSuffix(node.modifierKeyword, " ");
- safelyVisitNodeWithSuffix(node.returnType, " ");
- safelyVisitTokenWithSuffix(node.propertyKeyword, " ");
- safelyVisitTokenWithSuffix(node.operatorKeyword, " ");
- safelyVisitNode(node.name);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitToken(node.externalKeyword, suffix: ' ');
+ _visitToken(node.modifierKeyword, suffix: ' ');
+ _visitNode(node.returnType, suffix: ' ');
+ _visitToken(node.propertyKeyword, suffix: ' ');
+ _visitToken(node.operatorKeyword, suffix: ' ');
+ _visitNode(node.name);
if (!node.isGetter) {
- safelyVisitNode(node.typeParameters);
- safelyVisitNode(node.parameters);
+ _visitNode(node.typeParameters);
+ _visitNode(node.parameters);
}
- safelyVisitFunctionWithPrefix(" ", node.body);
+ _visitFunctionBody(node.body);
}
@override
@@ -835,75 +725,75 @@
sink.write(node.operator!.lexeme);
}
}
- safelyVisitNode(node.methodName);
- safelyVisitNode(node.typeArguments);
- safelyVisitNode(node.argumentList);
+ _visitNode(node.methodName);
+ _visitNode(node.typeArguments);
+ _visitNode(node.argumentList);
}
@override
void visitMixinDeclaration(MixinDeclaration node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- sink.write("mixin ");
- safelyVisitNode(node.name);
- safelyVisitNode(node.typeParameters);
- safelyVisitNodeWithPrefix(" ", node.onClause);
- safelyVisitNodeWithPrefix(" ", node.implementsClause);
- sink.write(" {");
- safelyVisitNodeListWithSeparator(node.members, " ");
- sink.write("}");
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ sink.write('mixin ');
+ _visitNode(node.name);
+ _visitNode(node.typeParameters);
+ _visitNode(node.onClause, prefix: ' ');
+ _visitNode(node.implementsClause, prefix: ' ');
+ sink.write(' {');
+ _visitNodeList(node.members, separator: ' ');
+ sink.write('}');
}
@override
void visitNamedExpression(NamedExpression node) {
- safelyVisitNode(node.name);
- safelyVisitNodeWithPrefix(" ", node.expression);
+ _visitNode(node.name);
+ _visitNode(node.expression, prefix: ' ');
}
@override
void visitNativeClause(NativeClause node) {
- sink.write("native ");
- safelyVisitNode(node.name);
+ sink.write('native ');
+ _visitNode(node.name);
}
@override
void visitNativeFunctionBody(NativeFunctionBody node) {
- sink.write("native ");
- safelyVisitNode(node.stringLiteral);
+ sink.write('native ');
+ _visitNode(node.stringLiteral);
sink.write(';');
}
@override
void visitNullLiteral(NullLiteral node) {
- sink.write("null");
+ sink.write('null');
}
@override
void visitOnClause(OnClause node) {
sink.write('on ');
- safelyVisitNodeListWithSeparator(node.superclassConstraints, ", ");
+ _visitNodeList(node.superclassConstraints, separator: ', ');
}
@override
void visitParenthesizedExpression(ParenthesizedExpression node) {
sink.write('(');
- safelyVisitNode(node.expression);
+ _visitNode(node.expression);
sink.write(')');
}
@override
void visitPartDirective(PartDirective node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- sink.write("part ");
- safelyVisitNode(node.uri);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ sink.write('part ');
+ _visitNode(node.uri);
sink.write(';');
}
@override
void visitPartOfDirective(PartOfDirective node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- sink.write("part of ");
- safelyVisitNode(node.libraryName);
- safelyVisitNode(node.uri);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ sink.write('part of ');
+ _visitNode(node.libraryName);
+ _visitNode(node.uri);
sink.write(';');
}
@@ -915,9 +805,9 @@
@override
void visitPrefixedIdentifier(PrefixedIdentifier node) {
- safelyVisitNode(node.prefix);
+ _visitNode(node.prefix);
sink.write('.');
- safelyVisitNode(node.identifier);
+ _visitNode(node.identifier);
}
@override
@@ -931,34 +821,34 @@
if (node.isCascaded) {
sink.write(node.operator.lexeme);
} else {
- safelyVisitNode(node.target);
+ _visitNode(node.target);
sink.write(node.operator.lexeme);
}
- safelyVisitNode(node.propertyName);
+ _visitNode(node.propertyName);
}
@override
void visitRedirectingConstructorInvocation(
RedirectingConstructorInvocation node) {
- sink.write("this");
- safelyVisitNodeWithPrefix(".", node.constructorName);
- safelyVisitNode(node.argumentList);
+ sink.write('this');
+ _visitNode(node.constructorName, prefix: '.');
+ _visitNode(node.argumentList);
}
@override
void visitRethrowExpression(RethrowExpression node) {
- sink.write("rethrow");
+ sink.write('rethrow');
}
@override
void visitReturnStatement(ReturnStatement node) {
var expression = node.expression;
if (expression == null) {
- sink.write("return;");
+ sink.write('return;');
} else {
- sink.write("return ");
+ sink.write('return ');
expression.accept(this);
- sink.write(";");
+ sink.write(';');
}
}
@@ -969,30 +859,30 @@
@override
void visitSetOrMapLiteral(SetOrMapLiteral node) {
- safelyVisitTokenWithSuffix(node.constKeyword, ' ');
- safelyVisitNode(node.typeArguments);
+ _visitToken(node.constKeyword, suffix: ' ');
+ _visitNode(node.typeArguments);
sink.write('{');
- safelyVisitNodeListWithSeparator(node.elements, ', ');
+ _visitNodeList(node.elements, separator: ', ');
sink.write('}');
}
@override
void visitShowCombinator(ShowCombinator node) {
- sink.write("show ");
- safelyVisitNodeListWithSeparator(node.shownNames, ", ");
+ sink.write('show ');
+ _visitNodeList(node.shownNames, separator: ', ');
}
@override
void visitSimpleFormalParameter(SimpleFormalParameter node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, ' ', ' ');
- safelyVisitTokenWithSuffix(node.requiredKeyword, ' ');
- safelyVisitTokenWithSuffix(node.covariantKeyword, ' ');
- safelyVisitTokenWithSuffix(node.keyword, " ");
- safelyVisitNode(node.type);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitToken(node.requiredKeyword, suffix: ' ');
+ _visitToken(node.covariantKeyword, suffix: ' ');
+ _visitToken(node.keyword, suffix: ' ');
+ _visitNode(node.type);
if (node.type != null && node.identifier != null) {
sink.write(' ');
}
- safelyVisitNode(node.identifier);
+ _visitNode(node.identifier);
}
@override
@@ -1008,58 +898,58 @@
@override
void visitSpreadElement(SpreadElement node) {
sink.write(node.spreadOperator.lexeme);
- safelyVisitNode(node.expression);
+ _visitNode(node.expression);
}
@override
void visitStringInterpolation(StringInterpolation node) {
- safelyVisitNodeList(node.elements);
+ _visitNodeList(node.elements);
}
@override
void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
- sink.write("super");
- safelyVisitNodeWithPrefix(".", node.constructorName);
- safelyVisitNode(node.argumentList);
+ sink.write('super');
+ _visitNode(node.constructorName, prefix: '.');
+ _visitNode(node.argumentList);
}
@override
void visitSuperExpression(SuperExpression node) {
- sink.write("super");
+ sink.write('super');
}
@override
void visitSwitchCase(SwitchCase node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.labels, " ", " ");
- sink.write("case ");
- safelyVisitNode(node.expression);
- sink.write(": ");
- safelyVisitNodeListWithSeparator(node.statements, " ");
+ _visitNodeList(node.labels, separator: ' ', suffix: ' ');
+ sink.write('case ');
+ _visitNode(node.expression);
+ sink.write(': ');
+ _visitNodeList(node.statements, separator: ' ');
}
@override
void visitSwitchDefault(SwitchDefault node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.labels, " ", " ");
- sink.write("default: ");
- safelyVisitNodeListWithSeparator(node.statements, " ");
+ _visitNodeList(node.labels, separator: ' ', suffix: ' ');
+ sink.write('default: ');
+ _visitNodeList(node.statements, separator: ' ');
}
@override
void visitSwitchStatement(SwitchStatement node) {
- sink.write("switch (");
- safelyVisitNode(node.expression);
- sink.write(") {");
- safelyVisitNodeListWithSeparator(node.members, " ");
- sink.write("}");
+ sink.write('switch (');
+ _visitNode(node.expression);
+ sink.write(') {');
+ _visitNodeList(node.members, separator: ' ');
+ sink.write('}');
}
@override
void visitSymbolLiteral(SymbolLiteral node) {
- sink.write("#");
+ sink.write('#');
List<Token> components = node.components;
for (int i = 0; i < components.length; i++) {
if (i > 0) {
- sink.write(".");
+ sink.write('.');
}
sink.write(components[i].lexeme);
}
@@ -1067,45 +957,45 @@
@override
void visitThisExpression(ThisExpression node) {
- sink.write("this");
+ sink.write('this');
}
@override
void visitThrowExpression(ThrowExpression node) {
- sink.write("throw ");
- safelyVisitNode(node.expression);
+ sink.write('throw ');
+ _visitNode(node.expression);
}
@override
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
- safelyVisitTokenWithSuffix(node.externalKeyword, " ");
- safelyVisitNodeWithSuffix(node.variables, ";");
+ _visitToken(node.externalKeyword, suffix: ' ');
+ _visitNode(node.variables, suffix: ';');
}
@override
void visitTryStatement(TryStatement node) {
- sink.write("try ");
- safelyVisitNode(node.body);
- safelyVisitNodeListWithSeparatorAndPrefix(" ", node.catchClauses, " ");
- safelyVisitNodeWithPrefix(" finally ", node.finallyBlock);
+ sink.write('try ');
+ _visitNode(node.body);
+ _visitNodeList(node.catchClauses, prefix: ' ', separator: ' ');
+ _visitNode(node.finallyBlock, prefix: ' finally ');
}
@override
void visitTypeArgumentList(TypeArgumentList node) {
sink.write('<');
- safelyVisitNodeListWithSeparator(node.arguments, ", ");
+ _visitNodeList(node.arguments, separator: ', ');
sink.write('>');
}
@override
void visitTypeLiteral(TypeLiteral node) {
- safelyVisitNode(node.typeName);
+ _visitNode(node.typeName);
}
@override
void visitTypeName(TypeName node) {
- safelyVisitNode(node.name);
- safelyVisitNode(node.typeArguments);
+ _visitNode(node.name);
+ _visitNode(node.typeArguments);
if (node.question != null) {
sink.write('?');
}
@@ -1113,69 +1003,114 @@
@override
void visitTypeParameter(TypeParameter node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
// TODO (kallentu) : Clean up TypeParameterImpl casting once variance is
// added to the interface.
var varianceKeyword = (node as TypeParameterImpl).varianceKeyword;
if (varianceKeyword != null) {
sink.write(varianceKeyword.lexeme + ' ');
}
- safelyVisitNode(node.name);
- safelyVisitNodeWithPrefix(" extends ", node.bound);
+ _visitNode(node.name);
+ _visitNode(node.bound, prefix: ' extends ');
}
@override
void visitTypeParameterList(TypeParameterList node) {
sink.write('<');
- safelyVisitNodeListWithSeparator(node.typeParameters, ", ");
+ _visitNodeList(node.typeParameters, separator: ', ');
sink.write('>');
}
@override
void visitVariableDeclaration(VariableDeclaration node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- safelyVisitNode(node.name);
- safelyVisitNodeWithPrefix(" = ", node.initializer);
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitNode(node.name);
+ _visitNode(node.initializer, prefix: ' = ');
}
@override
void visitVariableDeclarationList(VariableDeclarationList node) {
- safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
- safelyVisitTokenWithSuffix(node.lateKeyword, " ");
- safelyVisitTokenWithSuffix(node.keyword, " ");
- safelyVisitNodeWithSuffix(node.type, " ");
- safelyVisitNodeListWithSeparator(node.variables, ", ");
+ _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+ _visitToken(node.lateKeyword, suffix: ' ');
+ _visitToken(node.keyword, suffix: ' ');
+ _visitNode(node.type, suffix: ' ');
+ _visitNodeList(node.variables, separator: ', ');
}
@override
void visitVariableDeclarationStatement(VariableDeclarationStatement node) {
- safelyVisitNode(node.variables);
- sink.write(";");
+ _visitNode(node.variables);
+ sink.write(';');
}
@override
void visitWhileStatement(WhileStatement node) {
- sink.write("while (");
- safelyVisitNode(node.condition);
- sink.write(") ");
- safelyVisitNode(node.body);
+ sink.write('while (');
+ _visitNode(node.condition);
+ sink.write(') ');
+ _visitNode(node.body);
}
@override
void visitWithClause(WithClause node) {
- sink.write("with ");
- safelyVisitNodeListWithSeparator(node.mixinTypes, ", ");
+ sink.write('with ');
+ _visitNodeList(node.mixinTypes, separator: ', ');
}
@override
void visitYieldStatement(YieldStatement node) {
if (node.star != null) {
- sink.write("yield* ");
+ sink.write('yield* ');
} else {
- sink.write("yield ");
+ sink.write('yield ');
}
- safelyVisitNode(node.expression);
- sink.write(";");
+ _visitNode(node.expression);
+ sink.write(';');
+ }
+
+ /// Visit the given function [body], printing a prefix before if the body
+ /// is not empty.
+ void _visitFunctionBody(FunctionBody body) {
+ if (body is! EmptyFunctionBody) {
+ sink.write(' ');
+ }
+ _visitNode(body);
+ }
+
+ /// Print the given [node], printing the [prefix] before the node,
+ /// and [suffix] after the node, if it is non-`null`.
+ void _visitNode(AstNode? node, {String prefix = '', String suffix = ''}) {
+ if (node != null) {
+ sink.write(prefix);
+ node.accept(this);
+ sink.write(suffix);
+ }
+ }
+
+ /// Print a list of [nodes], separated by the given [separator]; if the list
+ /// is not empty print [prefix] before the first node, and [suffix] after
+ /// the last node.
+ void _visitNodeList(List<AstNode> nodes,
+ {String prefix = '', String separator = '', String suffix = ''}) {
+ var length = nodes.length;
+ if (length > 0) {
+ sink.write(prefix);
+ for (int i = 0; i < length; i++) {
+ if (i > 0) {
+ sink.write(separator);
+ }
+ nodes[i].accept(this);
+ }
+ sink.write(suffix);
+ }
+ }
+
+ /// Print the given [token].
+ void _visitToken(Token? token, {String suffix = ''}) {
+ if (token != null) {
+ sink.write(token.lexeme);
+ sink.write(suffix);
+ }
}
void _writeOperand(Expression node, Expression operand) {
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 531e95f..99c960c 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -983,6 +983,22 @@
@override
late Source librarySource;
+ /// If this unit has macro-generated elements, and is created in the
+ /// environment where the file content is available (e.g. interactive
+ /// analysis, and not batch analysis), then this is a combination of the
+ /// user-written code and macro-generated declarations.
+ ///
+ /// For elements created from the user-written code [Element.nameOffset]s
+ /// are offsets in the user-written code.
+ ///
+ /// For macro-generated elements [Element.nameOffset]s are offsets in the
+ /// combined file containing both user-written and generated code.
+ String? macroGeneratedContent;
+
+ /// If this unit has macro-generated elements, information about each one
+ /// is stored here, so that it can be combined to [macroGeneratedContent].
+ List<MacroGenerationData>? macroGenerationDataList;
+
/// A list containing all of the top-level accessors (getters and setters)
/// contained in this compilation unit.
List<PropertyAccessorElement> _accessors = const [];
@@ -4175,18 +4191,30 @@
/// The code that was produced by the macro. It is used to compose full
/// code of a unit to display to the user, so that new declarations are
- /// added to the unit or existing classes.
+ /// added to the end of the unit or existing classes.
///
/// When a class is generated, its code might have some members, or might
/// be empty, and new elements might be macro-generated into it.
final String code;
- /// When we build elements from macro-produced code, we remember informative
- /// data, such as offsets - to store it into bytes. This field is set to
- /// an empty list when reading from bytes.
+ /// Informative data derived from the [code], such as offsets.
final Uint8List informative;
- MacroGenerationData(this.id, this.code, this.informative);
+ /// If this element is macro-generated into a class declaration, this is
+ /// the index of this class declaration in the unit.
+ final int? classDeclarationIndex;
+
+ /// The offset in [CompilationUnitElementImpl.macroGeneratedContent],
+ /// where the [code] is located. This offset depends on the informative
+ /// data, as any other offset.
+ int offset = 0;
+
+ MacroGenerationData({
+ required this.id,
+ required this.code,
+ required this.informative,
+ required this.classDeclarationIndex,
+ });
}
/// A concrete implementation of a [MethodElement].
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index d52742b..26f8a6d 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -31,6 +31,7 @@
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary2/bundle_reader.dart';
+import 'package:analyzer/src/summary2/informative_data.dart';
import 'package:analyzer/src/summary2/link.dart' as link2;
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/reference.dart';
@@ -834,12 +835,15 @@
var resolutionData = byteStore.get(resolutionKey, cycle.signature);
var resolutionBytes = resolutionData?.bytes;
- var unitsInformativeBytes = <Uri, Uint8List>{};
+ var unitsInformativeData = <Uri, InformativeUnitData>{};
for (var library in cycle.libraries) {
for (var file in library.libraryFiles) {
var informativeBytes = file.informativeBytes;
if (informativeBytes != null) {
- unitsInformativeBytes[file.uri] = informativeBytes;
+ unitsInformativeData[file.uri] = InformativeUnitData(
+ content: file.getContentWithSameDigest(),
+ bytes: informativeBytes,
+ );
}
}
}
@@ -909,7 +913,7 @@
elementFactory.addBundle(
BundleReader(
elementFactory: elementFactory,
- unitsInformativeBytes: unitsInformativeBytes,
+ unitsInformativeData: unitsInformativeData,
resolutionBytes: resolutionBytes as Uint8List,
),
);
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index 840b7b8..7882635 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -78,7 +78,7 @@
_setRhsContext(node, leftType!, operator, right);
}
- var flow = _resolver.flowAnalysis?.flow;
+ var flow = _resolver.flowAnalysis.flow;
if (flow != null && isIfNull) {
flow.ifNullExpression_rightBegin(left, node.readType!);
}
@@ -294,7 +294,6 @@
void checkFinalAlreadyAssigned(Expression left) {
var flowAnalysis = _resolver.flowAnalysis;
- if (flowAnalysis == null) return;
var flow = flowAnalysis.flow;
if (flow == null) return;
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index abb22ed..d569e12 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -104,7 +104,7 @@
left.accept(_resolver);
left = node.leftOperand;
- var flow = _resolver.flowAnalysis?.flow;
+ var flow = _resolver.flowAnalysis.flow;
var leftExtensionOverride = left is ExtensionOverride;
if (!leftExtensionOverride) {
flow?.equalityOp_rightBegin(left, left.typeOrThrow);
@@ -113,7 +113,7 @@
var right = node.rightOperand;
right.accept(_resolver);
right = node.rightOperand;
- var whyNotPromoted = _resolver.flowAnalysis?.flow?.whyNotPromoted(right);
+ var whyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(right);
if (!leftExtensionOverride) {
flow?.equalityOp_end(node, right, right.typeOrThrow, notEqual: notEqual);
@@ -132,7 +132,7 @@
void _resolveIfNull(BinaryExpressionImpl node) {
var left = node.leftOperand;
var right = node.rightOperand;
- var flow = _resolver.flowAnalysis?.flow;
+ var flow = _resolver.flowAnalysis.flow;
var leftContextType = InferenceContext.getContext(node);
if (leftContextType != null && _isNonNullableByDefault) {
@@ -168,7 +168,7 @@
void _resolveLogicalAnd(BinaryExpressionImpl node) {
var left = node.leftOperand;
var right = node.rightOperand;
- var flow = _resolver.flowAnalysis?.flow;
+ var flow = _resolver.flowAnalysis.flow;
InferenceContext.setType(left, _typeProvider.boolType);
InferenceContext.setType(right, _typeProvider.boolType);
@@ -176,7 +176,7 @@
flow?.logicalBinaryOp_begin();
left.accept(_resolver);
left = node.leftOperand;
- var leftWhyNotPromoted = _resolver.flowAnalysis?.flow?.whyNotPromoted(left);
+ var leftWhyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(left);
flow?.logicalBinaryOp_rightBegin(left, node, isAnd: true);
_resolver.checkUnreachableNode(right);
@@ -184,7 +184,7 @@
right.accept(_resolver);
right = node.rightOperand;
var rightWhyNotPromoted =
- _resolver.flowAnalysis!.flow?.whyNotPromoted(right);
+ _resolver.flowAnalysis.flow?.whyNotPromoted(right);
_resolver.nullSafetyDeadCodeVerifier.flowEnd(right);
flow?.logicalBinaryOp_end(node, right, isAnd: true);
@@ -198,7 +198,7 @@
void _resolveLogicalOr(BinaryExpressionImpl node) {
var left = node.leftOperand;
var right = node.rightOperand;
- var flow = _resolver.flowAnalysis?.flow;
+ var flow = _resolver.flowAnalysis.flow;
InferenceContext.setType(left, _typeProvider.boolType);
InferenceContext.setType(right, _typeProvider.boolType);
@@ -206,7 +206,7 @@
flow?.logicalBinaryOp_begin();
left.accept(_resolver);
left = node.leftOperand;
- var leftWhyNotPromoted = _resolver.flowAnalysis?.flow?.whyNotPromoted(left);
+ var leftWhyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(left);
flow?.logicalBinaryOp_rightBegin(left, node, isAnd: false);
_resolver.checkUnreachableNode(right);
@@ -214,7 +214,7 @@
right.accept(_resolver);
right = node.rightOperand;
var rightWhyNotPromoted =
- _resolver.flowAnalysis?.flow?.whyNotPromoted(right);
+ _resolver.flowAnalysis.flow?.whyNotPromoted(right);
_resolver.nullSafetyDeadCodeVerifier.flowEnd(right);
flow?.logicalBinaryOp_end(node, right, isAnd: false);
@@ -264,7 +264,7 @@
right.accept(_resolver);
right = node.rightOperand;
- var whyNotPromoted = _resolver.flowAnalysis?.flow?.whyNotPromoted(right);
+ var whyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(right);
_resolveUserDefinableType(node);
_resolver.checkForArgumentTypeNotAssignableForArgument(right,
diff --git a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
index 04403ce..beb8e4f 100644
--- a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
@@ -130,20 +130,20 @@
}
if (loopVariable != null) {
- _resolver.flowAnalysis?.flow
+ _resolver.flowAnalysis.flow
?.declare(loopVariable.declaredElement!, true);
}
- _resolver.flowAnalysis?.flow?.forEach_bodyBegin(node);
+ _resolver.flowAnalysis.flow?.forEach_bodyBegin(node);
if (identifierElement is PromotableElement &&
forEachParts is ForEachPartsWithIdentifier) {
- _resolver.flowAnalysis?.flow?.write(forEachParts, identifierElement,
+ _resolver.flowAnalysis.flow?.write(forEachParts, identifierElement,
elementType ?? DynamicTypeImpl.instance, null);
}
body.accept(_resolver);
- _resolver.flowAnalysis?.flow?.forEach_end();
+ _resolver.flowAnalysis.flow?.forEach_end();
}
void _forParts(AstNode node, ForParts forParts, AstNode body) {
@@ -153,7 +153,7 @@
forParts.initialization?.accept(_resolver);
}
- _resolver.flowAnalysis?.for_conditionBegin(node);
+ _resolver.flowAnalysis.for_conditionBegin(node);
var condition = forParts.condition;
if (condition != null) {
@@ -161,17 +161,17 @@
condition.accept(_resolver);
condition = forParts.condition!;
var whyNotPromoted =
- _resolver.flowAnalysis?.flow?.whyNotPromoted(condition);
+ _resolver.flowAnalysis.flow?.whyNotPromoted(condition);
_resolver.boolExpressionVerifier
.checkForNonBoolCondition(condition, whyNotPromoted: whyNotPromoted);
}
- _resolver.flowAnalysis?.for_bodyBegin(node, condition);
+ _resolver.flowAnalysis.for_bodyBegin(node, condition);
body.accept(_resolver);
- _resolver.flowAnalysis?.flow?.for_updaterBegin();
+ _resolver.flowAnalysis.flow?.for_updaterBegin();
forParts.updaters.accept(_resolver);
- _resolver.flowAnalysis?.flow?.for_end();
+ _resolver.flowAnalysis.flow?.for_end();
}
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
index 2ea42d8..599eda3 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
@@ -38,8 +38,8 @@
bool isFunctionDeclaration = parent is FunctionDeclaration;
var body = node.body;
- if (_resolver.flowAnalysis!.flow != null && !isFunctionDeclaration) {
- _resolver.flowAnalysis!
+ if (_resolver.flowAnalysis.flow != null && !isFunctionDeclaration) {
+ _resolver.flowAnalysis
.executableDeclaration_enter(node, node.parameters, true);
}
@@ -63,14 +63,14 @@
}
_resolve2(node);
- if (_resolver.flowAnalysis!.flow != null && !isFunctionDeclaration) {
+ if (_resolver.flowAnalysis.flow != null && !isFunctionDeclaration) {
var bodyContext = BodyInferenceContext.of(node.body);
_resolver.checkForBodyMayCompleteNormally(
returnType: bodyContext?.contextType,
body: body,
errorNode: body,
);
- _resolver.flowAnalysis!.flow?.functionExpression_end();
+ _resolver.flowAnalysis.flow?.functionExpression_end();
_resolver.nullSafetyDeadCodeVerifier.flowEnd(node);
}
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
index a73cf65..f665fe8f 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -282,7 +282,7 @@
expression.staticType = type;
if (_typeSystem.isBottom(type)) {
- _resolver.flowAnalysis?.flow?.handleExit();
+ _resolver.flowAnalysis.flow?.handleExit();
}
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index d6267db..d5d7b50 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -194,7 +194,7 @@
expression.staticType = type;
if (_resolver.typeSystem.isBottom(type)) {
- _resolver.flowAnalysis?.flow?.handleExit();
+ _resolver.flowAnalysis.flow?.handleExit();
}
}
@@ -826,7 +826,7 @@
node.methodName,
);
}
- _resolver.flowAnalysis?.flow?.propertyGet(
+ _resolver.flowAnalysis.flow?.propertyGet(
functionExpression,
target,
node.methodName.name,
@@ -843,7 +843,7 @@
NodeReplacer.replace(node, invocation);
node.setProperty(_rewriteResultKey, invocation);
InferenceContext.setTypeFromNode(invocation, node);
- _resolver.flowAnalysis?.transferTestData(node, invocation);
+ _resolver.flowAnalysis.transferTestData(node, invocation);
}
void _setDynamicResolution(MethodInvocationImpl node,
diff --git a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
index c09803d..2927a58 100644
--- a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
@@ -173,7 +173,7 @@
if (operand is SimpleIdentifier) {
var element = operand.staticElement;
if (element is PromotableElement) {
- _resolver.flowAnalysis?.flow
+ _resolver.flowAnalysis.flow
?.write(node, element, operatorReturnType, null);
}
}
@@ -213,6 +213,6 @@
_inferenceHelper.recordStaticType(node, type);
_resolver.nullShortingTermination(node);
- _resolver.flowAnalysis?.flow?.nonNullAssert_end(operand);
+ _resolver.flowAnalysis.flow?.nonNullAssert_end(operand);
}
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index 6e787e6..4f5a2d4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -210,7 +210,7 @@
if (operand is SimpleIdentifier) {
var element = operand.staticElement;
if (element is PromotableElement) {
- _resolver.flowAnalysis?.flow
+ _resolver.flowAnalysis.flow
?.write(node, element, staticType, null);
}
}
@@ -226,13 +226,13 @@
operand.accept(_resolver);
operand = node.operand;
- var whyNotPromoted = _resolver.flowAnalysis?.flow?.whyNotPromoted(operand);
+ var whyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(operand);
_resolver.boolExpressionVerifier.checkForNonBoolNegationExpression(operand,
whyNotPromoted: whyNotPromoted);
_recordStaticType(node, _typeProvider.boolType);
- _resolver.flowAnalysis?.flow?.logicalNot_end(node, operand);
+ _resolver.flowAnalysis.flow?.logicalNot_end(node, operand);
}
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index b8dae44..84c1ec2 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -205,7 +205,7 @@
readElementRequested = _resolver.toLegacyElement(readLookup?.requested);
if (readElementRequested is PropertyAccessorElement &&
!readElementRequested.isStatic) {
- _resolver.flowAnalysis?.flow?.thisOrSuperPropertyGet(node, node.name,
+ _resolver.flowAnalysis.flow?.thisOrSuperPropertyGet(node, node.name,
readElementRequested, readElementRequested.returnType);
}
_resolver.checkReadOfNotAssignedLocalVariable(node, readElementRequested);
@@ -376,7 +376,7 @@
nameErrorEntity: propertyName,
);
- _resolver.flowAnalysis?.flow?.propertyGet(
+ _resolver.flowAnalysis.flow?.propertyGet(
node,
target,
propertyName.name,
@@ -656,7 +656,7 @@
);
}
}
- _resolver.flowAnalysis?.flow?.propertyGet(
+ _resolver.flowAnalysis.flow?.propertyGet(
node,
target,
propertyName.name,
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
index 5fa2a91..2344d90 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
@@ -129,7 +129,7 @@
}
List<DiagnosticMessage> messages = [];
- var flow = _resolver.flowAnalysis?.flow;
+ var flow = _resolver.flowAnalysis.flow;
if (flow != null) {
if (receiver != null) {
messages = _resolver.computeWhyNotPromotedMessages(
diff --git a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
index 63d610e..1e41759 100644
--- a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
@@ -45,24 +45,24 @@
InferenceContext.setTypeFromNode(initializer, node);
if (isTopLevel) {
- _resolver.flowAnalysis?.topLevelDeclaration_enter(node, null);
+ _resolver.flowAnalysis.topLevelDeclaration_enter(node, null);
} else if (element.isLate) {
- _resolver.flowAnalysis?.flow?.lateInitializer_begin(node);
+ _resolver.flowAnalysis.flow?.lateInitializer_begin(node);
}
initializer.accept(_resolver);
initializer = node.initializer!;
var whyNotPromoted =
- _resolver.flowAnalysis?.flow?.whyNotPromoted(initializer);
+ _resolver.flowAnalysis.flow?.whyNotPromoted(initializer);
if (parent.type == null) {
_setInferredType(element, initializer.typeOrThrow);
}
if (isTopLevel) {
- _resolver.flowAnalysis?.topLevelDeclaration_exit();
+ _resolver.flowAnalysis.topLevelDeclaration_exit();
} else if (element.isLate) {
- _resolver.flowAnalysis?.flow?.lateInitializer_end();
+ _resolver.flowAnalysis.flow?.lateInitializer_end();
}
// Initializers of top-level variables and fields are already included
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index fd77bb3..dce95dc 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -13014,9 +13014,6 @@
hasPublishedDocs: true,
uniqueName: 'UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE');
- /**
- * No parameters.
- */
// #### Description
//
// The analyzer produces this diagnostic when an expression whose type is
@@ -13072,16 +13069,6 @@
// }
// }
// ```
- static const CompileTimeErrorCode UNCHECKED_USE_OF_NULLABLE_VALUE =
- CompileTimeErrorCode(
- 'UNCHECKED_USE_OF_NULLABLE_VALUE',
- "An expression whose value can be 'null' must be null-checked before "
- "it can be dereferenced.",
- correction:
- "Try checking that the value isn't 'null' before dereferencing "
- "it.",
- hasPublishedDocs: true);
-
static const CompileTimeErrorCode
UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION = CompileTimeErrorCode(
'UNCHECKED_USE_OF_NULLABLE_VALUE',
diff --git a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
index 3c5caba..35834b5 100644
--- a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
+++ b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
@@ -78,7 +78,7 @@
List<DiagnosticMessage>? messages;
if (errorNode is Expression) {
messages = _resolver.computeWhyNotPromotedMessages(
- errorNode, _resolver.flowAnalysis?.flow?.whyNotPromoted(errorNode)());
+ errorNode, _resolver.flowAnalysis.flow?.whyNotPromoted(errorNode)());
}
report(errorCode, errorNode, receiverType, messages: messages);
return true;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index d776e90..9fad340 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -105,7 +105,7 @@
void popFunctionBodyContext(FunctionBody node) {
var context = _bodyContexts.removeLast();
- var flow = _resolver.flowAnalysis?.flow;
+ var flow = _resolver.flowAnalysis.flow;
var resultType = context.computeInferredReturnType(
endOfBlockIsReachable: flow == null || flow.isReachable,
@@ -261,7 +261,7 @@
/// Otherwise `null`.
DartType? _thisType;
- final FlowAnalysisHelper? flowAnalysis;
+ final FlowAnalysisHelper flowAnalysis;
/// A comment before a function should be resolved in the context of the
/// function. But when we incrementally resolve a comment, we don't want to
@@ -316,7 +316,7 @@
TypeProvider typeProvider,
AnalysisErrorListener errorListener,
{FeatureSet? featureSet,
- FlowAnalysisHelper? flowAnalysisHelper})
+ required FlowAnalysisHelper flowAnalysisHelper})
: this._(
inheritanceManager,
definingLibrary,
@@ -424,11 +424,7 @@
/// Return the object providing promoted or declared types of variables.
LocalVariableTypeProvider get localVariableTypeProvider {
- if (flowAnalysis != null) {
- return flowAnalysis!.localVariableTypeProvider;
- } else {
- return const NonPromotingLocalVariableTypeProvider();
- }
+ return flowAnalysis.localVariableTypeProvider;
}
NullabilitySuffix get noneOrStarSuffix {
@@ -464,7 +460,7 @@
for (int i = 0; i < arguments.length; i++) {
checkForArgumentTypeNotAssignableForArgument(arguments[i],
whyNotPromoted:
- flowAnalysis?.flow == null ? null : whyNotPromotedList[i]);
+ flowAnalysis.flow == null ? null : whyNotPromotedList[i]);
}
}
@@ -474,7 +470,7 @@
required AstNode errorNode,
}) {
if (!_isNonNullableByDefault) return;
- if (!flowAnalysis!.flow!.isReachable) {
+ if (!flowAnalysis.flow!.isReachable) {
return;
}
@@ -512,7 +508,7 @@
SimpleIdentifier node,
Element? element,
) {
- if (flowAnalysis?.flow == null) {
+ if (flowAnalysis.flow == null) {
return;
}
@@ -521,9 +517,9 @@
}
if (element is VariableElement) {
- var assigned = flowAnalysis!
- .isDefinitelyAssigned(node, element as PromotableElement);
- var unassigned = flowAnalysis!.isDefinitelyUnassigned(node, element);
+ var assigned =
+ flowAnalysis.isDefinitelyAssigned(node, element as PromotableElement);
+ var unassigned = flowAnalysis.isDefinitelyUnassigned(node, element);
if (element.isLate) {
if (unassigned) {
@@ -571,11 +567,11 @@
if (whyNotPromoted != null) {
for (var entry in whyNotPromoted.entries) {
var whyNotPromotedVisitor = _WhyNotPromotedVisitor(
- source, errorEntity, flowAnalysis!.dataForTesting);
+ source, errorEntity, flowAnalysis.dataForTesting);
if (typeSystem.isPotentiallyNullable(entry.key)) continue;
var message = entry.value.accept(whyNotPromotedVisitor);
if (message != null) {
- if (flowAnalysis!.dataForTesting != null) {
+ if (flowAnalysis.dataForTesting != null) {
var nonPromotionReasonText = entry.value.shortName;
var args = <String>[];
if (whyNotPromotedVisitor.propertyReference != null) {
@@ -589,7 +585,7 @@
if (args.isNotEmpty) {
nonPromotionReasonText += '(${args.join(', ')})';
}
- flowAnalysis!.dataForTesting!.nonPromotionReasons[errorEntity] =
+ flowAnalysis.dataForTesting!.nonPromotionReasons[errorEntity] =
nonPromotionReasonText;
}
messages = [message];
@@ -630,7 +626,7 @@
if (identical(_unfinishedNullShorts.last, node)) {
do {
_unfinishedNullShorts.removeLast();
- flowAnalysis!.flow!.nullAwareAccess_end();
+ flowAnalysis.flow!.nullAwareAccess_end();
} while (identical(_unfinishedNullShorts.last, node));
if (node is! CascadeExpression && !discardType) {
node.staticType = typeSystem.makeNullable(node.staticType as TypeImpl);
@@ -713,7 +709,7 @@
InferenceContext.setType(node.index, result.indexContextType);
node.index.accept(this);
- var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(node.index);
+ var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(node.index);
checkIndexExpressionIndex(
node.index,
readElement: result.readElement as ExecutableElement?,
@@ -844,7 +840,7 @@
void startNullAwareIndexExpression(IndexExpression node) {
if (_migratableAstInfoProvider.isIndexExpressionNullAware(node)) {
- var flow = flowAnalysis?.flow;
+ var flow = flowAnalysis.flow;
if (flow != null) {
flow.nullAwareAccess_rightBegin(node.target,
node.realTarget.staticType ?? typeProvider.dynamicType);
@@ -855,7 +851,7 @@
void startNullAwarePropertyAccess(PropertyAccess node) {
if (_migratableAstInfoProvider.isPropertyAccessNullAware(node)) {
- var flow = flowAnalysis?.flow;
+ var flow = flowAnalysis.flow;
if (flow != null) {
var target = node.target;
if (target is SimpleIdentifier &&
@@ -970,7 +966,7 @@
}
checkUnreachableNode(node);
int length = arguments.length;
- var flow = flowAnalysis?.flow;
+ var flow = flowAnalysis.flow;
for (var i = 0; i < length; i++) {
if (isIdentical && length > 1 && i == 1) {
var firstArg = arguments[0];
@@ -993,37 +989,37 @@
@override
void visitAsExpression(AsExpression node) {
super.visitAsExpression(node);
- flowAnalysis?.asExpression(node);
+ flowAnalysis.asExpression(node);
}
@override
void visitAssertInitializer(AssertInitializer node) {
InferenceContext.setType(node.condition, typeProvider.boolType);
- flowAnalysis?.flow?.assert_begin();
+ flowAnalysis.flow?.assert_begin();
node.condition.accept(this);
boolExpressionVerifier.checkForNonBoolExpression(
node.condition,
errorCode: CompileTimeErrorCode.NON_BOOL_EXPRESSION,
- whyNotPromoted: flowAnalysis?.flow?.whyNotPromoted(node.condition),
+ whyNotPromoted: flowAnalysis.flow?.whyNotPromoted(node.condition),
);
- flowAnalysis?.flow?.assert_afterCondition(node.condition);
+ flowAnalysis.flow?.assert_afterCondition(node.condition);
node.message?.accept(this);
- flowAnalysis?.flow?.assert_end();
+ flowAnalysis.flow?.assert_end();
}
@override
void visitAssertStatement(AssertStatement node) {
InferenceContext.setType(node.condition, typeProvider.boolType);
- flowAnalysis?.flow?.assert_begin();
+ flowAnalysis.flow?.assert_begin();
node.condition.accept(this);
boolExpressionVerifier.checkForNonBoolExpression(
node.condition,
errorCode: CompileTimeErrorCode.NON_BOOL_EXPRESSION,
- whyNotPromoted: flowAnalysis?.flow?.whyNotPromoted(node.condition),
+ whyNotPromoted: flowAnalysis.flow?.whyNotPromoted(node.condition),
);
- flowAnalysis?.flow?.assert_afterCondition(node.condition);
+ flowAnalysis.flow?.assert_afterCondition(node.condition);
node.message?.accept(this);
- flowAnalysis?.flow?.assert_end();
+ flowAnalysis.flow?.assert_end();
}
@override
@@ -1060,7 +1056,7 @@
@override
void visitBooleanLiteral(BooleanLiteral node) {
- flowAnalysis?.flow?.booleanLiteral(node, node.value);
+ flowAnalysis.flow?.booleanLiteral(node, node.value);
super.visitBooleanLiteral(node);
}
@@ -1073,7 +1069,7 @@
checkUnreachableNode(node);
node.accept(elementResolver);
node.accept(typeAnalyzer);
- flowAnalysis?.breakStatement(node);
+ flowAnalysis.breakStatement(node);
}
@override
@@ -1081,8 +1077,8 @@
InferenceContext.setTypeFromNode(node.target, node);
node.target.accept(this);
- if (node.isNullAware && flowAnalysis != null) {
- flowAnalysis!.flow!.nullAwareAccess_rightBegin(
+ if (node.isNullAware) {
+ flowAnalysis.flow!.nullAwareAccess_rightBegin(
node.target, node.target.staticType ?? typeProvider.dynamicType);
_unfinishedNullShorts.add(node.nullShortingTermination);
}
@@ -1148,13 +1144,13 @@
@override
void visitConditionalExpression(ConditionalExpression node) {
Expression condition = node.condition;
- var flow = flowAnalysis?.flow;
+ var flow = flowAnalysis.flow;
flow?.conditional_conditionBegin();
// TODO(scheglov) Do we need these checks for null?
condition.accept(this);
condition = node.condition;
- var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(condition);
+ var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
boolExpressionVerifier.checkForNonBoolCondition(condition,
whyNotPromoted: whyNotPromoted);
@@ -1193,8 +1189,8 @@
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
- flowAnalysis!.topLevelDeclaration_enter(node, node.parameters);
- flowAnalysis!.executableDeclaration_enter(node, node.parameters, false);
+ flowAnalysis.topLevelDeclaration_enter(node, node.parameters);
+ flowAnalysis.executableDeclaration_enter(node, node.parameters, false);
var returnType = node.declaredElement!.type.returnType;
InferenceContext.setType(node.body, returnType);
@@ -1218,8 +1214,8 @@
errorNode: node,
);
}
- flowAnalysis!.executableDeclaration_exit(node.body, false);
- flowAnalysis!.topLevelDeclaration_exit();
+ flowAnalysis.executableDeclaration_exit(node.body, false);
+ flowAnalysis.topLevelDeclaration_exit();
nullSafetyDeadCodeVerifier.flowEnd(node);
}
@@ -1232,7 +1228,7 @@
var fieldElement = enclosingClass!.getField(node.fieldName.name);
InferenceContext.setType(node.expression, fieldElement?.type);
node.expression.accept(this);
- var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(node.expression);
+ var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(node.expression);
node.accept(elementResolver);
node.accept(typeAnalyzer);
var enclosingConstructor = enclosingFunction as ConstructorElement;
@@ -1268,7 +1264,7 @@
checkUnreachableNode(node);
node.accept(elementResolver);
node.accept(typeAnalyzer);
- flowAnalysis?.continueStatement(node);
+ flowAnalysis.continueStatement(node);
}
@override
@@ -1289,18 +1285,18 @@
var body = node.body;
var condition = node.condition;
- flowAnalysis?.flow?.doStatement_bodyBegin(node);
+ flowAnalysis.flow?.doStatement_bodyBegin(node);
body.accept(this);
- flowAnalysis?.flow?.doStatement_conditionBegin();
+ flowAnalysis.flow?.doStatement_conditionBegin();
InferenceContext.setType(condition, typeProvider.boolType);
condition.accept(this);
condition = node.condition;
- var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(condition);
+ var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
boolExpressionVerifier.checkForNonBoolCondition(condition,
whyNotPromoted: whyNotPromoted);
- flowAnalysis?.flow?.doStatement_end(condition);
+ flowAnalysis.flow?.doStatement_end(condition);
}
@override
@@ -1349,7 +1345,7 @@
super.visitExpressionFunctionBody(node);
- flowAnalysis?.flow?.handleExit();
+ flowAnalysis.flow?.handleExit();
inferenceContext.bodyContext!.addReturnExpression(node.expression);
} finally {
@@ -1414,12 +1410,12 @@
bool isLocal = node.parent is FunctionDeclarationStatement;
if (isLocal) {
- flowAnalysis!.flow!.functionExpression_begin(node);
+ flowAnalysis.flow!.functionExpression_begin(node);
} else {
- flowAnalysis!
- .topLevelDeclaration_enter(node, node.functionExpression.parameters);
+ flowAnalysis.topLevelDeclaration_enter(
+ node, node.functionExpression.parameters);
}
- flowAnalysis!.executableDeclaration_enter(
+ flowAnalysis.executableDeclaration_enter(
node,
node.functionExpression.parameters,
isLocal,
@@ -1445,14 +1441,14 @@
body: node.functionExpression.body,
errorNode: node.name,
);
- flowAnalysis!.executableDeclaration_exit(
+ flowAnalysis.executableDeclaration_exit(
node.functionExpression.body,
isLocal,
);
if (isLocal) {
- flowAnalysis!.flow!.functionExpression_end();
+ flowAnalysis.flow!.functionExpression_end();
} else {
- flowAnalysis!.topLevelDeclaration_exit();
+ flowAnalysis.topLevelDeclaration_exit();
}
nullSafetyDeadCodeVerifier.flowEnd(node);
@@ -1516,27 +1512,27 @@
@override
void visitIfElement(IfElement node) {
- flowAnalysis?.flow?.ifStatement_conditionBegin();
+ flowAnalysis.flow?.ifStatement_conditionBegin();
Expression condition = node.condition;
InferenceContext.setType(condition, typeProvider.boolType);
condition.accept(this);
condition = node.condition;
- var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(condition);
+ var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
boolExpressionVerifier.checkForNonBoolCondition(condition,
whyNotPromoted: whyNotPromoted);
CollectionElement thenElement = node.thenElement;
- flowAnalysis!.flow?.ifStatement_thenBegin(condition, node);
+ flowAnalysis.flow?.ifStatement_thenBegin(condition, node);
thenElement.accept(this);
var elseElement = node.elseElement;
if (elseElement != null) {
- flowAnalysis?.flow?.ifStatement_elseBegin();
+ flowAnalysis.flow?.ifStatement_elseBegin();
elseElement.accept(this);
}
- flowAnalysis?.flow?.ifStatement_end(elseElement != null);
+ flowAnalysis.flow?.ifStatement_end(elseElement != null);
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -1545,31 +1541,31 @@
@override
void visitIfStatement(IfStatement node) {
checkUnreachableNode(node);
- flowAnalysis?.flow?.ifStatement_conditionBegin();
+ flowAnalysis.flow?.ifStatement_conditionBegin();
Expression condition = node.condition;
InferenceContext.setType(condition, typeProvider.boolType);
condition.accept(this);
condition = node.condition;
- var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(condition);
+ var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
boolExpressionVerifier.checkForNonBoolCondition(condition,
whyNotPromoted: whyNotPromoted);
Statement thenStatement = node.thenStatement;
- flowAnalysis!.flow?.ifStatement_thenBegin(condition, node);
+ flowAnalysis.flow?.ifStatement_thenBegin(condition, node);
thenStatement.accept(this);
nullSafetyDeadCodeVerifier.flowEnd(thenStatement);
var elseStatement = node.elseStatement;
if (elseStatement != null) {
- flowAnalysis?.flow?.ifStatement_elseBegin();
+ flowAnalysis.flow?.ifStatement_elseBegin();
elseStatement.accept(this);
nullSafetyDeadCodeVerifier.flowEnd(elseStatement);
}
- flowAnalysis?.flow?.ifStatement_end(elseStatement != null);
+ flowAnalysis.flow?.ifStatement_end(elseStatement != null);
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -1592,7 +1588,7 @@
InferenceContext.setType(node.index, result.indexContextType);
node.index.accept(this);
- var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(node.index);
+ var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(node.index);
checkIndexExpressionIndex(
node.index,
readElement: result.readElement as ExecutableElement?,
@@ -1622,7 +1618,7 @@
@override
void visitIsExpression(IsExpression node) {
super.visitIsExpression(node);
- flowAnalysis?.isExpression(node);
+ flowAnalysis.isExpression(node);
}
@override
@@ -1630,9 +1626,9 @@
@override
void visitLabeledStatement(LabeledStatement node) {
- flowAnalysis?.labeledStatement_enter(node);
+ flowAnalysis.labeledStatement_enter(node);
super.visitLabeledStatement(node);
- flowAnalysis?.labeledStatement_exit(node);
+ flowAnalysis.labeledStatement_exit(node);
}
@override
@@ -1646,8 +1642,8 @@
@override
void visitMethodDeclaration(MethodDeclaration node) {
- flowAnalysis!.topLevelDeclaration_enter(node, node.parameters);
- flowAnalysis!.executableDeclaration_enter(node, node.parameters, false);
+ flowAnalysis.topLevelDeclaration_enter(node, node.parameters);
+ flowAnalysis.executableDeclaration_enter(node, node.parameters, false);
DartType returnType = node.declaredElement!.returnType;
InferenceContext.setType(node.body, returnType);
@@ -1670,8 +1666,8 @@
body: node.body,
errorNode: node.name,
);
- flowAnalysis!.executableDeclaration_exit(node.body, false);
- flowAnalysis!.topLevelDeclaration_exit();
+ flowAnalysis.executableDeclaration_exit(node.body, false);
+ flowAnalysis.topLevelDeclaration_exit();
nullSafetyDeadCodeVerifier.flowEnd(node);
node.accept(elementResolver);
@@ -1686,7 +1682,7 @@
target?.accept(this);
if (_migratableAstInfoProvider.isMethodInvocationNullAware(node)) {
- var flow = flowAnalysis?.flow;
+ var flow = flowAnalysis.flow;
if (flow != null) {
if (target is SimpleIdentifierImpl &&
target.staticElement is ClassElement) {
@@ -1738,7 +1734,7 @@
// Any "why not promoted" information that flow analysis had associated with
// `node.expression` now needs to be forwarded to `node`, so that when
// `visitArgumentList` iterates through the arguments, it will find it.
- flowAnalysis?.flow?.forwardExpression(node, node.expression);
+ flowAnalysis.flow?.forwardExpression(node, node.expression);
}
@override
@@ -1751,7 +1747,7 @@
@override
void visitNullLiteral(NullLiteral node) {
- flowAnalysis?.flow?.nullLiteral(node);
+ flowAnalysis.flow?.nullLiteral(node);
super.visitNullLiteral(node);
}
@@ -1759,7 +1755,7 @@
void visitParenthesizedExpression(ParenthesizedExpression node) {
InferenceContext.setTypeFromNode(node.expression, node);
super.visitParenthesizedExpression(node);
- flowAnalysis?.flow?.parenthesizedExpression(node, node.expression);
+ flowAnalysis.flow?.parenthesizedExpression(node, node.expression);
}
@override
@@ -1834,7 +1830,7 @@
@override
void visitRethrowExpression(RethrowExpression node) {
super.visitRethrowExpression(node);
- flowAnalysis?.flow?.handleExit();
+ flowAnalysis.flow?.handleExit();
}
@override
@@ -1847,7 +1843,7 @@
super.visitReturnStatement(node);
inferenceContext.bodyContext?.addReturnExpression(node.expression);
- flowAnalysis?.flow?.handleExit();
+ flowAnalysis.flow?.handleExit();
}
@override
@@ -1901,7 +1897,7 @@
node.expression, _enclosingSwitchStatementExpressionType);
super.visitSwitchCase(node);
- var flow = flowAnalysis?.flow;
+ var flow = flowAnalysis.flow;
if (flow != null && flow.isReachable && _isNonNullableByDefault) {
var switchStatement = node.parent as SwitchStatement;
if (switchStatement.members.last != node && node.statements.isNotEmpty) {
@@ -1933,27 +1929,23 @@
_enclosingSwitchStatementExpressionType = expression.typeOrThrow;
- if (flowAnalysis != null) {
- var flow = flowAnalysis!.flow!;
+ var flow = flowAnalysis.flow!;
- flow.switchStatement_expressionEnd(node);
+ flow.switchStatement_expressionEnd(node);
- var exhaustiveness = _SwitchExhaustiveness(
- _enclosingSwitchStatementExpressionType!,
- );
+ var exhaustiveness = _SwitchExhaustiveness(
+ _enclosingSwitchStatementExpressionType!,
+ );
- var members = node.members;
- for (var member in members) {
- flow.switchStatement_beginCase(member.labels.isNotEmpty, node);
- member.accept(this);
+ var members = node.members;
+ for (var member in members) {
+ flow.switchStatement_beginCase(member.labels.isNotEmpty, node);
+ member.accept(this);
- exhaustiveness.visitSwitchMember(member);
- }
-
- flow.switchStatement_end(exhaustiveness.isExhaustive);
- } else {
- node.members.accept(this);
+ exhaustiveness.visitSwitchMember(member);
}
+
+ flow.switchStatement_end(exhaustiveness.isExhaustive);
} finally {
_enclosingSwitchStatementExpressionType = previousExpressionType;
}
@@ -1962,17 +1954,13 @@
@override
void visitThrowExpression(ThrowExpression node) {
super.visitThrowExpression(node);
- flowAnalysis?.flow?.handleExit();
+ flowAnalysis.flow?.handleExit();
}
@override
void visitTryStatement(TryStatement node) {
- if (flowAnalysis == null) {
- return super.visitTryStatement(node);
- }
-
checkUnreachableNode(node);
- var flow = flowAnalysis!.flow!;
+ var flow = flowAnalysis.flow!;
var body = node.body;
var catchClauses = node.catchClauses;
@@ -2044,11 +2032,11 @@
if (declaredType == null) {
if (_isNonNullableByDefault &&
initializerStaticType is TypeParameterType) {
- flowAnalysis?.flow?.promote(
+ flowAnalysis.flow?.promote(
declaredElement as PromotableElement, initializerStaticType);
}
} else {
- flowAnalysis?.flow?.initialize(declaredElement as PromotableElement,
+ flowAnalysis.flow?.initialize(declaredElement as PromotableElement,
initializerStaticType, initializer,
isFinal: parent.isFinal, isLate: parent.isLate);
}
@@ -2057,7 +2045,7 @@
@override
void visitVariableDeclarationList(VariableDeclarationList node) {
- flowAnalysis?.variableDeclarationList(node);
+ flowAnalysis.variableDeclarationList(node);
for (VariableDeclaration decl in node.variables) {
VariableElement variableElement = decl.declaredElement!;
InferenceContext.setType(decl, variableElement.type);
@@ -2072,18 +2060,18 @@
Expression condition = node.condition;
InferenceContext.setType(condition, typeProvider.boolType);
- flowAnalysis?.flow?.whileStatement_conditionBegin(node);
+ flowAnalysis.flow?.whileStatement_conditionBegin(node);
condition.accept(this);
condition = node.condition;
- var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(condition);
+ var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
boolExpressionVerifier.checkForNonBoolCondition(node.condition,
whyNotPromoted: whyNotPromoted);
Statement body = node.body;
- flowAnalysis?.flow?.whileStatement_bodyBegin(node, condition);
+ flowAnalysis.flow?.whileStatement_bodyBegin(node, condition);
body.accept(this);
- flowAnalysis?.flow?.whileStatement_end();
+ flowAnalysis.flow?.whileStatement_end();
nullSafetyDeadCodeVerifier.flowEnd(node.body);
// TODO(brianwilkerson) If the loop can only be exited because the condition
// is false, then propagateFalseState(condition);
@@ -2125,7 +2113,7 @@
if (target is SimpleIdentifier && target.staticElement is ClassElement) {
// `?.` to access static methods is equivalent to `.`, so do nothing.
} else {
- flowAnalysis!.flow!.nullAwareAccess_rightBegin(function,
+ flowAnalysis.flow!.nullAwareAccess_rightBegin(function,
function.realTarget.staticType ?? typeProvider.dynamicType);
_unfinishedNullShorts.add(node.nullShortingTermination);
}
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 43750b2..4c44ba5 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -59,7 +59,7 @@
expression.staticType = type;
if (_typeSystem.isBottom(type)) {
- _resolver.flowAnalysis?.flow?.handleExit();
+ _resolver.flowAnalysis.flow?.handleExit();
}
}
@@ -270,7 +270,7 @@
@override
void visitSuperExpression(covariant SuperExpressionImpl node) {
var thisType = _resolver.thisType;
- _resolver.flowAnalysis?.flow?.thisOrSuper(node, thisType ?? _dynamicType);
+ _resolver.flowAnalysis.flow?.thisOrSuper(node, thisType ?? _dynamicType);
if (thisType == null ||
node.thisOrAncestorOfType<ExtensionDeclaration>() != null) {
// TODO(brianwilkerson) Report this error if it hasn't already been
@@ -291,7 +291,7 @@
@override
void visitThisExpression(covariant ThisExpressionImpl node) {
var thisType = _resolver.thisType;
- _resolver.flowAnalysis?.flow?.thisOrSuper(node, thisType ?? _dynamicType);
+ _resolver.flowAnalysis.flow?.thisOrSuper(node, thisType ?? _dynamicType);
if (thisType == null) {
// TODO(brianwilkerson) Report this error if it hasn't already been
// reported.
diff --git a/pkg/analyzer/lib/src/generated/variable_type_provider.dart b/pkg/analyzer/lib/src/generated/variable_type_provider.dart
index 4258443..35cf432 100644
--- a/pkg/analyzer/lib/src/generated/variable_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/variable_type_provider.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
/// Provider of types for local variables and formal parameters.
@@ -12,15 +11,3 @@
/// return the type of the variable at the node - declared or promoted.
DartType getType(SimpleIdentifier node, {required bool isRead});
}
-
-/// Implementation of [LocalVariableTypeProvider] that does not promote, for use
-/// in situations where no flow analysis is being done. This happens in some
-/// analyzer internal unit tests.
-class NonPromotingLocalVariableTypeProvider
- implements LocalVariableTypeProvider {
- const NonPromotingLocalVariableTypeProvider();
-
- @override
- DartType getType(SimpleIdentifier node, {required bool isRead}) =>
- (node.staticElement as VariableElement).type;
-}
diff --git a/pkg/analyzer/lib/src/macro/impl/macro.dart b/pkg/analyzer/lib/src/macro/impl/macro.dart
index 73e10f7..989bdb4 100644
--- a/pkg/analyzer/lib/src/macro/impl/macro.dart
+++ b/pkg/analyzer/lib/src/macro/impl/macro.dart
@@ -2,23 +2,33 @@
// 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:typed_data';
-
import 'package:analyzer/dart/analysis/utilities.dart';
import 'package:analyzer/dart/ast/ast.dart' as ast;
import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
import 'package:analyzer/src/dart/ast/ast.dart' as ast;
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/macro/api/code.dart';
import 'package:analyzer/src/macro/api/macro.dart';
import 'package:analyzer/src/summary2/informative_data.dart';
+import 'package:analyzer/src/summary2/library_builder.dart';
class ClassDeclarationBuilderImpl extends DeclarationBuilderImpl
implements ClassDeclarationBuilder {
- final DeclarationCollector _collector;
+ final LinkingUnit linkingUnit;
+
+ /// The index of [node] among other [ast.ClassDeclarationImpl]s.
+ final int nodeIndex;
+
final ast.ClassDeclarationImpl node;
- ClassDeclarationBuilderImpl(this._collector, this.node);
+ ClassDeclarationBuilderImpl(
+ this.linkingUnit,
+ this.nodeIndex,
+ this.node,
+ );
@override
void addToClass(Declaration declaration) {
@@ -35,7 +45,18 @@
_rebaseOffsets(parsedMember);
node.members.add(parsedMember);
- _collector._add(parsedMember, declaration);
+
+ var macroGeneratedContent = linkingUnit.macroGeneratedContent;
+ var collected = _Declaration(
+ data: MacroGenerationData(
+ id: macroGeneratedContent.nextId++,
+ code: declarationCode,
+ informative: writeDeclarationInformative(parsedMember),
+ classDeclarationIndex: nodeIndex,
+ ),
+ node: parsedMember,
+ );
+ macroGeneratedContent._declarations.add(collected);
}
/// We parsed [node] in the context of some synthetic code string, its
@@ -63,46 +84,136 @@
}
}
-class DeclarationCollector {
- final Map<ast.AstNode, _CollectedDeclaration> _declarations = {};
- int _nextId = 0;
+class MacroGeneratedContent {
+ final LinkingUnit linkingUnit;
+ final List<_Declaration> _declarations = [];
+ int nextId = 0;
- /// Elements for nodes in [_declarations] were built.
- /// Move information from [_CollectedDeclaration] into elements.
- void updateElements() {
- for (var entry in _declarations.entries) {
- var node = entry.key;
+ MacroGeneratedContent(this.linkingUnit);
+
+ /// Finish building of elements: combine the source code of the unit with
+ /// macro-generated pieces of code; update offsets of macro-generated
+ /// elements to use offsets inside this combined code.
+ void finish() {
+ // Don't set empty values, keep it null.
+ if (_declarations.isEmpty) {
+ return;
+ }
+
+ // Sort declarations by:
+ // 1. The top-level declaration location.
+ // 2. The ordering in the top-level declaration.
+ // We need (2) because `sort` is not stable.
+ _declarations.sort((a, b) {
+ const indexForUnit = 1 << 24;
+ var aIndex = a.data.classDeclarationIndex ?? indexForUnit;
+ var bIndex = b.data.classDeclarationIndex ?? indexForUnit;
+ if (aIndex != bIndex) {
+ return aIndex - bIndex;
+ }
+ return a.data.id - b.data.id;
+ });
+
+ const classMemberCodePrefix = '\n';
+ const classMemberCodeSuffix = '\n';
+ // TODO(scheglov) make it required?
+ var generatedContent = linkingUnit.input.sourceContent!;
+ var shift = 0;
+ var classDeclarations = linkingUnit.input.unit.declarations
+ .whereType<ast.ClassDeclaration>()
+ .toList();
+ for (var declaration in _declarations) {
+ var classIndex = declaration.data.classDeclarationIndex;
+ if (classIndex != null) {
+ var targetClass = classDeclarations[classIndex];
+ var code = classMemberCodePrefix +
+ declaration.data.code +
+ classMemberCodeSuffix;
+ var insertOffset = shift + targetClass.rightBracket.offset;
+ declaration.data.offset = insertOffset + classMemberCodePrefix.length;
+ generatedContent = generatedContent.substring(0, insertOffset) +
+ code +
+ generatedContent.substring(insertOffset);
+ shift += code.length;
+ } else {
+ throw UnimplementedError();
+ }
+
+ var node = declaration.node;
if (node is ast.Declaration) {
- var element = node.declaredElement;
+ var element = node.declaredElement as ElementImpl;
+ element.accept(
+ _ShiftOffsetsElementVisitor(declaration.data.offset),
+ );
if (element is HasMacroGenerationData) {
- var collectedDeclaration = entry.value;
- (element as HasMacroGenerationData).macro = MacroGenerationData(
- collectedDeclaration.id,
- collectedDeclaration.declaration.code,
- collectedDeclaration.informative,
- );
+ (element as HasMacroGenerationData).macro = declaration.data;
}
}
}
- }
- void _add(ast.AstNode node, Declaration declaration) {
- _declarations[node] = _CollectedDeclaration(
- _nextId++,
- declaration,
- writeDeclarationInformative(node),
- );
+ linkingUnit.element.macroGeneratedContent = generatedContent;
+ linkingUnit.element.macroGenerationDataList =
+ _declarations.map((e) => e.data).toList();
}
}
-class _CollectedDeclaration {
- final int id;
- final Declaration declaration;
- final Uint8List informative;
+/// [MacroGenerationData] plus its linking [node] (to get the element).
+class _Declaration {
+ final MacroGenerationData data;
+ final ast.AstNode node;
- _CollectedDeclaration(
- this.id,
- this.declaration,
- this.informative,
- );
+ _Declaration({
+ required this.data,
+ required this.node,
+ });
+}
+
+/// TODO(scheglov) Enhance to support more nodes.
+/// For now only nodes that are currently used in tests are supported.
+/// Which is probably enough for experiments, but should be improved if this
+/// is something we are going to do for real.
+class _ShiftOffsetsAstVisitor extends RecursiveAstVisitor<void> {
+ final int shift;
+
+ _ShiftOffsetsAstVisitor(this.shift);
+
+ @override
+ void visitAnnotation(ast.Annotation node) {
+ _token(node.atSign);
+ super.visitAnnotation(node);
+ }
+
+ @override
+ void visitSimpleIdentifier(ast.SimpleIdentifier node) {
+ _token(node.token);
+ }
+
+ void _token(Token token) {
+ token.offset += shift;
+ }
+}
+
+/// Macro-generated elements are created from pieces of code that are rebased
+/// to start at zero-th offset. When we later know that actual offset in the
+/// combined (source + generated) code of the unit, we shift the offsets.
+class _ShiftOffsetsElementVisitor extends GeneralizingElementVisitor<void> {
+ final int shift;
+
+ _ShiftOffsetsElementVisitor(this.shift);
+
+ @override
+ void visitElement(covariant ElementImpl element) {
+ element.nameOffset += shift;
+ _metadata(element.metadata);
+ super.visitElement(element);
+ }
+
+ void _metadata(List<ElementAnnotation> metadata) {
+ for (var annotation in metadata) {
+ annotation as ElementAnnotationImpl;
+ annotation.annotationAst.accept(
+ _ShiftOffsetsAstVisitor(shift),
+ );
+ }
+ }
}
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index 2c9d02c..c6ae30c 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -30,16 +30,16 @@
class BundleReader {
final SummaryDataReader _reader;
- final Map<Uri, Uint8List> _unitsInformativeBytes;
+ final Map<Uri, InformativeUnitData> _unitsInformativeData;
final Map<String, LibraryReader> libraryMap = {};
BundleReader({
required LinkedElementFactory elementFactory,
required Uint8List resolutionBytes,
- Map<Uri, Uint8List> unitsInformativeBytes = const {},
+ Map<Uri, InformativeUnitData> unitsInformativeData = const {},
}) : _reader = SummaryDataReader(resolutionBytes),
- _unitsInformativeBytes = unitsInformativeBytes {
+ _unitsInformativeData = unitsInformativeData {
_reader.offset = _reader.bytes.length - 4 * 4;
var baseResolutionOffset = _reader.readUInt32();
var librariesOffset = _reader.readUInt32();
@@ -69,7 +69,7 @@
libraryMap[uriStr] = LibraryReader._(
elementFactory: elementFactory,
reader: _reader,
- unitsInformativeBytes: _unitsInformativeBytes,
+ unitsInformativeData: _unitsInformativeData,
baseResolutionOffset: baseResolutionOffset,
referenceReader: referenceReader,
reference: reference,
@@ -412,11 +412,12 @@
class LibraryReader {
final LinkedElementFactory _elementFactory;
final SummaryDataReader _reader;
- final Map<Uri, Uint8List> _unitsInformativeBytes;
+ final Map<Uri, InformativeUnitData> _unitsInformativeData;
final int _baseResolutionOffset;
final _ReferenceReader _referenceReader;
final Reference _reference;
final int _offset;
+ final Map<int, MacroGenerationData> _macroDeclarations = {};
final Uint32List _classMembersLengths;
int _classMembersLengthsIndex = 0;
@@ -426,7 +427,7 @@
LibraryReader._({
required LinkedElementFactory elementFactory,
required SummaryDataReader reader,
- required Map<Uri, Uint8List> unitsInformativeBytes,
+ required Map<Uri, InformativeUnitData> unitsInformativeData,
required int baseResolutionOffset,
required _ReferenceReader referenceReader,
required Reference reference,
@@ -434,7 +435,7 @@
required Uint32List classMembersLengths,
}) : _elementFactory = elementFactory,
_reader = reader,
- _unitsInformativeBytes = unitsInformativeBytes,
+ _unitsInformativeData = unitsInformativeData,
_baseResolutionOffset = baseResolutionOffset,
_referenceReader = referenceReader,
_reference = reference,
@@ -493,7 +494,7 @@
_declareDartCoreDynamicNever();
InformativeDataApplier(_elementFactory).applyTo(
- _unitsInformativeBytes,
+ _unitsInformativeData,
libraryElement,
);
@@ -851,15 +852,16 @@
}
void _readMacro(Element element, HasMacroGenerationData hasMacro) {
- if (_reader.readBool()) {
- hasMacro.macro = MacroGenerationData(
- _reader.readUInt30(),
- _reader.readStringUtf8(),
- Uint8List(0),
- );
- InformativeDataApplier(_elementFactory).applyToDeclaration(
+ var id = _reader.readOptionalUInt30();
+ if (id != null) {
+ var data = _macroDeclarations[id]!;
+ hasMacro.macro = data;
+ InformativeDataApplier(
+ _elementFactory,
+ baseOffset: data.offset,
+ ).applyToDeclaration(
element,
- _reader.readUint8List(),
+ data.informative,
);
}
}
@@ -1235,6 +1237,7 @@
unitElement.isSynthetic = _reader.readBool();
unitElement.sourceContent = _reader.readOptionalStringUtf8();
+ _readUnitMacroGenerationDataList(unitElement);
_readClasses(unitElement, unitReference);
_readEnums(unitElement, unitReference);
_readExtensions(unitElement, unitReference);
@@ -1252,6 +1255,28 @@
return unitElement;
}
+ void _readUnitMacroGenerationDataList(
+ CompilationUnitElementImpl unitElement,
+ ) {
+ var length = _reader.readUInt30();
+ if (length == 0) {
+ return;
+ }
+
+ var dataList = List.generate(length, (index) {
+ return MacroGenerationData(
+ id: _reader.readUInt30(),
+ code: _reader.readStringUtf8(),
+ informative: _reader.readUint8List(),
+ classDeclarationIndex: _reader.readOptionalUInt30(),
+ );
+ });
+ unitElement.macroGenerationDataList = dataList;
+ for (var data in dataList) {
+ _macroDeclarations[data.id] = data;
+ }
+ }
+
static Variance? _decodeVariance(int index) {
var tag = TypeParameterVarianceTag.values[index];
switch (tag) {
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 4b67169..8a3993f 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -280,12 +280,7 @@
}
void _writeMacro(MacroGenerationData? macro) {
- _sink.writeBool(macro != null);
- if (macro != null) {
- _sink.writeUInt30(macro.id);
- _sink.writeStringUtf8(macro.code);
- _sink.writeUint8List(macro.informative);
- }
+ _sink.writeOptionalUInt30(macro?.id);
}
void _writeMethodElement(MethodElement element) {
@@ -454,6 +449,7 @@
_sink.writeBool(unitElement.isSynthetic);
_sink.writeOptionalStringUtf8(unitElement.sourceContent);
_resolutionSink._writeAnnotationList(unitElement.metadata);
+ _writeUnitElementMacroGenerationDataList(unitElement);
_writeList(unitElement.classes, _writeClassElement);
_writeList(unitElement.enums, _writeEnumElement);
_writeList(unitElement.extensions, _writeExtensionElement);
@@ -473,6 +469,18 @@
);
}
+ void _writeUnitElementMacroGenerationDataList(
+ CompilationUnitElementImpl unitElement,
+ ) {
+ var dataList = unitElement.macroGenerationDataList ?? [];
+ _writeList<MacroGenerationData>(dataList, (data) {
+ _sink.writeUInt30(data.id);
+ _sink.writeStringUtf8(data.code);
+ _sink.writeUint8List(data.informative);
+ _sink.writeOptionalUInt30(data.classDeclarationIndex);
+ });
+ }
+
static TypeParameterVarianceTag _encodeVariance(
TypeParameterElementImpl element) {
if (element.isLegacyCovariant) {
diff --git a/pkg/analyzer/lib/src/summary2/informative_data.dart b/pkg/analyzer/lib/src/summary2/informative_data.dart
index f14a0f2..f513e75 100644
--- a/pkg/analyzer/lib/src/summary2/informative_data.dart
+++ b/pkg/analyzer/lib/src/summary2/informative_data.dart
@@ -41,10 +41,15 @@
/// offsets are different from `nameOffset` for example, which are applied
/// directly after creating corresponding elements during a library loading.
class ApplyConstantOffsets {
+ final int _baseOffset;
Uint32List? _offsets;
void Function(_OffsetsApplier)? _function;
- ApplyConstantOffsets(this._offsets, this._function);
+ ApplyConstantOffsets(
+ this._offsets,
+ this._function, {
+ int baseOffset = 0,
+ }) : _baseOffset = baseOffset;
void perform() {
var offsets = _offsets;
@@ -52,6 +57,7 @@
if (offsets != null && function != null) {
var applier = _OffsetsApplier(
_SafeListIterator(offsets),
+ baseOffset: _baseOffset,
);
function.call(applier);
// Clear the references to possible closure data.
@@ -64,11 +70,15 @@
class InformativeDataApplier {
final LinkedElementFactory _elementFactory;
+ final int _baseOffset;
- InformativeDataApplier(this._elementFactory);
+ InformativeDataApplier(
+ this._elementFactory, {
+ int baseOffset = 0,
+ }) : _baseOffset = baseOffset;
void applyTo(
- Map<Uri, Uint8List> unitsInformativeBytes,
+ Map<Uri, InformativeUnitData> unitsInformativeData,
LibraryElementImpl libraryElement,
) {
if (_elementFactory.isApplyingInformativeData) {
@@ -80,9 +90,9 @@
for (var i = 0; i < unitElements.length; i++) {
var unitElement = unitElements[i] as CompilationUnitElementImpl;
var unitUri = unitElement.source.uri;
- var unitInfoBytes = unitsInformativeBytes[unitUri];
- if (unitInfoBytes != null) {
- var unitReader = SummaryDataReader(unitInfoBytes);
+ var unitInfoData = unitsInformativeData[unitUri];
+ if (unitInfoData != null) {
+ var unitReader = SummaryDataReader(unitInfoData.bytes);
var unitInfo = _InfoUnit(unitReader);
if (i == 0) {
@@ -91,6 +101,7 @@
unitElement.setCodeRange(unitInfo.codeOffset, unitInfo.codeLength);
unitElement.lineInfo = LineInfo(unitInfo.lineStarts);
+ _setUnitMacroGeneratedContent(unitElement, unitInfoData, unitInfo);
_applyToAccessors(unitElement.accessors, unitInfo.accessors);
@@ -269,7 +280,7 @@
element as ConstructorElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.periodOffset = info.periodOffset;
- element.nameOffset = info.nameOffset;
+ element.nameOffset = _baseOffset + info.nameOffset;
element.nameEnd = info.nameEnd;
element.documentationComment = info.documentationComment;
_applyToFormalParameters(
@@ -390,7 +401,7 @@
(element, info) {
element as ParameterElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
- element.nameOffset = info.nameOffset;
+ element.nameOffset = _baseOffset + info.nameOffset;
_applyToTypeParameters(element.typeParameters, info.typeParameters);
_applyToFormalParameters(element.parameters, info.parameters);
},
@@ -529,7 +540,7 @@
void _applyToMethod(MethodElement element, _InfoMethodDeclaration info) {
element as MethodElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
- element.nameOffset = info.nameOffset;
+ element.nameOffset = _baseOffset + info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
@@ -548,6 +559,7 @@
applier.applyToTypeParameters(element.typeParameters);
applier.applyToFormalParameters(element.parameters);
},
+ baseOffset: _baseOffset,
);
}
@@ -595,7 +607,7 @@
) {
element as PropertyAccessorElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
- element.nameOffset = info.nameOffset;
+ element.nameOffset = _baseOffset + info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToFormalParameters(
element.parameters_unresolved,
@@ -611,6 +623,7 @@
applier.applyToTypeParameters(element.typeParameters);
applier.applyToFormalParameters(element.parameters);
},
+ baseOffset: _baseOffset,
);
}
}
@@ -649,6 +662,36 @@
);
}
+ void _setUnitMacroGeneratedContent(
+ CompilationUnitElementImpl unitElement,
+ InformativeUnitData unitInfoData,
+ _InfoUnit unitInfo,
+ ) {
+ var macroGenerationDataList = unitElement.macroGenerationDataList;
+ if (macroGenerationDataList != null) {
+ const classMemberCodePrefix = '\n';
+ const classMemberCodeSuffix = '\n';
+ var generatedContent = unitInfoData.content;
+ var shift = 0;
+ for (var data in macroGenerationDataList) {
+ var classIndex = data.classDeclarationIndex;
+ if (classIndex != null) {
+ var targetClass = unitInfo.classDeclarations[classIndex];
+ var code = classMemberCodePrefix + data.code + classMemberCodeSuffix;
+ var insertOffset = shift + targetClass.rightBracketOffset;
+ data.offset = insertOffset + classMemberCodePrefix.length;
+ generatedContent = generatedContent.substring(0, insertOffset) +
+ code +
+ generatedContent.substring(insertOffset);
+ shift += code.length;
+ } else {
+ throw UnimplementedError();
+ }
+ }
+ unitElement.macroGeneratedContent = generatedContent;
+ }
+ }
+
void _setupApplyConstantOffsetsForTypeAlias(
TypeAliasElementImpl element,
Uint32List constantOffsets, {
@@ -684,6 +727,20 @@
}
}
+/// Informative data about a source file.
+class InformativeUnitData {
+ /// The content of the file.
+ final String content;
+
+ /// Informative data derived from the [content], such as offsets.
+ final Uint8List bytes;
+
+ InformativeUnitData({
+ required this.content,
+ required this.bytes,
+ });
+}
+
enum _DeclarationKind {
constructorDeclaration,
methodDeclaration,
@@ -693,6 +750,7 @@
final int codeOffset;
final int codeLength;
final int nameOffset;
+ final int rightBracketOffset;
final String? documentationComment;
final List<_InfoTypeParameter> typeParameters;
final List<_InfoConstructorDeclaration> constructors;
@@ -707,6 +765,7 @@
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30() - nameOffsetDelta,
+ rightBracketOffset: reader.readUInt30(),
documentationComment: reader.readStringUtf8().nullIfEmpty,
typeParameters: reader.readTypedList(
() => _InfoTypeParameter(reader),
@@ -731,6 +790,7 @@
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
+ required this.rightBracketOffset,
required this.documentationComment,
required this.typeParameters,
required this.constructors,
@@ -1194,6 +1254,7 @@
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
+ sink.writeUInt30(node.rightBracket.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeConstructors(node.members);
@@ -1239,6 +1300,7 @@
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(1 + (node.name?.offset ?? -1));
+ sink.writeUInt30(node.rightBracket.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeConstructors(node.members);
@@ -1328,6 +1390,7 @@
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
+ sink.writeUInt30(node.rightBracket.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeConstructors(node.members);
@@ -1738,8 +1801,12 @@
class _OffsetsApplier extends _OffsetsAstVisitor {
final _SafeListIterator<int> _iterator;
+ final int _baseOffset;
- _OffsetsApplier(this._iterator);
+ _OffsetsApplier(
+ this._iterator, {
+ int baseOffset = 0,
+ }) : _baseOffset = baseOffset;
void applyToConstantInitializer(Element element) {
if (element is ConstVariableElement) {
@@ -1793,7 +1860,7 @@
void handleToken(Token token) {
var offset = _iterator.take();
if (offset != null) {
- token.offset = offset;
+ token.offset = _baseOffset + offset;
}
}
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index c1eb205..661ba7d 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -231,13 +231,15 @@
TypesBuilder(linker).build(nodesToBuildType);
}
- var collector = macro.DeclarationCollector();
for (var linkingUnit in units) {
+ var classDeclarationIndex = -1;
for (var declaration in linkingUnit.node.declarations) {
if (declaration is ast.ClassDeclarationImpl) {
+ classDeclarationIndex++;
var members = declaration.members.toList();
var classBuilder = macro.ClassDeclarationBuilderImpl(
- collector,
+ linkingUnit,
+ classDeclarationIndex,
declaration,
);
if (hasMacroAnnotation(declaration, 'autoConstructor')) {
@@ -283,7 +285,10 @@
}
}
}
- collector.updateElements();
+
+ for (var linkingUnit in units) {
+ linkingUnit.macroGeneratedContent.finish();
+ }
}
void storeExportScope() {
@@ -413,6 +418,8 @@
final Reference reference;
final ast.CompilationUnitImpl node;
final CompilationUnitElementImpl element;
+ late final macro.MacroGeneratedContent macroGeneratedContent =
+ macro.MacroGeneratedContent(this);
LinkingUnit({
required this.input,
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index ad23ac1..a79005d 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/src/dart/ast/ast_factory.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
import 'package:analyzer/src/generated/element_resolver.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -725,7 +726,9 @@
_visitor = ResolverVisitor(
inheritance, _definingLibrary, source, _typeProvider, _listener,
- featureSet: FeatureSet.forTesting());
+ featureSet: FeatureSet.forTesting(),
+ flowAnalysisHelper:
+ FlowAnalysisHelper(context.typeSystemLegacy, false, false));
_resolver = _visitor.elementResolver;
}
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index 696241c..18d6b1a 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
+import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
import 'package:analyzer/src/generated/resolver.dart' show ResolverVisitor;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/static_type_analyzer.dart';
@@ -514,7 +515,9 @@
_visitor = ResolverVisitor(
inheritance, _definingLibrary, source, _typeProvider, _listener,
- featureSet: featureSet);
+ featureSet: featureSet,
+ flowAnalysisHelper:
+ FlowAnalysisHelper(context.typeSystemLegacy, false, false));
_analyzer = _visitor.typeAnalyzer;
}
diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
index 9a41bd0..6119dbf 100644
--- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
@@ -792,6 +792,21 @@
]));
}
+ void test_visitExportDirective_configurations() {
+ var unit = parseString(content: r'''
+export 'foo.dart'
+ if (dart.library.io) 'foo_io.dart'
+ if (dart.library.html) 'foo_html.dart';
+''').unit;
+ var directive = unit.directives[0] as ExportDirective;
+ _assertSource(
+ "export 'foo.dart'"
+ " if (dart.library.io) 'foo_io.dart'"
+ " if (dart.library.html) 'foo_html.dart';",
+ directive,
+ );
+ }
+
void test_visitExportDirective_minimal() {
_assertSource(
"export 'a.dart';", AstTestFactory.exportDirective2("a.dart"));
@@ -1788,6 +1803,21 @@
]));
}
+ void test_visitImportDirective_configurations() {
+ var unit = parseString(content: r'''
+import 'foo.dart'
+ if (dart.library.io) 'foo_io.dart'
+ if (dart.library.html) 'foo_html.dart';
+''').unit;
+ var directive = unit.directives[0] as ImportDirective;
+ _assertSource(
+ "import 'foo.dart'"
+ " if (dart.library.io) 'foo_io.dart'"
+ " if (dart.library.html) 'foo_html.dart';",
+ directive,
+ );
+ }
+
void test_visitImportDirective_deferred() {
_assertSource("import 'a.dart' deferred as p;",
AstTestFactory.importDirective2("a.dart", true, "p"));
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index f8366c5..a4ad397 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -361,7 +361,6 @@
});
_withIndent(() {
- _writeMacro(e);
_writeDocumentation(e);
_writeMetadata(e);
_writeCodeRange(e);
@@ -530,19 +529,6 @@
buffer.writeln(line);
}
- void _writeMacro(Element e) {
- if (e is HasMacroGenerationData) {
- var macro = (e as HasMacroGenerationData).macro;
- if (macro != null) {
- _writelnWithIndent('macro');
- _withIndent(() {
- _writelnWithIndent('id: ${macro.id}');
- _writelnMultiLineWithIndent('code: ${macro.code}');
- });
- }
- }
- }
-
void _writeMetadata(Element element) {
var annotations = element.metadata;
if (annotations.isNotEmpty) {
@@ -568,7 +554,6 @@
});
_withIndent(() {
- _writeMacro(e);
_writeDocumentation(e);
_writeMetadata(e);
_writeCodeRange(e);
@@ -711,7 +696,6 @@
});
_withIndent(() {
- _writeMacro(e);
_writeDocumentation(e);
_writeMetadata(e);
_writeCodeRange(e);
@@ -875,6 +859,7 @@
}
void _writeUnitElement(CompilationUnitElement e) {
+ e as CompilationUnitElementImpl;
_writeElements('classes', e.classes, _writeClassElement);
_writeElements('enums', e.enums, _writeClassElement);
_writeElements('extensions', e.extensions, _writeExtensionElement);
@@ -891,6 +876,12 @@
_writePropertyAccessorElement,
);
_writeElements('functions', e.functions, _writeFunctionElement);
+
+ var macroGeneratedContent = e.macroGeneratedContent;
+ if (macroGeneratedContent != null) {
+ _writelnWithIndent('macroGeneratedContent');
+ buffer.write(macroGeneratedContent);
+ }
}
void _writeUri(Source? source) {
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
index 3a95b46..c18ab0cf 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
@@ -59,11 +59,9 @@
var inputLibraries = <LinkInputLibrary>[];
for (var sdkLibrary in sdk.sdkLibraries) {
var source = sourceFactory.resolveUri(null, sdkLibrary.shortName)!;
- var text = getFile(source.fullName).readAsStringSync();
- var unit = parseText(text, featureSet);
var inputUnits = <LinkInputUnit>[];
- _addLibraryUnits(source, unit, inputUnits, featureSet);
+ _addLibraryUnits(source, inputUnits, featureSet);
inputLibraries.add(
LinkInputLibrary(
source: source,
@@ -99,11 +97,17 @@
var inputLibraries = <LinkInputLibrary>[];
_addNonDartLibraries({}, inputLibraries, source);
- var unitsInformativeBytes = <Uri, Uint8List>{};
+ var unitsInformativeData = <Uri, InformativeUnitData>{};
for (var inputLibrary in inputLibraries) {
for (var inputUnit in inputLibrary.units) {
- var informativeBytes = writeUnitInformative(inputUnit.unit);
- unitsInformativeBytes[inputUnit.uri] = informativeBytes;
+ var content = inputUnit.sourceContent;
+ if (content != null) {
+ var informativeBytes = writeUnitInformative(inputUnit.unit);
+ unitsInformativeData[inputUnit.uri] = InformativeUnitData(
+ content: content,
+ bytes: informativeBytes,
+ );
+ }
}
}
@@ -123,7 +127,7 @@
elementFactory.addBundle(
BundleReader(
elementFactory: elementFactory,
- unitsInformativeBytes: {},
+ unitsInformativeData: {},
resolutionBytes: sdkBundle.resolutionBytes,
),
);
@@ -137,7 +141,7 @@
elementFactory.addBundle(
BundleReader(
elementFactory: elementFactory,
- unitsInformativeBytes: unitsInformativeBytes,
+ unitsInformativeData: unitsInformativeData,
resolutionBytes: linkResult.resolutionBytes,
),
);
@@ -152,14 +156,16 @@
void _addLibraryUnits(
Source definingSource,
- CompilationUnit definingUnit,
List<LinkInputUnit> units,
FeatureSet featureSet,
) {
+ var definingContent = _readSafely(definingSource.fullName);
+ var definingUnit = parseText(definingContent, featureSet);
units.add(
LinkInputUnit(
partDirectiveIndex: null,
source: definingSource,
+ sourceContent: definingContent,
isSynthetic: false,
unit: definingUnit,
),
@@ -184,6 +190,7 @@
partDirectiveIndex: partDirectiveIndex,
partUriStr: relativeUriStr,
source: partSource,
+ sourceContent: text,
isSynthetic: false,
unit: unit,
),
@@ -208,7 +215,7 @@
var unit = parseText(text, featureSet);
var units = <LinkInputUnit>[];
- _addLibraryUnits(source, unit, units, featureSet);
+ _addLibraryUnits(source, units, featureSet);
libraries.add(
LinkInputLibrary(
source: source,
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 9adf69a..74fe439 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -21282,37 +21282,31 @@
final b @88
type: int?
constructors
- @0
- macro
- id: 0
- code: A({required this.a, this.b});
+ @92
parameters
- requiredName final this.a @17
+ requiredName final this.a @109
type: int
- optionalNamed final this.b @25
+ optionalNamed final this.b @117
type: int?
accessors
synthetic get a @-1
returnType: int
synthetic get b @-1
returnType: int?
+ macroGeneratedContent
+import 'macro_annotations.dart';
+@autoConstructor
+class A {
+ final int a;
+ final int? b;
+
+A({required this.a, this.b});
+}
''');
}
test_macro_hashCode() async {
addLibrarySource('/macro_annotations.dart', r'''
-library analyzer.macro.annotations;
-const hashCode = 0;
-''');
- var library = await checkLibrary(r'''
-import 'macro_annotations.dart';
-@hashCode
-class A {
- final int a;
- final int b;
-}
-''');
- checkElementText(library, r'''
library
imports
macro_annotations.dart
@@ -21341,10 +21335,7 @@
returnType: int
synthetic get b @-1
returnType: int
- get hashCode @18
- macro
- id: 0
- code: @override\nint get hashCode => a.hashCode ^ b.hashCode;
+ get hashCode @102
metadata
Annotation
atSign: @ @0
@@ -21354,6 +21345,16 @@
staticType: null
token: override @1
returnType: int
+ macroGeneratedContent
+import 'macro_annotations.dart';
+@hashCode
+class A {
+ final int a;
+ final int b;
+
+@override
+int get hashCode => a.hashCode ^ b.hashCode;
+}
''');
}
@@ -21409,19 +21410,30 @@
accessors
synthetic get b @-1
returnType: int
- get hashCode @18
- macro
- id: 0
- code: @override\nint get hashCode => b.hashCode ^ a.hashCode;
+ get hashCode @126
metadata
Annotation
- atSign: @ @0
+ atSign: @ @108
element: dart:core::@getter::override
name: SimpleIdentifier
staticElement: dart:core::@getter::override
staticType: null
- token: override @1
+ token: override @109
returnType: int
+ macroGeneratedContent
+import 'macro_annotations.dart';
+
+class A {
+ final int a;
+}
+
+@hashCode
+class B extends A {
+ final int b;
+
+@override
+int get hashCode => b.hashCode ^ a.hashCode;
+}
''');
}
@@ -21467,19 +21479,26 @@
requiredPositional __f @-1
type: int
returnType: void
- get f @8
- macro
- id: 0
- code: int get f => _f;
+ get f @80
returnType: int
- set f @4
- macro
- id: 1
- code: set f(int val) {\n print('Setting f to ${val}');\n _f = val;\n}
+ set f @94
parameters
- requiredPositional val @10
+ requiredPositional val @100
type: int
returnType: void
+ macroGeneratedContent
+import 'macro_annotations.dart';
+class A {
+ @observable
+ int _f = 0;
+
+int get f => _f;
+
+set f(int val) {
+ print('Setting f to ${val}');
+ _f = val;
+}
+}
''');
}
@@ -21528,19 +21547,26 @@
requiredPositional __f @-1
type: T
returnType: void
- get f @6
- macro
- id: 0
- code: T get f => _f;
+ get f @75
returnType: T
- set f @4
- macro
- id: 1
- code: set f(T val) {\n print('Setting f to ${val}');\n _f = val;\n}
+ set f @89
parameters
- requiredPositional val @8
+ requiredPositional val @93
type: T
returnType: void
+ macroGeneratedContent
+import 'macro_annotations.dart';
+class A<T> {
+ @observable
+ T _f;
+
+T get f => _f;
+
+set f(T val) {
+ print('Setting f to ${val}');
+ _f = val;
+}
+}
''');
}
@@ -21585,19 +21611,26 @@
synthetic get b @-1
returnType: int
methods
- toString @17
- macro
- id: 0
- code: @override\nString toString() => 'A(a: $a, b: $b)';
+ toString @101
metadata
Annotation
- atSign: @ @0
+ atSign: @ @84
element: dart:core::@getter::override
name: SimpleIdentifier
staticElement: dart:core::@getter::override
staticType: null
- token: override @1
+ token: override @85
returnType: String
+ macroGeneratedContent
+import 'macro_annotations.dart';
+@toString
+class A {
+ final int a;
+ final int b;
+
+@override
+String toString() => 'A(a: $a, b: $b)';
+}
''');
}
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 3d568e4..dbd9c55 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -12928,9 +12928,6 @@
_A nullable expression can't be used in a yield-each statement._
-_An expression whose value can be 'null' must be null-checked before it can be
-dereferenced._
-
_The function can't be unconditionally invoked because it can be 'null'._
_The method '{0}' can't be unconditionally invoked because the receiver can be
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 64a6537..6f2a3bd 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -570,10 +570,6 @@
FieldEntity get pragmaClassOptionsField;
bool isCreateInvocationMirrorHelper(MemberEntity member);
-
- ClassEntity get metaNoInlineClass;
-
- ClassEntity get metaTryInlineClass;
}
abstract class JCommonElements implements CommonElements {
@@ -2112,38 +2108,6 @@
_env.lookupLibrary(Uris.dart__js_embedded_names, required: true),
'JsBuiltin');
- bool _metaAnnotationChecked = false;
- ClassEntity _metaNoInlineClass;
- ClassEntity _metaTryInlineClass;
-
- void _ensureMetaAnnotations() {
- if (!_metaAnnotationChecked) {
- _metaAnnotationChecked = true;
- LibraryEntity library = _env.lookupLibrary(Uris.package_meta_dart2js);
- if (library != null) {
- _metaNoInlineClass = _env.lookupClass(library, '_NoInline');
- _metaTryInlineClass = _env.lookupClass(library, '_TryInline');
- if (_metaNoInlineClass == null || _metaTryInlineClass == null) {
- // This is not the package you're looking for.
- _metaNoInlineClass = null;
- _metaTryInlineClass = null;
- }
- }
- }
- }
-
- @override
- ClassEntity get metaNoInlineClass {
- _ensureMetaAnnotations();
- return _metaNoInlineClass;
- }
-
- @override
- ClassEntity get metaTryInlineClass {
- _ensureMetaAnnotations();
- return _metaTryInlineClass;
- }
-
@override
bool isForeign(MemberEntity element) => element.library == foreignLibrary;
diff --git a/pkg/meta/CHANGELOG.md b/pkg/meta/CHANGELOG.md
index 81fd808..ea032dd 100644
--- a/pkg/meta/CHANGELOG.md
+++ b/pkg/meta/CHANGELOG.md
@@ -1,6 +1,8 @@
## master
* Add `@UseResult.unless`.
+* The mechanism behind `noInline` and `tryInline` from `dart2js.dart` has been
+ changed. This should not affect the use of these annotations in practice.
## 1.7.0
diff --git a/pkg/meta/lib/dart2js.dart b/pkg/meta/lib/dart2js.dart
index 483faeb..29944c8 100644
--- a/pkg/meta/lib/dart2js.dart
+++ b/pkg/meta/lib/dart2js.dart
@@ -17,7 +17,7 @@
///
/// @dart2js.noInline
/// String text() => 'A String of unusual size';
-const _NoInline noInline = _NoInline();
+const noInline = pragma('dart2js:noInline');
/// An annotation for methods to request that dart2js always inline the
/// method.
@@ -34,12 +34,4 @@
/// }
///
/// It is an error to use both `@noInline` and `@tryInline` on the same method.
-const _TryInline tryInline = _TryInline();
-
-class _NoInline {
- const _NoInline();
-}
-
-class _TryInline {
- const _TryInline();
-}
+const tryInline = pragma('dart2js:tryInline');
diff --git a/pkg/meta/pubspec.yaml b/pkg/meta/pubspec.yaml
index b7e00f8..d4d36da 100644
--- a/pkg/meta/pubspec.yaml
+++ b/pkg/meta/pubspec.yaml
@@ -1,6 +1,6 @@
name: meta
# Note, because version `2.0.0` was mistakenly released, the next major version must be `3.x.y`.
-version: 1.7.0
+version: 1.7.1-dev
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/meta
description: >-
Annotations that developers can use to express the intentions that otherwise
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index fb33534..02f2592 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -88,7 +88,18 @@
return Type::Double();
} else if (instance.IsType() || instance.IsFunctionType()) {
return Type::DartTypeType();
+ } else if (IsArrayClassId(instance.GetClassId())) {
+ const auto& cls = Class::Handle(
+ zone, thread->isolate_group()->object_store()->list_class());
+ const auto& type_arguments =
+ TypeArguments::Handle(zone, instance.GetTypeArguments());
+ const auto& type = Type::Handle(
+ zone,
+ Type::New(cls, type_arguments, Nullability::kNonNullable, Heap::kNew));
+ type.SetIsFinalized();
+ return type.Canonicalize(thread, nullptr);
}
+
return instance.GetType(Heap::kNew);
}
@@ -101,14 +112,18 @@
if (left_cid != right_cid) {
if (IsIntegerClassId(left_cid)) {
return IsIntegerClassId(right_cid);
- }
- if (IsStringClassId(left_cid)) {
+ } else if (IsStringClassId(left_cid)) {
return IsStringClassId(right_cid);
- }
- if (IsTypeClassId(left_cid)) {
+ } else if (IsTypeClassId(left_cid)) {
return IsTypeClassId(right_cid);
+ } else if (IsArrayClassId(left_cid)) {
+ if (!IsArrayClassId(right_cid)) {
+ return false;
+ }
+ // Still need to check type arguments.
+ } else {
+ return false;
}
- return false;
}
if (left_cid == kClosureCid) {
diff --git a/runtime/tests/vm/dart/have_same_runtime_type_test.dart b/runtime/tests/vm/dart/have_same_runtime_type_test.dart
new file mode 100644
index 0000000..b7ade2a
--- /dev/null
+++ b/runtime/tests/vm/dart/have_same_runtime_type_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2021, 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.
+
+// Test for corner cases of 'a.runtimeType == b.runtimeType' pattern
+// which is recognized and optimized in AOT mode.
+
+import "package:expect/expect.dart";
+
+@pragma('vm:never-inline')
+Object getType(Object obj) => obj.runtimeType;
+
+@pragma('vm:never-inline')
+void test(bool expected, Object a, Object b) {
+ bool result1 = getType(a) == getType(b);
+ bool result2 = a.runtimeType == b.runtimeType;
+ Expect.equals(expected, result1);
+ Expect.equals(expected, result2);
+}
+
+typedef Func = void Function();
+
+void main() {
+ test(true, 0x7fffffffffffffff, int.parse('42'));
+ test(true, 'hi', String.fromCharCode(1114111));
+ test(false, 'hi', 1);
+ test(true, List, Func);
+ test(true, <int>[1], const <int>[2]);
+ test(true, const <String>[], List<String>.filled(1, ''));
+ test(true, <String>[]..add('hi'), List<String>.filled(2, ''));
+ test(false, <int>[], <String>[]);
+}
diff --git a/runtime/tests/vm/dart_2/have_same_runtime_type_test.dart b/runtime/tests/vm/dart_2/have_same_runtime_type_test.dart
new file mode 100644
index 0000000..119e40f
--- /dev/null
+++ b/runtime/tests/vm/dart_2/have_same_runtime_type_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2021, 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.
+
+// Test for corner cases of 'a.runtimeType == b.runtimeType' pattern
+// which is recognized and optimized in AOT mode.
+
+// @dart = 2.9
+
+import "package:expect/expect.dart";
+
+@pragma('vm:never-inline')
+Object getType(Object obj) => obj.runtimeType;
+
+@pragma('vm:never-inline')
+void test(bool expected, Object a, Object b) {
+ bool result1 = getType(a) == getType(b);
+ bool result2 = a.runtimeType == b.runtimeType;
+ Expect.equals(expected, result1);
+ Expect.equals(expected, result2);
+}
+
+typedef Func = void Function();
+
+void main() {
+ test(true, 0x7fffffffffffffff, int.parse('42'));
+ test(true, 'hi', String.fromCharCode(1114111));
+ test(false, 'hi', 1);
+ test(true, List, Func);
+ test(true, <int>[1], const <int>[2]);
+ test(true, const <String>[], List<String>.filled(1, ''));
+ test(true, <String>[]..add('hi'), List<String>.filled(2, ''));
+ test(false, <int>[], <String>[]);
+}
diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h
index ac06355..5ca709a 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -78,7 +78,6 @@
V(Mint) \
V(Double) \
V(Bool) \
- V(GrowableObjectArray) \
V(Float32x4) \
V(Int32x4) \
V(Float64x2) \
@@ -108,10 +107,14 @@
// TODO(http://dartbug.com/45908): Add ImmutableLinkedHashSet.
#define CLASS_LIST_SETS(V) V(LinkedHashSet)
-#define CLASS_LIST_ARRAYS(V) \
+#define CLASS_LIST_FIXED_LENGTH_ARRAYS(V) \
V(Array) \
V(ImmutableArray)
+#define CLASS_LIST_ARRAYS(V) \
+ CLASS_LIST_FIXED_LENGTH_ARRAYS(V) \
+ V(GrowableObjectArray)
+
#define CLASS_LIST_STRINGS(V) \
V(String) \
V(OneByteString) \
@@ -182,6 +185,7 @@
V(LinkedHashMap) \
V(LinkedHashSet) \
V(Array) \
+ V(GrowableObjectArray) \
V(String)
#define CLASS_LIST_NO_OBJECT(V) \
@@ -327,11 +331,15 @@
index == kExternalTwoByteStringCid);
}
+inline bool IsArrayClassId(intptr_t index) {
+ COMPILE_ASSERT(kImmutableArrayCid == kArrayCid + 1);
+ COMPILE_ASSERT(kGrowableObjectArrayCid == kArrayCid + 2);
+ return (index >= kArrayCid && index <= kGrowableObjectArrayCid);
+}
+
inline bool IsBuiltinListClassId(intptr_t index) {
// Make sure this function is updated when new builtin List types are added.
- COMPILE_ASSERT(kImmutableArrayCid == kArrayCid + 1);
- return ((index >= kArrayCid && index <= kImmutableArrayCid) ||
- (index == kGrowableObjectArrayCid) || IsTypedDataBaseClassId(index) ||
+ return (IsArrayClassId(index) || IsTypedDataBaseClassId(index) ||
(index == kByteBufferCid));
}
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm.cc b/runtime/vm/compiler/asm_intrinsifier_arm.cc
index 375c454..e7f2ee1 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm.cc
@@ -1198,6 +1198,14 @@
kIfNotInRange, target);
}
+static void JumpIfNotList(Assembler* assembler,
+ Register cid,
+ Register tmp,
+ Label* target) {
+ RangeCheck(assembler, cid, tmp, kArrayCid, kGrowableObjectArrayCid,
+ kIfNotInRange, target);
+}
+
static void JumpIfType(Assembler* assembler,
Register cid,
Register tmp,
@@ -1284,7 +1292,7 @@
Register scratch,
bool testing_instance_cids) {
Label different_cids, equal_cids_but_generic, not_integer,
- not_integer_or_string;
+ not_integer_or_string, not_integer_or_string_or_list;
// Check if left hand side is a closure. Closures are handled in the runtime.
__ CompareImmediate(cid1, kClosureCid);
@@ -1310,7 +1318,8 @@
__ b(equal);
// Class ids are different. Check if we are comparing two string types (with
- // different representations) or two integer types or two type types.
+ // different representations), two integer types, two list types or two type
+ // types.
__ Bind(&different_cids);
__ CompareImmediate(cid1, kNumPredefinedCids);
__ b(not_equal, HI);
@@ -1335,9 +1344,20 @@
if (testing_instance_cids) {
__ Bind(¬_integer_or_string);
+ // Check if both are List types.
+ JumpIfNotList(assembler, cid1, scratch, ¬_integer_or_string_or_list);
+
+ // First type is a List. Check if the second is a List too.
+ JumpIfNotList(assembler, cid2, scratch, not_equal);
+ ASSERT(compiler::target::Array::type_arguments_offset() ==
+ compiler::target::GrowableObjectArray::type_arguments_offset());
+ __ LoadImmediate(scratch, compiler::target::Array::type_arguments_offset());
+ __ b(&equal_cids_but_generic);
+
+ __ Bind(¬_integer_or_string_or_list);
// Check if the first type is a Type. If it is not then types are not
// equivalent because they have different class ids and they are not String
- // or integer or Type.
+ // or integer or List or Type.
JumpIfNotType(assembler, cid1, scratch, not_equal);
// First type is a Type. Check if the second is a Type too.
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
index 36cb205..1e0134a 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -1342,6 +1342,14 @@
kIfNotInRange, target);
}
+static void JumpIfNotList(Assembler* assembler,
+ Register cid,
+ Register tmp,
+ Label* target) {
+ RangeCheck(assembler, cid, tmp, kArrayCid, kGrowableObjectArrayCid,
+ kIfNotInRange, target);
+}
+
static void JumpIfType(Assembler* assembler,
Register cid,
Register tmp,
@@ -1432,7 +1440,7 @@
Register scratch,
bool testing_instance_cids) {
Label different_cids, equal_cids_but_generic, not_integer,
- not_integer_or_string;
+ not_integer_or_string, not_integer_or_string_or_list;
// Check if left hand side is a closure. Closures are handled in the runtime.
__ CompareImmediate(cid1, kClosureCid);
@@ -1458,7 +1466,8 @@
__ b(equal);
// Class ids are different. Check if we are comparing two string types (with
- // different representations) or two integer types or two type types.
+ // different representations), two integer types, two list types or two type
+ // types.
__ Bind(&different_cids);
__ CompareImmediate(cid1, kNumPredefinedCids);
__ b(not_equal, HI);
@@ -1483,9 +1492,20 @@
if (testing_instance_cids) {
__ Bind(¬_integer_or_string);
+ // Check if both are List types.
+ JumpIfNotList(assembler, cid1, scratch, ¬_integer_or_string_or_list);
+
+ // First type is a List. Check if the second is a List too.
+ JumpIfNotList(assembler, cid2, scratch, not_equal);
+ ASSERT(compiler::target::Array::type_arguments_offset() ==
+ compiler::target::GrowableObjectArray::type_arguments_offset());
+ __ LoadImmediate(scratch, compiler::target::Array::type_arguments_offset());
+ __ b(&equal_cids_but_generic);
+
+ __ Bind(¬_integer_or_string_or_list);
// Check if the first type is a Type. If it is not then types are not
// equivalent because they have different class ids and they are not String
- // or integer or Type.
+ // or integer or List or Type.
JumpIfNotType(assembler, cid1, scratch, not_equal);
// First type is a Type. Check if the second is a Type too.
diff --git a/runtime/vm/compiler/asm_intrinsifier_ia32.cc b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
index a17f7a8..a6f1c9d 100644
--- a/runtime/vm/compiler/asm_intrinsifier_ia32.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
@@ -1281,6 +1281,11 @@
kIfNotInRange, target);
}
+static void JumpIfNotList(Assembler* assembler, Register cid, Label* target) {
+ RangeCheck(assembler, cid, kArrayCid, kGrowableObjectArrayCid, kIfNotInRange,
+ target);
+}
+
static void JumpIfType(Assembler* assembler, Register cid, Label* target) {
RangeCheck(assembler, cid, kTypeCid, kFunctionTypeCid, kIfInRange, target);
}
@@ -1370,7 +1375,7 @@
Register scratch,
bool testing_instance_cids) {
Label different_cids, equal_cids_but_generic, not_integer,
- not_integer_or_string;
+ not_integer_or_string, not_integer_or_string_or_list;
// Check if left hand side is a closure. Closures are handled in the runtime.
__ cmpl(cid1, Immediate(kClosureCid));
@@ -1392,11 +1397,12 @@
scratch,
target::Class::host_type_arguments_field_offset_in_words_offset()));
__ cmpl(scratch, Immediate(target::Class::kNoTypeArguments));
- __ j(NOT_EQUAL, &equal_cids_but_generic, Assembler::kNearJump);
+ __ j(NOT_EQUAL, &equal_cids_but_generic);
__ jmp(equal);
// Class ids are different. Check if we are comparing two string types (with
- // different representations) or two integer types or two type types.
+ // different representations), two integer types, two list types or two type
+ // types.
__ Bind(&different_cids);
__ cmpl(cid1, Immediate(kNumPredefinedCids));
__ j(ABOVE_EQUAL, not_equal);
@@ -1406,25 +1412,42 @@
JumpIfNotInteger(assembler, scratch, ¬_integer);
// First type is an integer. Check if the second is an integer too.
- JumpIfInteger(assembler, cid2, equal);
+ __ movl(scratch, cid2);
+ JumpIfInteger(assembler, scratch, equal);
// Integer types are only equivalent to other integer types.
__ jmp(not_equal);
__ Bind(¬_integer);
// Check if both are String types.
- JumpIfNotString(assembler, cid1,
+ __ movl(scratch, cid1);
+ JumpIfNotString(assembler, scratch,
testing_instance_cids ? ¬_integer_or_string : not_equal);
// First type is a String. Check if the second is a String too.
- JumpIfString(assembler, cid2, equal);
+ __ movl(scratch, cid2);
+ JumpIfString(assembler, scratch, equal);
// String types are only equivalent to other String types.
__ jmp(not_equal);
if (testing_instance_cids) {
__ Bind(¬_integer_or_string);
+ // Check if both are List types.
+ __ movl(scratch, cid1);
+ JumpIfNotList(assembler, scratch, ¬_integer_or_string_or_list);
+
+ // First type is a List. Check if the second is a List too.
+ __ movl(scratch, cid2);
+ JumpIfNotList(assembler, scratch, not_equal);
+ ASSERT(compiler::target::Array::type_arguments_offset() ==
+ compiler::target::GrowableObjectArray::type_arguments_offset());
+ __ movl(scratch,
+ Immediate(compiler::target::Array::type_arguments_offset()));
+ __ jmp(&equal_cids_but_generic, Assembler::kNearJump);
+
+ __ Bind(¬_integer_or_string_or_list);
// Check if the first type is a Type. If it is not then types are not
// equivalent because they have different class ids and they are not String
- // or integer or Type.
+ // or integer or List or Type.
JumpIfNotType(assembler, cid1, not_equal);
// First type is a Type. Check if the second is a Type too.
diff --git a/runtime/vm/compiler/asm_intrinsifier_x64.cc b/runtime/vm/compiler/asm_intrinsifier_x64.cc
index b7109e8..3196c49 100644
--- a/runtime/vm/compiler/asm_intrinsifier_x64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_x64.cc
@@ -1184,6 +1184,11 @@
kIfNotInRange, target);
}
+static void JumpIfNotList(Assembler* assembler, Register cid, Label* target) {
+ RangeCheck(assembler, cid, kArrayCid, kGrowableObjectArrayCid, kIfNotInRange,
+ target);
+}
+
static void JumpIfType(Assembler* assembler, Register cid, Label* target) {
RangeCheck(assembler, cid, kTypeCid, kFunctionTypeCid, kIfInRange, target);
}
@@ -1275,7 +1280,7 @@
Register scratch,
bool testing_instance_cids) {
Label different_cids, equal_cids_but_generic, not_integer,
- not_integer_or_string;
+ not_integer_or_string, not_integer_or_string_or_list;
// Check if left hand side is a closure. Closures are handled in the runtime.
__ cmpq(cid1, Immediate(kClosureCid));
@@ -1297,11 +1302,12 @@
scratch,
target::Class::host_type_arguments_field_offset_in_words_offset()));
__ cmpl(scratch, Immediate(target::Class::kNoTypeArguments));
- __ j(NOT_EQUAL, &equal_cids_but_generic, Assembler::kNearJump);
+ __ j(NOT_EQUAL, &equal_cids_but_generic);
__ jmp(equal);
// Class ids are different. Check if we are comparing two string types (with
- // different representations) or two integer types or two type types.
+ // different representations), two integer types, two list types or two type
+ // types.
__ Bind(&different_cids);
__ cmpq(cid1, Immediate(kNumPredefinedCids));
__ j(ABOVE_EQUAL, not_equal);
@@ -1311,25 +1317,42 @@
JumpIfNotInteger(assembler, scratch, ¬_integer);
// First type is an integer. Check if the second is an integer too.
- JumpIfInteger(assembler, cid2, equal);
+ __ movq(scratch, cid2);
+ JumpIfInteger(assembler, scratch, equal);
// Integer types are only equivalent to other integer types.
__ jmp(not_equal);
__ Bind(¬_integer);
// Check if both are String types.
- JumpIfNotString(assembler, cid1,
+ __ movq(scratch, cid1);
+ JumpIfNotString(assembler, scratch,
testing_instance_cids ? ¬_integer_or_string : not_equal);
// First type is a String. Check if the second is a String too.
- JumpIfString(assembler, cid2, equal);
+ __ movq(scratch, cid2);
+ JumpIfString(assembler, scratch, equal);
// String types are only equivalent to other String types.
__ jmp(not_equal);
if (testing_instance_cids) {
__ Bind(¬_integer_or_string);
+ // Check if both are List types.
+ __ movq(scratch, cid1);
+ JumpIfNotList(assembler, scratch, ¬_integer_or_string_or_list);
+
+ // First type is a List. Check if the second is a List too.
+ __ movq(scratch, cid2);
+ JumpIfNotList(assembler, scratch, not_equal);
+ ASSERT(compiler::target::Array::type_arguments_offset() ==
+ compiler::target::GrowableObjectArray::type_arguments_offset());
+ __ movq(scratch,
+ Immediate(compiler::target::Array::type_arguments_offset()));
+ __ jmp(&equal_cids_but_generic, Assembler::kNearJump);
+
+ __ Bind(¬_integer_or_string_or_list);
// Check if the first type is a Type. If it is not then types are not
// equivalent because they have different class ids and they are not String
- // or integer or Type.
+ // or integer or List or Type.
JumpIfNotType(assembler, cid1, not_equal);
// First type is a Type. Check if the second is a Type too.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 4473e81..5ce5395 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -1531,13 +1531,11 @@
Register class_id_reg,
compiler::Label* is_instance_lbl) {
assembler()->Comment("ListTypeCheck");
- compiler::Label unknown;
- GrowableArray<intptr_t> args;
- args.Add(kArrayCid);
- args.Add(kGrowableObjectArrayCid);
- args.Add(kImmutableArrayCid);
- CheckClassIds(class_id_reg, args, is_instance_lbl, &unknown);
- assembler()->Bind(&unknown);
+ COMPILE_ASSERT((kImmutableArrayCid == kArrayCid + 1) &&
+ (kGrowableObjectArrayCid == kArrayCid + 2));
+ CidRangeVector ranges;
+ ranges.Add({kArrayCid, kGrowableObjectArrayCid});
+ GenerateCidRangesCheck(assembler(), class_id_reg, ranges, is_instance_lbl);
}
void FlowGraphCompiler::EmitComment(Instruction* instr) {
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index cf52ef4..cfb05b7 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -291,7 +291,7 @@
if (!obj->IsNewObject() || visiting_old_object_->untag()->IsRemembered()) {
return;
}
- visiting_old_object_->untag()->SetRememberedBit();
+ visiting_old_object_->untag()->SetRememberedBitUnsynchronized();
thread_->StoreBufferAddObjectGC(visiting_old_object_);
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 5c3adc4..9b7ff28 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -607,6 +607,7 @@
builtin_vtables_[k##clazz##Cid] = fake_handle.vtable(); \
}
CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY_NOR_MAP(INIT_VTABLE)
+ INIT_VTABLE(GrowableObjectArray)
#undef INIT_VTABLE
#define INIT_VTABLE(clazz) \
@@ -630,7 +631,7 @@
Array fake_handle; \
builtin_vtables_[k##clazz##Cid] = fake_handle.vtable(); \
}
- CLASS_LIST_ARRAYS(INIT_VTABLE)
+ CLASS_LIST_FIXED_LENGTH_ARRAYS(INIT_VTABLE)
#undef INIT_VTABLE
#define INIT_VTABLE(clazz) \
diff --git a/runtime/vm/object_graph_copy.cc b/runtime/vm/object_graph_copy.cc
index 76d65b6..1a54883 100644
--- a/runtime/vm/object_graph_copy.cc
+++ b/runtime/vm/object_graph_copy.cc
@@ -1009,6 +1009,7 @@
CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY_NOR_MAP(COPY_TO)
COPY_TO(Array)
+ COPY_TO(GrowableObjectArray)
COPY_TO(LinkedHashMap)
COPY_TO(LinkedHashSet)
#undef COPY_TO
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index f99afbe..5680c3a 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -317,10 +317,14 @@
ASSERT(IsOldObject());
return !tags_.Read<OldAndNotRememberedBit>();
}
- void SetRememberedBit() {
+ bool TryAcquireRememberedBit() {
+ ASSERT(!IsCardRemembered());
+ return tags_.TryClear<OldAndNotRememberedBit>();
+ }
+ void SetRememberedBitUnsynchronized() {
ASSERT(!IsRemembered());
ASSERT(!IsCardRemembered());
- tags_.UpdateBool<OldAndNotRememberedBit>(false);
+ tags_.UpdateUnsynchronized<OldAndNotRememberedBit>(false);
}
void ClearRememberedBit() {
ASSERT(IsOldObject());
@@ -328,10 +332,10 @@
}
DART_FORCE_INLINE
- void AddToRememberedSet(Thread* thread) {
- ASSERT(!this->IsRemembered());
- this->SetRememberedBit();
- thread->StoreBufferAddObject(ObjectPtr(this));
+ void EnsureInRememberedSet(Thread* thread) {
+ if (TryAcquireRememberedBit()) {
+ thread->StoreBufferAddObject(ObjectPtr(this));
+ }
}
bool IsCardRemembered() const { return tags_.Read<CardRememberedBit>(); }
@@ -665,7 +669,7 @@
if (value->IsNewObject()) {
// Generational barrier: record when a store creates an
// old-and-not-remembered -> new reference.
- AddToRememberedSet(thread);
+ EnsureInRememberedSet(thread);
} else {
// Incremental barrier: record when a store creates an
// old -> old-and-not-marked reference.
@@ -695,11 +699,9 @@
if (value->IsNewObject()) {
// Generational barrier: record when a store creates an
// old-and-not-remembered -> new reference.
- ASSERT(!this->IsRemembered());
if (this->IsCardRemembered()) {
RememberCard(addr);
- } else {
- this->SetRememberedBit();
+ } else if (this->TryAcquireRememberedBit()) {
thread->StoreBufferAddObject(static_cast<ObjectPtr>(this));
}
} else {
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index a545c0e..d6c3ad6 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -483,7 +483,7 @@
}
if (add_to_remembered_set) {
- object->untag()->AddToRememberedSet(thread);
+ object->untag()->EnsureInRememberedSet(thread);
}
// For incremental write barrier elimination, we need to ensure that the
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 6112fa7..4985582 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -5208,7 +5208,6 @@
{
JSONArray internals(&map, "List");
CLASS_LIST_ARRAYS(DEFINE_ADD_VALUE_F_CID)
- DEFINE_ADD_VALUE_F_CID(GrowableObjectArray)
DEFINE_ADD_VALUE_F_CID(ByteBuffer)
}
{
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 09a3b25..a9e319e 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -688,9 +688,7 @@
switch (op_) {
case Thread::RestoreWriteBarrierInvariantOp::kAddToRememberedSet:
- if (!obj->untag()->IsRemembered()) {
- obj->untag()->AddToRememberedSet(current_);
- }
+ obj->untag()->EnsureInRememberedSet(current_);
if (current_->is_marking()) {
current_->DeferredMarkingStackAddObject(obj);
}
diff --git a/tests/lib/mirrors/regress_b196606044_test.dart b/tests/lib/mirrors/regress_b196606044_test.dart
new file mode 100644
index 0000000..e656519
--- /dev/null
+++ b/tests/lib/mirrors/regress_b196606044_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2021, 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.
+
+// Regression test for b/196606044.
+//
+// Verifies that instance.type.instanceMembers contains 'isNotEmpty'
+// member for a List literal.
+
+import 'package:expect/expect.dart';
+import 'dart:mirrors';
+
+dynamic object = <int>[1, 2, 3];
+String name = 'isNotEmpty';
+
+main() {
+ var instance = reflect(object);
+ var member = instance.type.instanceMembers[new Symbol(name)];
+ Expect.isNotNull(member);
+ var invocation = instance.getField(member!.simpleName);
+ Expect.isNotNull(invocation);
+ Expect.equals(true, invocation.reflectee);
+}
diff --git a/tests/lib_2/mirrors/regress_b196606044_test.dart b/tests/lib_2/mirrors/regress_b196606044_test.dart
new file mode 100644
index 0000000..12df1a2
--- /dev/null
+++ b/tests/lib_2/mirrors/regress_b196606044_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2021, 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.
+
+// @dart = 2.9
+
+// Regression test for b/196606044.
+//
+// Verifies that instance.type.instanceMembers contains 'isNotEmpty'
+// member for a List literal.
+
+import 'package:expect/expect.dart';
+import 'dart:mirrors';
+
+dynamic object = <int>[1, 2, 3];
+String name = 'isNotEmpty';
+
+main() {
+ var instance = reflect(object);
+ var member = instance.type.instanceMembers[new Symbol(name)];
+ Expect.isNotNull(member);
+ var invocation = instance.getField(member.simpleName);
+ Expect.isNotNull(invocation);
+ Expect.equals(true, invocation.reflectee);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 848e6fb..2155d95 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 19
+PRERELEASE 20
PRERELEASE_PATCH 0
\ No newline at end of file