Version 2.13.0-27.0.dev
Merge commit '6944a2c1ec9c2c6018e21c27ed868ff1ad6cfb1a' into 'dev'
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index d3df6824..62fa573 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -1525,7 +1525,11 @@
var builder = callbacks.createContextBuilder(info.folder);
var options = builder.getAnalysisOptions(contextRoot,
contextRoot: driver.contextRoot);
- var packages = builder.createPackageMap(contextRoot);
+ var packages = ContextBuilder.createPackageMap(
+ resourceProvider: builder.resourceProvider,
+ options: builder.builderOptions,
+ rootPath: contextRoot,
+ );
var factory = builder.createSourceFactory(contextRoot);
driver.configure(
analysisOptions: options,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index f2bec91..87d5edb 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -70,6 +70,31 @@
final unit = await path.mapResult(requireResolvedUnit);
+ bool shouldIncludeKind(CodeActionKind kind) {
+ /// Checks whether the kind matches the [wanted] kind.
+ ///
+ /// If `wanted` is `refactor.foo` then:
+ /// - refactor.foo - included
+ /// - refactor.foobar - not included
+ /// - refactor.foo.bar - included
+ bool isMatch(CodeActionKind wanted) =>
+ kind == wanted || kind.toString().startsWith('${wanted.toString()}.');
+
+ // If the client wants only a specific set, use only that filter.
+ if (params.context?.only != null) {
+ return params.context.only.any(isMatch);
+ }
+
+ // Otherwise, filter out anything not supported by the client (if they
+ // advertised that they provided the kinds).
+ if (clientSupportsLiteralCodeActions &&
+ !clientSupportedCodeActionKinds.any(isMatch)) {
+ return false;
+ }
+
+ return true;
+ }
+
return unit.mapResult((unit) {
final startOffset = toOffset(unit.lineInfo, params.range.start);
final endOffset = toOffset(unit.lineInfo, params.range.end);
@@ -78,7 +103,7 @@
final offset = startOffset;
final length = endOffset - startOffset;
return _getCodeActions(
- clientSupportedCodeActionKinds,
+ shouldIncludeKind,
clientSupportsLiteralCodeActions,
clientSupportsWorkspaceApplyEdit,
clientSupportedDiagnosticTags,
@@ -218,19 +243,13 @@
}
Future<List<Either2<Command, CodeAction>>> _getAssistActions(
- HashSet<CodeActionKind> clientSupportedCodeActionKinds,
+ bool Function(CodeActionKind) shouldIncludeKind,
bool clientSupportsLiteralCodeActions,
Range range,
int offset,
int length,
ResolvedUnitResult unit,
) async {
- // We only support these for clients that advertise codeActionLiteralSupport.
- if (!clientSupportsLiteralCodeActions ||
- !clientSupportedCodeActionKinds.contains(CodeActionKind.Refactor)) {
- return const [];
- }
-
try {
var context = DartAssistContextImpl(
server.instrumentationService,
@@ -247,6 +266,7 @@
_dedupeActions(assists.map(_createAssistAction), range.start);
return assistActions
+ .where((action) => shouldIncludeKind(action.kind))
.map((action) => Either2<Command, CodeAction>.t2(action))
.toList();
} on InconsistentAnalysisException {
@@ -258,7 +278,7 @@
}
Future<ErrorOr<List<Either2<Command, CodeAction>>>> _getCodeActions(
- HashSet<CodeActionKind> kinds,
+ bool Function(CodeActionKind) shouldIncludeKind,
bool supportsLiterals,
bool supportsWorkspaceApplyEdit,
HashSet<DiagnosticTag> supportedDiagnosticTags,
@@ -269,12 +289,14 @@
ResolvedUnitResult unit,
) async {
final results = await Future.wait([
- _getSourceActions(
- kinds, supportsLiterals, supportsWorkspaceApplyEdit, path),
- _getAssistActions(kinds, supportsLiterals, range, offset, length, unit),
- _getRefactorActions(kinds, supportsLiterals, path, offset, length, unit),
- _getFixActions(
- kinds, supportsLiterals, supportedDiagnosticTags, range, unit),
+ _getSourceActions(shouldIncludeKind, supportsLiterals,
+ supportsWorkspaceApplyEdit, path),
+ _getAssistActions(
+ shouldIncludeKind, supportsLiterals, range, offset, length, unit),
+ _getRefactorActions(
+ shouldIncludeKind, supportsLiterals, path, offset, length, unit),
+ _getFixActions(shouldIncludeKind, supportsLiterals,
+ supportedDiagnosticTags, range, unit),
]);
final flatResults = results.expand((x) => x).toList();
@@ -282,18 +304,12 @@
}
Future<List<Either2<Command, CodeAction>>> _getFixActions(
- HashSet<CodeActionKind> clientSupportedCodeActionKinds,
+ bool Function(CodeActionKind) shouldIncludeKind,
bool clientSupportsLiteralCodeActions,
HashSet<DiagnosticTag> supportedDiagnosticTags,
Range range,
ResolvedUnitResult unit,
) async {
- // We only support these for clients that advertise codeActionLiteralSupport.
- if (!clientSupportsLiteralCodeActions ||
- !clientSupportedCodeActionKinds.contains(CodeActionKind.QuickFix)) {
- return const [];
- }
-
final lineInfo = unit.lineInfo;
final codeActions = <CodeAction>[];
final fixAllCodeActions = <CodeAction>[];
@@ -374,6 +390,7 @@
final dedupedActions = _dedupeActions(codeActions, range.start);
return dedupedActions
+ .where((action) => shouldIncludeKind(action.kind))
.map((action) => Either2<Command, CodeAction>.t2(action))
.toList();
} on InconsistentAnalysisException {
@@ -385,7 +402,7 @@
}
Future<List<Either2<Command, CodeAction>>> _getRefactorActions(
- HashSet<CodeActionKind> clientSupportedCodeActionKinds,
+ bool Function(CodeActionKind) shouldIncludeKind,
bool clientSupportsLiteralCodeActions,
String path,
int offset,
@@ -397,13 +414,6 @@
return const [];
}
- // If the client told us what kinds they support but it does not include
- // Refactor then don't return any.
- if (clientSupportsLiteralCodeActions &&
- !clientSupportedCodeActionKinds.contains(CodeActionKind.Refactor)) {
- return const [];
- }
-
/// Helper to create refactors that execute commands provided with
/// the current file, location and document version.
Either2<Command, CodeAction> createRefactor(
@@ -432,24 +442,29 @@
try {
final refactorActions = <Either2<Command, CodeAction>>[];
- // Extract Method
- if (ExtractMethodRefactoring(server.searchEngine, unit, offset, length)
- .isAvailable()) {
- refactorActions.add(createRefactor(CodeActionKind.RefactorExtract,
- 'Extract Method', RefactoringKind.EXTRACT_METHOD));
- }
+ // Extracts
+ if (shouldIncludeKind(CodeActionKind.RefactorExtract)) {
+ // Extract Method
+ if (ExtractMethodRefactoring(server.searchEngine, unit, offset, length)
+ .isAvailable()) {
+ refactorActions.add(createRefactor(CodeActionKind.RefactorExtract,
+ 'Extract Method', RefactoringKind.EXTRACT_METHOD));
+ }
- // Extract Local Variable
- if (ExtractLocalRefactoring(unit, offset, length).isAvailable()) {
- refactorActions.add(createRefactor(CodeActionKind.RefactorExtract,
- 'Extract Local Variable', RefactoringKind.EXTRACT_LOCAL_VARIABLE));
- }
+ // Extract Local Variable
+ if (ExtractLocalRefactoring(unit, offset, length).isAvailable()) {
+ refactorActions.add(createRefactor(
+ CodeActionKind.RefactorExtract,
+ 'Extract Local Variable',
+ RefactoringKind.EXTRACT_LOCAL_VARIABLE));
+ }
- // Extract Widget
- if (ExtractWidgetRefactoring(server.searchEngine, unit, offset, length)
- .isAvailable()) {
- refactorActions.add(createRefactor(CodeActionKind.RefactorExtract,
- 'Extract Widget', RefactoringKind.EXTRACT_WIDGET));
+ // Extract Widget
+ if (ExtractWidgetRefactoring(server.searchEngine, unit, offset, length)
+ .isAvailable()) {
+ refactorActions.add(createRefactor(CodeActionKind.RefactorExtract,
+ 'Extract Widget', RefactoringKind.EXTRACT_WIDGET));
+ }
}
return refactorActions;
@@ -464,7 +479,7 @@
/// Gets "Source" CodeActions, which are actions that apply to whole files of
/// source such as Sort Members and Organise Imports.
Future<List<Either2<Command, CodeAction>>> _getSourceActions(
- HashSet<CodeActionKind> clientSupportedCodeActionKinds,
+ bool Function(CodeActionKind) shouldIncludeKind,
bool clientSupportsLiteralCodeActions,
bool clientSupportsWorkspaceApplyEdit,
String path,
@@ -474,13 +489,6 @@
return const [];
}
- // If the client told us what kinds they support but it does not include
- // Source then don't return any.
- if (clientSupportsLiteralCodeActions &&
- !clientSupportedCodeActionKinds.contains(CodeActionKind.Source)) {
- return const [];
- }
-
// If the client does not support workspace/applyEdit, we won't be able to
// run any of these.
if (!clientSupportsWorkspaceApplyEdit) {
@@ -488,22 +496,24 @@
}
return [
- _commandOrCodeAction(
- clientSupportsLiteralCodeActions,
- DartCodeActionKind.SortMembers,
- Command(
- title: 'Sort Members',
- command: Commands.sortMembers,
- arguments: [path]),
- ),
- _commandOrCodeAction(
- clientSupportsLiteralCodeActions,
- CodeActionKind.SourceOrganizeImports,
- Command(
- title: 'Organize Imports',
- command: Commands.organizeImports,
- arguments: [path]),
- ),
+ if (shouldIncludeKind(DartCodeActionKind.SortMembers))
+ _commandOrCodeAction(
+ clientSupportsLiteralCodeActions,
+ DartCodeActionKind.SortMembers,
+ Command(
+ title: 'Sort Members',
+ command: Commands.sortMembers,
+ arguments: [path]),
+ ),
+ if (shouldIncludeKind(CodeActionKind.SourceOrganizeImports))
+ _commandOrCodeAction(
+ clientSupportsLiteralCodeActions,
+ CodeActionKind.SourceOrganizeImports,
+ Command(
+ title: 'Organize Imports',
+ command: Commands.organizeImports,
+ arguments: [path]),
+ ),
];
}
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
index 242c72f..4a74f56 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
@@ -36,11 +36,19 @@
if (!server.initializationOptions.onlyAnalyzeProjectsWithOpenFiles) {
if (params.workspaceFolders != null) {
params.workspaceFolders.forEach((wf) {
- openWorkspacePaths.add(Uri.parse(wf.uri).toFilePath());
+ final uri = Uri.parse(wf.uri);
+ // Only file URIs are supported, but there's no way to signal this to
+ // the LSP client (and certainly not before initialization).
+ if (uri.isScheme('file')) {
+ openWorkspacePaths.add(uri.toFilePath());
+ }
});
}
if (params.rootUri != null) {
- openWorkspacePaths.add(Uri.parse(params.rootUri).toFilePath());
+ final uri = Uri.parse(params.rootUri);
+ if (uri.isScheme('file')) {
+ openWorkspacePaths.add(uri.toFilePath());
+ }
} else if (params.rootPath != null) {
openWorkspacePaths.add(params.rootPath);
}
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index a0dbd4c..f020e2a 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -8,69 +8,12 @@
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/services/correction/change_workspace.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
-import 'package:analysis_server/src/services/correction/dart/add_await.dart';
-import 'package:analysis_server/src/services/correction/dart/add_const.dart';
-import 'package:analysis_server/src/services/correction/dart/add_diagnostic_property_reference.dart';
-import 'package:analysis_server/src/services/correction/dart/add_override.dart';
-import 'package:analysis_server/src/services/correction/dart/add_required.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_add_all_to_spread.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_conditional_expression_to_if_element.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_documentation_into_line.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_into_is_not.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_map_from_iterable_to_for_literal.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_quotes.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_contains.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_generic_function_syntax.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_if_null.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_int_literal.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_list_literal.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_map_literal.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_null_aware.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_package_import.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_relative_import.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_set_literal.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_where_type.dart';
-import 'package:analysis_server/src/services/correction/dart/create_method.dart';
import 'package:analysis_server/src/services/correction/dart/data_driven.dart';
-import 'package:analysis_server/src/services/correction/dart/inline_invocation.dart';
-import 'package:analysis_server/src/services/correction/dart/inline_typedef.dart';
-import 'package:analysis_server/src/services/correction/dart/make_final.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_argument.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_await.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_const.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_duplicate_case.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_empty_catch.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_empty_constructor_body.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_empty_else.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_empty_statement.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_if_null_operator.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_initializer.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_interpolation_braces.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_method_declaration.dart';
import 'package:analysis_server/src/services/correction/dart/remove_non_null_assertion.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_operator.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_this_expression.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_type_annotation.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_unnecessary_new.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_unnecessary_string_interpolation.dart';
-import 'package:analysis_server/src/services/correction/dart/rename_to_camel_case.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_cascade_with_dot.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_colon_with_equals.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_final_with_const.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_null_with_closure.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_with_conditional_assignment.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_with_is_empty.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_with_tear_off.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_with_var.dart';
-import 'package:analysis_server/src/services/correction/dart/sort_child_property_last.dart';
-import 'package:analysis_server/src/services/correction/dart/use_curly_braces.dart';
-import 'package:analysis_server/src/services/correction/dart/use_is_not_empty.dart';
-import 'package:analysis_server/src/services/correction/dart/use_rethrow.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/fix/data_driven/transform_override_set.dart';
import 'package:analysis_server/src/services/correction/fix/data_driven/transform_override_set_parser.dart';
import 'package:analysis_server/src/services/correction/fix_internal.dart';
-import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/error/error.dart';
@@ -97,202 +40,6 @@
/// The correction producers that are associated with the diagnostics should not
/// produce changes that alter the semantics of the code.
class BulkFixProcessor {
- /// A map from the name of a lint rule to a list of generators used to create
- /// the correction producer used to build a fix for that diagnostic. The
- /// generators used for non-lint diagnostics are in the [nonLintProducerMap].
- ///
- /// Most entries will have only one generator. In cases where there is more
- /// than one, they will be applied in series and the expectation is that only
- /// one will produce a change for a given fix. If more than one change is
- /// produced the result will almost certainly be invalid code.
- static const Map<String, List<ProducerGenerator>> lintProducerMap = {
- LintNames.always_require_non_null_named_parameters: [
- AddRequired.newInstance,
- ],
- LintNames.annotate_overrides: [
- AddOverride.newInstance,
- ],
- LintNames.avoid_annotating_with_dynamic: [
- RemoveTypeAnnotation.newInstance,
- ],
- LintNames.avoid_empty_else: [
- RemoveEmptyElse.newInstance,
- ],
- LintNames.avoid_init_to_null: [
- RemoveInitializer.newInstance,
- ],
- LintNames.avoid_private_typedef_functions: [
- InlineTypedef.newInstance,
- ],
- LintNames.avoid_redundant_argument_values: [
- RemoveArgument.newInstance,
- ],
- LintNames.avoid_relative_lib_imports: [
- ConvertToPackageImport.newInstance,
- ],
- LintNames.avoid_return_types_on_setters: [
- RemoveTypeAnnotation.newInstance,
- ],
- LintNames.avoid_single_cascade_in_expression_statements: [
- ReplaceCascadeWithDot.newInstance,
- ],
- LintNames.avoid_types_on_closure_parameters: [
- RemoveTypeAnnotation.newInstance,
- ],
- LintNames.await_only_futures: [
- RemoveAwait.newInstance,
- ],
- LintNames.curly_braces_in_flow_control_structures: [
- UseCurlyBraces.newInstance,
- ],
- LintNames.diagnostic_describe_all_properties: [
- AddDiagnosticPropertyReference.newInstance,
- ],
- LintNames.empty_catches: [
- RemoveEmptyCatch.newInstance,
- ],
- LintNames.empty_constructor_bodies: [
- RemoveEmptyConstructorBody.newInstance,
- ],
- LintNames.empty_statements: [
- RemoveEmptyStatement.newInstance,
- ],
- LintNames.hash_and_equals: [
- CreateMethod.equalsOrHashCode,
- ],
- LintNames.no_duplicate_case_values: [
- RemoveDuplicateCase.newInstance,
- ],
- LintNames.non_constant_identifier_names: [
- RenameToCamelCase.newInstance,
- ],
- LintNames.null_closures: [
- ReplaceNullWithClosure.newInstance,
- ],
- LintNames.omit_local_variable_types: [
- ReplaceWithVar.newInstance,
- ],
- LintNames.prefer_adjacent_string_concatenation: [
- RemoveOperator.newInstance,
- ],
- LintNames.prefer_collection_literals: [
- ConvertToListLiteral.newInstance,
- ConvertToMapLiteral.newInstance,
- ConvertToSetLiteral.newInstance,
- ],
- LintNames.prefer_conditional_assignment: [
- ReplaceWithConditionalAssignment.newInstance,
- ],
- // TODO (pq): can produce results incompatible w/ `unnecessary_const`
- // LintNames.prefer_const_constructors: [
- // AddConst.newInstance,
- // ReplaceNewWithConst.newInstance,
- // ],
- LintNames.prefer_const_constructors_in_immutables: [
- AddConst.newInstance,
- ],
- LintNames.prefer_const_declarations: [
- ReplaceFinalWithConst.newInstance,
- ],
- LintNames.prefer_contains: [
- ConvertToContains.newInstance,
- ],
- LintNames.prefer_equal_for_default_values: [
- ReplaceColonWithEquals.newInstance,
- ],
- LintNames.prefer_final_fields: [
- MakeFinal.newInstance,
- ],
- LintNames.prefer_final_locals: [
- MakeFinal.newInstance,
- ],
- LintNames.prefer_for_elements_to_map_fromIterable: [
- ConvertMapFromIterableToForLiteral.newInstance,
- ],
- LintNames.prefer_generic_function_type_aliases: [
- ConvertToGenericFunctionSyntax.newInstance,
- ],
- LintNames.prefer_if_elements_to_conditional_expressions: [
- ConvertConditionalExpressionToIfElement.newInstance,
- ],
- LintNames.prefer_if_null_operators: [
- ConvertToIfNull.newInstance,
- ],
- LintNames.prefer_inlined_adds: [
- ConvertAddAllToSpread.newInstance,
- InlineInvocation.newInstance,
- ],
- LintNames.prefer_int_literals: [
- ConvertToIntLiteral.newInstance,
- ],
- LintNames.prefer_is_empty: [
- ReplaceWithIsEmpty.newInstance,
- ],
- LintNames.prefer_is_not_empty: [
- UseIsNotEmpty.newInstance,
- ],
- LintNames.prefer_is_not_operator: [
- ConvertIntoIsNot.newInstance,
- ],
- LintNames.prefer_iterable_whereType: [
- ConvertToWhereType.newInstance,
- ],
- LintNames.prefer_null_aware_operators: [
- ConvertToNullAware.newInstance,
- ],
- LintNames.prefer_relative_imports: [
- ConvertToRelativeImport.newInstance,
- ],
- LintNames.prefer_single_quotes: [
- ConvertToSingleQuotes.newInstance,
- ],
- LintNames.prefer_spread_collections: [
- ConvertAddAllToSpread.newInstance,
- ],
- LintNames.slash_for_doc_comments: [
- ConvertDocumentationIntoLine.newInstance,
- ],
- LintNames.sort_child_properties_last: [
- SortChildPropertyLast.newInstance,
- ],
- LintNames.type_init_formals: [
- RemoveTypeAnnotation.newInstance,
- ],
- LintNames.unawaited_futures: [
- AddAwait.newInstance,
- ],
- LintNames.unnecessary_brace_in_string_interps: [
- RemoveInterpolationBraces.newInstance,
- ],
- LintNames.unnecessary_const: [
- RemoveUnnecessaryConst.newInstance,
- ],
- LintNames.unnecessary_lambdas: [
- ReplaceWithTearOff.newInstance,
- ],
- LintNames.unnecessary_new: [
- RemoveUnnecessaryNew.newInstance,
- ],
- LintNames.unnecessary_null_in_if_null_operators: [
- RemoveIfNullOperator.newInstance,
- ],
- LintNames.unnecessary_overrides: [
- RemoveMethodDeclaration.newInstance,
- ],
- LintNames.unnecessary_string_interpolations: [
- RemoveUnnecessaryStringInterpolation.newInstance,
- ],
- LintNames.unnecessary_this: [
- RemoveThisExpression.newInstance,
- ],
- LintNames.use_function_type_syntax_for_parameters: [
- ConvertToGenericFunctionSyntax.newInstance,
- ],
- LintNames.use_rethrow_when_possible: [
- UseRethrow.newInstance,
- ],
- };
-
/// A map from an error code to a list of generators used to create multiple
/// correction producers used to build fixes for those diagnostics. The
/// generators used for lint rules are in the [lintMultiProducerMap].
@@ -489,9 +236,14 @@
) sync* {
final errorCode = diagnostic.errorCode;
if (errorCode is LintCode) {
- final generators = lintProducerMap[errorCode.name];
- if (generators != null) {
- yield* generators.map((g) => g().fixKind).where((k) => k != null);
+ var fixes = FixProcessor.lintProducerMap2[errorCode.name];
+ for (var fix in fixes) {
+ if (fix.canBeBulkApplied) {
+ final generators = fix.generators;
+ if (generators != null) {
+ yield* generators.map((g) => g().fixKind).where((k) => k != null);
+ }
+ }
}
return;
}
@@ -613,10 +365,15 @@
try {
var codeName = errorCode.name;
if (errorCode is LintCode) {
- var generators = lintProducerMap[codeName];
- if (generators != null) {
- for (var generator in generators) {
- await generate(generator(), codeName);
+ var fixes = FixProcessor.lintProducerMap2[errorCode.name];
+ for (var fix in fixes) {
+ if (fix.canBeBulkApplied) {
+ final generators = fix.generators;
+ if (generators != null) {
+ for (var generator in generators) {
+ await generate(generator(), codeName);
+ }
+ }
}
}
} else {
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 3cacd94..0c2b4ba 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -38,6 +38,7 @@
import 'package:analysis_server/src/services/correction/dart/convert_documentation_into_line.dart';
import 'package:analysis_server/src/services/correction/dart/convert_flutter_child.dart';
import 'package:analysis_server/src/services/correction/dart/convert_flutter_children.dart';
+import 'package:analysis_server/src/services/correction/dart/convert_into_is_not.dart';
import 'package:analysis_server/src/services/correction/dart/convert_map_from_iterable_to_for_literal.dart';
import 'package:analysis_server/src/services/correction/dart/convert_quotes.dart';
import 'package:analysis_server/src/services/correction/dart/convert_to_contains.dart';
@@ -166,6 +167,7 @@
import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart' hide FixContributor;
+import 'package:meta/meta.dart';
/// A function that can be executed to create a multi-correction producer.
typedef MultiProducerGenerator = MultiCorrectionProducer Function();
@@ -302,7 +304,7 @@
var fixes = <Fix>[];
for (var generator in generators) {
- var fixInfo = FixInfo(workspace);
+ var fixState = FixState(workspace);
for (var error in errors) {
var fixContext = DartFixContextImpl(
instrumentationService,
@@ -311,12 +313,12 @@
error,
(name) => [],
);
- await _fixError(fixContext, fixInfo, generator(), error);
+ await _fixError(fixContext, fixState, generator(), error);
}
- var sourceChange = fixInfo.builder.sourceChange;
+ var sourceChange = fixState.builder.sourceChange;
if (sourceChange.edits.isNotEmpty) {
- var fixKind = fixInfo.fixKind;
- if (fixKind.canBeAppliedTogether() && fixInfo.fixCount > 1) {
+ var fixKind = fixState.fixKind;
+ if (fixKind.canBeAppliedTogether() && fixState.fixCount > 1) {
sourceChange.message = fixKind.appliedTogetherMessage;
fixes.add(Fix(fixKind, sourceChange));
}
@@ -325,7 +327,7 @@
return fixes;
}
- Future<void> _fixError(DartFixContext fixContext, FixInfo fixInfo,
+ Future<void> _fixError(DartFixContext fixContext, FixState fixState,
CorrectionProducer producer, AnalysisError diagnostic) async {
var context = CorrectionProducerContext(
applyingBulkFixes: true,
@@ -345,13 +347,13 @@
producer.configure(context);
try {
- var localBuilder = fixInfo.builder.copy();
+ var localBuilder = fixState.builder.copy();
await producer.compute(localBuilder);
- fixInfo.builder = localBuilder;
+ fixState.builder = localBuilder;
// todo (pq): consider discarding the change if the producer's fixKind
// doesn't match a previously cached one.
- fixInfo.fixKind = producer.fixKind;
- fixInfo.fixCount++;
+ fixState.fixKind = producer.fixKind;
+ fixState.fixCount++;
} on ConflictingEditException {
// If a conflicting edit was added in [compute], then the [localBuilder]
// is discarded and we revert to the previous state of the builder.
@@ -379,17 +381,690 @@
}
}
-/// Info used while producing fix all in file fixes.
class FixInfo {
- ChangeBuilder builder;
- FixKind fixKind;
- int fixCount = 0;
- FixInfo(ChangeWorkspace workspace)
- : builder = ChangeBuilder(workspace: workspace);
+ final bool canBeAppliedToFile;
+ final bool canBeBulkApplied;
+ final List<ProducerGenerator> generators;
+ const FixInfo({
+ @required this.canBeAppliedToFile,
+ @required this.canBeBulkApplied,
+ @required this.generators,
+ });
}
/// The computer for Dart fixes.
class FixProcessor extends BaseProcessor {
+ /// todo (pq): to replace lintProducerMap.
+ static const Map<String, List<FixInfo>> lintProducerMap2 = {
+ LintNames.always_declare_return_types: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ // not currently supported; TODO(pq): consider adding
+ canBeBulkApplied: false,
+ generators: [
+ AddReturnType.newInstance,
+ ],
+ )
+ ],
+ LintNames.always_require_non_null_named_parameters: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ AddRequired.newInstance,
+ ],
+ )
+ ],
+ LintNames.always_specify_types: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ // not currently supported; TODO(pq): consider adding
+ canBeBulkApplied: false,
+ generators: [
+ AddTypeAnnotation.newInstance,
+ ],
+ )
+ ],
+ LintNames.annotate_overrides: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ AddOverride.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_annotating_with_dynamic: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveTypeAnnotation.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_empty_else: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveEmptyElse.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_init_to_null: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveInitializer.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_private_typedef_functions: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ InlineTypedef.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_redundant_argument_values: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveArgument.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_relative_lib_imports: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertToPackageImport.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_return_types_on_setters: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveTypeAnnotation.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_returning_null_for_future: [
+ FixInfo(
+ canBeAppliedToFile: false,
+ // not currently supported; TODO(pq): consider adding
+ canBeBulkApplied: false,
+ generators: [
+ AddAsync.newInstance,
+ WrapInFuture.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_single_cascade_in_expression_statements: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ // TODO(brianwilkerson) This fix should be applied to some non-lint
+ // diagnostics and should also be available as an assist.
+ ReplaceCascadeWithDot.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_types_as_parameter_names: [
+ FixInfo(
+ canBeAppliedToFile: false,
+ canBeBulkApplied: false,
+ generators: [
+ ConvertToOnType.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_types_on_closure_parameters: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ReplaceWithIdentifier.newInstance,
+ RemoveTypeAnnotation.newInstance,
+ ],
+ )
+ ],
+ LintNames.avoid_unused_constructor_parameters: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: false,
+ generators: [
+ RemoveUnusedParameter.newInstance,
+ ],
+ )
+ ],
+ LintNames.await_only_futures: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveAwait.newInstance,
+ ],
+ )
+ ],
+ LintNames.curly_braces_in_flow_control_structures: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ UseCurlyBraces.newInstance,
+ ],
+ )
+ ],
+ LintNames.diagnostic_describe_all_properties: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ AddDiagnosticPropertyReference.newInstance,
+ ],
+ )
+ ],
+ LintNames.directives_ordering: [
+ FixInfo(
+ canBeAppliedToFile: false, // Fix will sort all directives.
+ canBeBulkApplied: false,
+ generators: [
+ OrganizeImports.newInstance,
+ ],
+ )
+ ],
+ LintNames.empty_catches: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveEmptyCatch.newInstance,
+ ],
+ )
+ ],
+ LintNames.empty_constructor_bodies: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveEmptyConstructorBody.newInstance,
+ ],
+ )
+ ],
+ LintNames.empty_statements: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveEmptyStatement.newInstance,
+ ReplaceWithBrackets.newInstance,
+ ],
+ )
+ ],
+ LintNames.hash_and_equals: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ CreateMethod.equalsOrHashCode,
+ ],
+ )
+ ],
+ LintNames.no_duplicate_case_values: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveDuplicateCase.newInstance,
+ ],
+ )
+ ],
+ LintNames.non_constant_identifier_names: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RenameToCamelCase.newInstance,
+ ],
+ )
+ ],
+ LintNames.null_closures: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ReplaceNullWithClosure.newInstance,
+ ],
+ )
+ ],
+ LintNames.omit_local_variable_types: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ReplaceWithVar.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_adjacent_string_concatenation: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveOperator.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_collection_literals: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertToListLiteral.newInstance,
+ ConvertToMapLiteral.newInstance,
+ ConvertToSetLiteral.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_conditional_assignment: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ReplaceWithConditionalAssignment.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_const_constructors: [
+ FixInfo(
+ canBeAppliedToFile: false,
+ // Can produce results incompatible w/ `unnecessary_const`
+ canBeBulkApplied: false,
+ generators: [
+ AddConst.newInstance,
+ ReplaceNewWithConst.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_const_constructors_in_immutables: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ AddConst.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_const_declarations: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ReplaceFinalWithConst.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_contains: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertToContains.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_equal_for_default_values: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ReplaceColonWithEquals.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_expression_function_bodies: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ // not currently supported; TODO(pq): consider adding
+ canBeBulkApplied: false,
+ generators: [
+ ConvertToExpressionFunctionBody.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_final_fields: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ MakeFinal.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_final_in_for_each: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ MakeFinal.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_final_locals: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ MakeFinal.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_for_elements_to_map_fromIterable: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertMapFromIterableToForLiteral.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_generic_function_type_aliases: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertToGenericFunctionSyntax.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_if_elements_to_conditional_expressions: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertConditionalExpressionToIfElement.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_is_empty: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ReplaceWithIsEmpty.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_is_not_empty: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ UseIsNotEmpty.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_if_null_operators: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertToIfNull.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_inlined_adds: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertAddAllToSpread.newInstance,
+ InlineInvocation.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_int_literals: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertToIntLiteral.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_interpolation_to_compose_strings: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ // not currently supported; TODO(pq): consider adding
+ canBeBulkApplied: false,
+ generators: [
+ ReplaceWithInterpolation.newInstance,
+ ],
+ )
+ ],
+ // todo (pq): note this is not in lintProducerMap
+ LintNames.prefer_is_not_operator: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertIntoIsNot.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_iterable_whereType: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertToWhereType.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_null_aware_operators: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertToNullAware.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_relative_imports: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertToRelativeImport.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_single_quotes: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertToSingleQuotes.newInstance,
+ ],
+ )
+ ],
+ LintNames.prefer_spread_collections: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertAddAllToSpread.newInstance,
+ ],
+ )
+ ],
+ LintNames.slash_for_doc_comments: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertDocumentationIntoLine.newInstance,
+ ],
+ )
+ ],
+ LintNames.sort_child_properties_last: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ SortChildPropertyLast.newInstance,
+ ],
+ )
+ ],
+ LintNames.type_annotate_public_apis: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ // not currently supported; TODO(pq): consider adding
+ canBeBulkApplied: false,
+ generators: [
+ AddTypeAnnotation.newInstance,
+ ],
+ )
+ ],
+ LintNames.type_init_formals: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveTypeAnnotation.newInstance,
+ ],
+ )
+ ],
+ LintNames.unawaited_futures: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ AddAwait.newInstance,
+ ],
+ )
+ ],
+ LintNames.unnecessary_brace_in_string_interps: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveInterpolationBraces.newInstance,
+ ],
+ )
+ ],
+ LintNames.unnecessary_const: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveUnnecessaryConst.newInstance,
+ ],
+ )
+ ],
+ LintNames.unnecessary_lambdas: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ReplaceWithTearOff.newInstance,
+ ],
+ )
+ ],
+ LintNames.unnecessary_new: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveUnnecessaryNew.newInstance,
+ ],
+ )
+ ],
+ LintNames.unnecessary_null_in_if_null_operators: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveIfNullOperator.newInstance,
+ ],
+ )
+ ],
+ LintNames.unnecessary_overrides: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveMethodDeclaration.newInstance,
+ ],
+ )
+ ],
+ LintNames.unnecessary_parenthesis: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ // not currently supported; TODO(pq): consider adding
+ canBeBulkApplied: false,
+ generators: [
+ RemoveUnnecessaryParentheses.newInstance,
+ ],
+ )
+ ],
+ LintNames.unnecessary_string_interpolations: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveUnnecessaryStringInterpolation.newInstance,
+ ],
+ )
+ ],
+ LintNames.unnecessary_this: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ RemoveThisExpression.newInstance,
+ ],
+ )
+ ],
+ LintNames.use_full_hex_values_for_flutter_colors: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ // not currently supported; TODO(pq): consider adding
+ canBeBulkApplied: false,
+ generators: [
+ ReplaceWithEightDigitHex.newInstance,
+ ],
+ )
+ ],
+ LintNames.use_function_type_syntax_for_parameters: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ ConvertToGenericFunctionSyntax.newInstance,
+ ],
+ )
+ ],
+ LintNames.use_rethrow_when_possible: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
+ generators: [
+ UseRethrow.newInstance,
+ ],
+ )
+ ],
+ };
+
/// A map from the names of lint rules to a list of generators used to create
/// the correction producers used to build fixes for those diagnostics. The
/// generators used for non-lint diagnostics are in the [nonLintProducerMap].
@@ -1339,3 +2014,12 @@
}
}
}
+
+/// State associated with producing fix-all-in-file fixes.
+class FixState {
+ ChangeBuilder builder;
+ FixKind fixKind;
+ int fixCount = 0;
+ FixState(ChangeWorkspace workspace)
+ : builder = ChangeBuilder(workspace: workspace);
+}
diff --git a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
index bf327be..0996e9d 100644
--- a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
@@ -96,6 +96,29 @@
expect(contents[mainFilePath], equals(expectedContent));
}
+ Future<void> test_filtersCorrectly() async {
+ const content = '''
+ import 'dart:async';
+ [[import]] 'dart:convert';
+
+ Future foo;
+ ''';
+ newFile(mainFilePath, content: withoutMarkers(content));
+ await initialize();
+
+ final ofKind = (CodeActionKind kind) => getCodeActions(
+ mainFileUri.toString(),
+ range: rangeFromMarkers(content),
+ kinds: [kind],
+ );
+
+ // The code above will return a quickfix.remove.unusedImport
+ expect(await ofKind(CodeActionKind.QuickFix), isNotEmpty);
+ expect(await ofKind(CodeActionKind('quickfix.remove')), isNotEmpty);
+ expect(await ofKind(CodeActionKind('quickfix.other')), isEmpty);
+ expect(await ofKind(CodeActionKind.Refactor), isEmpty);
+ }
+
Future<void> test_noDuplicates_sameFix() async {
const content = '''
var a = [Test, Test, Te[[]]st];
diff --git a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
index bd236eb..e6d10cc 100644
--- a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
@@ -159,6 +159,31 @@
req1, throwsA(isResponseError(ErrorCodes.ContentModified)));
}
+ Future<void> test_filtersCorrectly() async {
+ const content = '''
+main() {
+ print('Test!');
+ [[print('Test!');]]
+}
+ ''';
+ newFile(mainFilePath, content: withoutMarkers(content));
+ await initialize();
+
+ final ofKind = (CodeActionKind kind) => getCodeActions(
+ mainFileUri.toString(),
+ range: rangeFromMarkers(content),
+ kinds: [kind],
+ );
+
+ // The code above will return a RefactorExtract that should be included
+ // by both Refactor and RefactorExtract, but not RefactorExtractFoo or
+ // RefactorRewrite
+ expect(await ofKind(CodeActionKind.Refactor), isNotEmpty);
+ expect(await ofKind(CodeActionKind.RefactorExtract), isNotEmpty);
+ expect(await ofKind(CodeActionKind('refactor.extract.foo')), isEmpty);
+ expect(await ofKind(CodeActionKind.RefactorRewrite), isEmpty);
+ }
+
Future<void> test_generatesNames() async {
const content = '''
Object main() {
diff --git a/pkg/analysis_server/test/lsp/code_actions_source_test.dart b/pkg/analysis_server/test/lsp/code_actions_source_test.dart
index 12838ed..9a75e7e 100644
--- a/pkg/analysis_server/test/lsp/code_actions_source_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_source_test.dart
@@ -128,6 +128,24 @@
expect(commandResponse, isNull);
}
+ Future<void> test_filtersCorrectly() async {
+ newFile(mainFilePath, content: '');
+ await initialize(
+ workspaceCapabilities:
+ withApplyEditSupport(emptyWorkspaceClientCapabilities));
+
+ final ofKind = (CodeActionKind kind) => getCodeActions(
+ mainFileUri.toString(),
+ kinds: [kind],
+ );
+
+ expect(await ofKind(CodeActionKind.Source), hasLength(2));
+ expect(await ofKind(CodeActionKind.SourceOrganizeImports), hasLength(1));
+ expect(await ofKind(DartCodeActionKind.SortMembers), hasLength(1));
+ expect(await ofKind(CodeActionKind('source.foo')), isEmpty);
+ expect(await ofKind(CodeActionKind.Refactor), isEmpty);
+ }
+
Future<void> test_noEdits() async {
const content = '''
import 'dart:async';
diff --git a/pkg/analysis_server/test/lsp/initialization_test.dart b/pkg/analysis_server/test/lsp/initialization_test.dart
index ce2263f..f864ea6 100644
--- a/pkg/analysis_server/test/lsp/initialization_test.dart
+++ b/pkg/analysis_server/test/lsp/initialization_test.dart
@@ -459,6 +459,36 @@
expect(server.contextManager.includedPaths, equals([projectFolderPath]));
}
+ Future<void> test_nonFileScheme_rootUri() async {
+ final rootUri = Uri.parse('vsls://');
+ final fileUri = rootUri.replace(path: '/file1.dart');
+
+ await initialize(rootUri: rootUri);
+ expect(server.contextManager.includedPaths, equals([]));
+
+ // Also open a non-file file to ensure it doesn't cause the root to be added.
+ await openFile(fileUri, '');
+ expect(server.contextManager.includedPaths, equals([]));
+ }
+
+ Future<void> test_nonFileScheme_workspaceFolders() async {
+ final pubspecPath = join(projectFolderPath, 'pubspec.yaml');
+ newFile(pubspecPath);
+
+ final rootUri = Uri.parse('vsls://');
+ final fileUri = rootUri.replace(path: '/file1.dart');
+
+ await initialize(workspaceFolders: [
+ rootUri,
+ Uri.file(projectFolderPath),
+ ]);
+ expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+
+ // Also open a non-file file to ensure it doesn't cause the root to be added.
+ await openFile(fileUri, '');
+ expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+ }
+
Future<void> test_onlyAnalyzeProjectsWithOpenFiles_multipleFiles() async {
final file1 = join(projectFolderPath, 'file1.dart');
final file1Uri = Uri.file(file1);
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index fead448..dc653fe 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -1470,7 +1470,7 @@
WorkspaceFolder toWorkspaceFolder(Uri uri) {
return WorkspaceFolder(
uri: uri.toString(),
- name: path.basename(uri.toFilePath()),
+ name: path.basename(uri.path),
);
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/data_driven_test.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/data_driven_test.dart
index 2a480a0..a92e878 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/data_driven_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/data_driven_test.dart
@@ -5,6 +5,7 @@
import 'package:analysis_server/src/services/correction/bulk_fix_processor.dart';
import 'package:analysis_server/src/services/correction/dart/data_driven.dart';
import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_manager.dart';
+import 'package:analysis_server/src/services/correction/fix_internal.dart';
import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -505,8 +506,11 @@
// action accidentally executing data-driven fixes.
final dataDrivenCodes = <String>{};
+ final bulkFixCodes = FixProcessor.lintProducerMap2.entries
+ .where((e) => e.value.where((fix) => fix.canBeBulkApplied).isNotEmpty)
+ .map((e) => e.key);
final nonDataDrivenCodes = <String>{
- ...BulkFixProcessor.lintProducerMap.keys,
+ ...bulkFixCodes,
...BulkFixProcessor.nonLintProducerMap.keys.map((c) => c.uniqueName),
};
diff --git a/pkg/analysis_server/tool/bulk_fix/supported_lints.dart b/pkg/analysis_server/tool/bulk_fix/supported_lints.dart
index 7d6fbb3..135c10c 100644
--- a/pkg/analysis_server/tool/bulk_fix/supported_lints.dart
+++ b/pkg/analysis_server/tool/bulk_fix/supported_lints.dart
@@ -2,13 +2,16 @@
// 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 'package:analysis_server/src/services/correction/bulk_fix_processor.dart';
+import 'package:analysis_server/src/services/correction/fix_internal.dart';
/// Print lints that are bulk-fixable in a format that can be included in
/// analysis options.
void main() {
+ final bulkFixCodes = FixProcessor.lintProducerMap2.entries
+ .where((e) => e.value.where((fix) => fix.canBeBulkApplied).isNotEmpty)
+ .map((e) => e.key);
print(' # bulk-fixable lints');
- for (var lintName in BulkFixProcessor.lintProducerMap.keys) {
+ for (var lintName in bulkFixCodes) {
print(' - $lintName');
}
}
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 4219495..77ee797 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -1491,12 +1491,11 @@
///
/// Clients may not extend, implement or mix-in this class.
abstract class ConstructorDeclaration implements ClassMember {
- /// Return the body of the constructor, or `null` if the constructor does not
- /// have a body.
- FunctionBody? get body;
+ /// Return the body of the constructor.
+ FunctionBody get body;
/// Set the body of the constructor to the given [functionBody].
- set body(FunctionBody? functionBody);
+ set body(FunctionBody functionBody);
/// Return the token for the 'const' keyword, or `null` if the constructor is
/// not a const constructor.
@@ -2747,12 +2746,11 @@
///
/// Clients may not extend, implement or mix-in this class.
abstract class FunctionExpression implements Expression {
- /// Return the body of the function, or `null` if this is an external
- /// function.
- FunctionBody? get body;
+ /// Return the body of the function.
+ FunctionBody get body;
/// Set the body of the function to the given [functionBody].
- set body(FunctionBody? functionBody);
+ set body(FunctionBody functionBody);
/// Return the element associated with the function, or `null` if the AST
/// structure has not been resolved.
diff --git a/pkg/analyzer/lib/dart/ast/ast_factory.dart b/pkg/analyzer/lib/dart/ast/ast_factory.dart
index 7aabf24..8ba70d1 100644
--- a/pkg/analyzer/lib/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/dart/ast/ast_factory.dart
@@ -201,8 +201,7 @@
/// initializers and does not redirect to a different constructor. The list of
/// [initializers] can be `null` if the constructor does not have any
/// initializers. The [redirectedConstructor] can be `null` if the constructor
- /// does not redirect to a different constructor. The [body] can be `null` if
- /// the constructor does not have a body.
+ /// does not redirect to a different constructor.
ConstructorDeclaration constructorDeclaration(
Comment? comment,
List<Annotation>? metadata,
@@ -216,7 +215,7 @@
Token? separator,
List<ConstructorInitializer>? initializers,
ConstructorName? redirectedConstructor,
- FunctionBody? body);
+ FunctionBody body);
/// Returns a newly created field initializer to initialize the field with
/// the given name to the value of the given expression. The [thisKeyword] and
@@ -465,7 +464,7 @@
/// Returns a newly created function declaration.
FunctionExpression functionExpression(TypeParameterList? typeParameters,
- FormalParameterList? parameters, FunctionBody? body);
+ FormalParameterList? parameters, FunctionBody body);
/// Returns a newly created function expression invocation.
FunctionExpressionInvocation functionExpressionInvocation(Expression function,
diff --git a/pkg/analyzer/lib/exception/exception.dart b/pkg/analyzer/lib/exception/exception.dart
index d23c830..9ac1bca 100644
--- a/pkg/analyzer/lib/exception/exception.dart
+++ b/pkg/analyzer/lib/exception/exception.dart
@@ -20,10 +20,13 @@
StringBuffer buffer = StringBuffer();
buffer.write('$runtimeType: ');
buffer.writeln(message);
+
+ var cause = this.cause;
if (cause != null) {
buffer.write('Caused by ');
- cause!._writeOn(buffer);
+ cause._writeOn(buffer);
}
+
return buffer.toString();
}
}
diff --git a/pkg/analyzer/lib/instrumentation/log_adapter.dart b/pkg/analyzer/lib/instrumentation/log_adapter.dart
index c3f3ad6..cd1393c 100644
--- a/pkg/analyzer/lib/instrumentation/log_adapter.dart
+++ b/pkg/analyzer/lib/instrumentation/log_adapter.dart
@@ -25,7 +25,7 @@
static const String TAG_WATCH_EVENT = 'Watch';
/// A logger used to log instrumentation in string format.
- final InstrumentationLogger? _instrumentationLogger;
+ final InstrumentationLogger _instrumentationLogger;
/// Initialize a newly created instrumentation service to communicate with the
/// given [_instrumentationLogger].
@@ -43,11 +43,9 @@
StackTrace? stackTrace,
List<InstrumentationServiceAttachment>? attachments,
]) {
- if (_instrumentationLogger != null) {
- String message = _toString(exception);
- String trace = _toString(stackTrace);
- _instrumentationLogger!.log(_join([TAG_EXCEPTION, message, trace]));
- }
+ String message = _toString(exception);
+ String trace = _toString(stackTrace);
+ _instrumentationLogger.log(_join([TAG_EXCEPTION, message, trace]));
}
@override
@@ -57,20 +55,18 @@
@override
void logLogEntry(String level, DateTime? time, String message,
Object exception, StackTrace stackTrace) {
- if (_instrumentationLogger != null) {
- String timeStamp =
- time == null ? 'null' : time.millisecondsSinceEpoch.toString();
- String exceptionText = exception.toString();
- String stackTraceText = stackTrace.toString();
- _instrumentationLogger!.log(_join([
- TAG_LOG_ENTRY,
- level,
- timeStamp,
- message,
- exceptionText,
- stackTraceText
- ]));
- }
+ String timeStamp =
+ time == null ? 'null' : time.millisecondsSinceEpoch.toString();
+ String exceptionText = exception.toString();
+ String stackTraceText = stackTrace.toString();
+ _instrumentationLogger.log(_join([
+ TAG_LOG_ENTRY,
+ level,
+ timeStamp,
+ message,
+ exceptionText,
+ stackTraceText
+ ]));
}
@override
@@ -80,63 +76,46 @@
@override
void logPluginError(
PluginData plugin, String code, String message, String stackTrace) {
- if (_instrumentationLogger != null) {
- List<String> fields = <String>[
- TAG_PLUGIN_ERROR,
- code,
- message,
- stackTrace
- ];
- plugin.addToFields(fields);
- _instrumentationLogger!.log(_join(fields));
- }
+ List<String> fields = <String>[TAG_PLUGIN_ERROR, code, message, stackTrace];
+ plugin.addToFields(fields);
+ _instrumentationLogger.log(_join(fields));
}
@override
void logPluginException(
PluginData plugin, dynamic exception, StackTrace? stackTrace) {
- if (_instrumentationLogger != null) {
- List<String> fields = <String>[
- TAG_PLUGIN_EXCEPTION,
- _toString(exception),
- _toString(stackTrace)
- ];
- plugin.addToFields(fields);
- _instrumentationLogger!.log(_join(fields));
- }
+ List<String> fields = <String>[
+ TAG_PLUGIN_EXCEPTION,
+ _toString(exception),
+ _toString(stackTrace)
+ ];
+ plugin.addToFields(fields);
+ _instrumentationLogger.log(_join(fields));
}
@override
void logPluginNotification(String pluginId, String notification) {
- if (_instrumentationLogger != null) {
- _instrumentationLogger!.log(
- _join([TAG_PLUGIN_NOTIFICATION, notification, pluginId, '', '']));
- }
+ _instrumentationLogger
+ .log(_join([TAG_PLUGIN_NOTIFICATION, notification, pluginId, '', '']));
}
@override
void logPluginRequest(String pluginId, String request) {
- if (_instrumentationLogger != null) {
- _instrumentationLogger!
- .log(_join([TAG_PLUGIN_REQUEST, request, pluginId, '', '']));
- }
+ _instrumentationLogger
+ .log(_join([TAG_PLUGIN_REQUEST, request, pluginId, '', '']));
}
@override
void logPluginResponse(String pluginId, String response) {
- if (_instrumentationLogger != null) {
- _instrumentationLogger!
- .log(_join([TAG_PLUGIN_RESPONSE, response, pluginId, '', '']));
- }
+ _instrumentationLogger
+ .log(_join([TAG_PLUGIN_RESPONSE, response, pluginId, '', '']));
}
@override
void logPluginTimeout(PluginData plugin, String request) {
- if (_instrumentationLogger != null) {
- List<String> fields = <String>[TAG_PLUGIN_TIMEOUT, request];
- plugin.addToFields(fields);
- _instrumentationLogger!.log(_join(fields));
- }
+ List<String> fields = <String>[TAG_PLUGIN_TIMEOUT, request];
+ plugin.addToFields(fields);
+ _instrumentationLogger.log(_join(fields));
}
@override
@@ -151,29 +130,25 @@
String normalize(String? value) =>
value != null && value.isNotEmpty ? value : 'unknown';
- if (_instrumentationLogger != null) {
- _instrumentationLogger!.log(_join([
- TAG_VERSION,
- uuid,
- normalize(clientId),
- normalize(clientVersion),
- serverVersion,
- sdkVersion
- ]));
- }
+ _instrumentationLogger.log(_join([
+ TAG_VERSION,
+ uuid,
+ normalize(clientId),
+ normalize(clientVersion),
+ serverVersion,
+ sdkVersion
+ ]));
}
@override
void logWatchEvent(String folderPath, String filePath, String changeType) {
- if (_instrumentationLogger != null) {
- _instrumentationLogger!
- .log(_join([TAG_WATCH_EVENT, folderPath, filePath, changeType]));
- }
+ _instrumentationLogger
+ .log(_join([TAG_WATCH_EVENT, folderPath, filePath, changeType]));
}
@override
Future<void> shutdown() async {
- await _instrumentationLogger?.shutdown();
+ await _instrumentationLogger.shutdown();
}
/// Write an escaped version of the given [field] to the given [buffer].
@@ -208,9 +183,7 @@
/// Log the given message with the given tag.
void _log(String tag, String message) {
- if (_instrumentationLogger != null) {
- _instrumentationLogger!.log(_join([tag, message]));
- }
+ _instrumentationLogger.log(_join([tag, message]));
}
/// Convert the given [object] to a string.
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index e8a31f4..6d79372 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -67,7 +67,7 @@
/// The manager used to manage the DartSdk's that have been created so that
/// they can be shared across contexts.
- final DartSdkManager? sdkManager;
+ final DartSdkManager sdkManager;
/// The cache containing the contents of overlaid files. If this builder will
/// be used to build analysis drivers, set the [fileContentOverlay] instead.
@@ -114,13 +114,19 @@
String path = contextRoot.root;
var options = getAnalysisOptions(path, contextRoot: contextRoot);
//_processAnalysisOptions(context, optionMap);
+
SummaryDataStore? summaryData;
- if (builderOptions.librarySummaryPaths != null) {
- summaryData = SummaryDataStore(builderOptions.librarySummaryPaths!);
+ var librarySummaryPaths = builderOptions.librarySummaryPaths;
+ if (librarySummaryPaths != null) {
+ summaryData = SummaryDataStore(librarySummaryPaths);
}
+
Workspace workspace = ContextBuilder.createWorkspace(
- resourceProvider, path, this,
- lookForBazelBuildFileSubstitutes: lookForBazelBuildFileSubstitutes);
+ resourceProvider: resourceProvider,
+ options: builderOptions,
+ rootPath: path,
+ lookForBazelBuildFileSubstitutes: lookForBazelBuildFileSubstitutes,
+ );
final sf =
createSourceFactoryFromWorkspace(workspace, summaryData: summaryData);
@@ -133,7 +139,11 @@
contextRoot,
sf,
options,
- packages: createPackageMap(path),
+ packages: createPackageMap(
+ resourceProvider: resourceProvider,
+ options: builderOptions,
+ rootPath: path,
+ ),
enableIndex: enableIndex,
externalSummaries: summaryData,
retainDataForTesting: retainDataForTesting,
@@ -196,21 +206,13 @@
// }
// }
- Packages createPackageMap(String rootDirectoryPath) {
- var configPath = builderOptions.defaultPackageFilePath;
- if (configPath != null) {
- var configFile = resourceProvider.getFile(configPath);
- return parsePackagesFile(resourceProvider, configFile);
- } else {
- var resource = resourceProvider.getResource(rootDirectoryPath);
- return findPackagesFrom(resourceProvider, resource);
- }
- }
-
SourceFactory createSourceFactory(String rootPath,
{SummaryDataStore? summaryData}) {
- Workspace workspace =
- ContextBuilder.createWorkspace(resourceProvider, rootPath, this);
+ Workspace workspace = ContextBuilder.createWorkspace(
+ resourceProvider: resourceProvider,
+ options: builderOptions,
+ rootPath: rootPath,
+ );
DartSdk sdk = findSdk(workspace);
if (summaryData != null && sdk is SummaryBasedDartSdk) {
summaryData.addBundle(null, sdk.bundle);
@@ -248,9 +250,9 @@
DartSdk folderSdk;
{
- String sdkPath = sdkManager!.defaultSdkDirectory;
+ String sdkPath = sdkManager.defaultSdkDirectory;
SdkDescription description = SdkDescription(sdkPath);
- folderSdk = sdkManager!.getSdk(description, () {
+ folderSdk = sdkManager.getSdk(description, () {
return FolderBasedDartSdk(
resourceProvider,
resourceProvider.getFolder(sdkPath),
@@ -296,8 +298,11 @@
// TODO(danrubel) restructure so that we don't create a workspace
// both here and in createSourceFactory
- Workspace workspace =
- ContextBuilder.createWorkspace(resourceProvider, path, this);
+ Workspace workspace = ContextBuilder.createWorkspace(
+ resourceProvider: resourceProvider,
+ options: builderOptions,
+ rootPath: path,
+ );
SourceFactory sourceFactory = workspace.createSourceFactory(null, null);
AnalysisOptionsProvider optionsProvider =
AnalysisOptionsProvider(sourceFactory);
@@ -342,8 +347,9 @@
if (optionMap != null) {
applyToAnalysisOptions(options, optionMap);
- if (builderOptions.argResults != null) {
- applyAnalysisOptionFlags(options, builderOptions.argResults!,
+ var argResults = builderOptions.argResults;
+ if (argResults != null) {
+ applyAnalysisOptionFlags(options, argResults,
verbosePrint: verbosePrint);
}
} else {
@@ -402,10 +408,33 @@
return null;
}
- static Workspace createWorkspace(ResourceProvider resourceProvider,
- String rootPath, ContextBuilder contextBuilder,
- {bool lookForBazelBuildFileSubstitutes = true}) {
- var packages = contextBuilder.createPackageMap(rootPath);
+ /// Return [Packages] to analyze a resource with the [rootPath].
+ static Packages createPackageMap({
+ required ResourceProvider resourceProvider,
+ required ContextBuilderOptions options,
+ required String rootPath,
+ }) {
+ var configPath = options.defaultPackageFilePath;
+ if (configPath != null) {
+ var configFile = resourceProvider.getFile(configPath);
+ return parsePackagesFile(resourceProvider, configFile);
+ } else {
+ var resource = resourceProvider.getResource(rootPath);
+ return findPackagesFrom(resourceProvider, resource);
+ }
+ }
+
+ static Workspace createWorkspace({
+ required ResourceProvider resourceProvider,
+ required ContextBuilderOptions options,
+ required String rootPath,
+ bool lookForBazelBuildFileSubstitutes = true,
+ }) {
+ var packages = ContextBuilder.createPackageMap(
+ resourceProvider: resourceProvider,
+ options: options,
+ rootPath: rootPath,
+ );
var packageMap = <String, List<Folder>>{};
for (var package in packages.packages) {
packageMap[package.name] = [package.libFolder];
diff --git a/pkg/analyzer/lib/src/context/packages.dart b/pkg/analyzer/lib/src/context/packages.dart
index 57cdcd2..fd7c7e5 100644
--- a/pkg/analyzer/lib/src/context/packages.dart
+++ b/pkg/analyzer/lib/src/context/packages.dart
@@ -93,10 +93,11 @@
);
Version? languageVersion;
- if (jsonPackage.languageVersion != null) {
+ var jsonLanguageVersion = jsonPackage.languageVersion;
+ if (jsonLanguageVersion != null) {
languageVersion = Version(
- jsonPackage.languageVersion!.major,
- jsonPackage.languageVersion!.minor,
+ jsonLanguageVersion.major,
+ jsonLanguageVersion.minor,
0,
);
// New features were added in `2.2.2` over `2.2.0`.
diff --git a/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart b/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
index 836177c..6a8e2c1 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
@@ -142,12 +142,6 @@
/// are different.
late List<int> uriSignature;
- /// The name of the enclosing class name, or `null` if outside a class.
- String? enclosingClassName;
-
- /// The super class of the enclosing class, or `null` if outside a class.
- TypeName? enclosingSuperClass;
-
/// The precomputed signature of the enclosing class name, or `null` if
/// outside a class.
///
@@ -156,9 +150,6 @@
/// locations are different.
List<int>? enclosingClassNameSignature;
- /// The node of the enclosing class.
- Node? enclosingClass;
-
_LibraryBuilder(this.uri, this.units);
Library build() {
@@ -176,25 +167,29 @@
}
void _addClassOrMixin(ClassOrMixinDeclaration node) {
- enclosingClassName = node.name.name;
+ var enclosingClassName = node.name.name;
+
+ TypeName? enclosingSuperClass;
if (node is ClassDeclaration) {
enclosingSuperClass = node.extendsClause?.superclass;
}
enclosingClassNameSignature =
- (ApiSignature()..addString(enclosingClassName!)).toByteList();
+ (ApiSignature()..addString(enclosingClassName)).toByteList();
var apiTokenSignature = _computeTokenSignature(
node.beginToken,
node.leftBracket,
);
+ var typeParameters = node.typeParameters;
+
Dependencies api;
if (node is ClassDeclaration) {
api = referenceCollector.collect(
apiTokenSignature,
thisNodeName: enclosingClassName,
- typeParameters: node.typeParameters,
+ typeParameters: typeParameters,
extendsClause: node.extendsClause,
withClause: node.withClause,
implementsClause: node.implementsClause,
@@ -203,7 +198,7 @@
api = referenceCollector.collect(
apiTokenSignature,
thisNodeName: enclosingClassName,
- typeParameters: node.typeParameters,
+ typeParameters: typeParameters,
onClause: node.onClause,
implementsClause: node.implementsClause,
);
@@ -211,8 +206,8 @@
throw UnimplementedError('(${node.runtimeType}) $node');
}
- enclosingClass = Node(
- LibraryQualifiedName(uri, enclosingClassName!),
+ var enclosingClass = Node(
+ LibraryQualifiedName(uri, enclosingClassName),
node is MixinDeclaration ? NodeKind.MIXIN : NodeKind.CLASS,
api,
Dependencies.none,
@@ -224,9 +219,9 @@
// TODO(scheglov) do we need type parameters at all?
List<Node> classTypeParameters;
- if (node.typeParameters != null) {
+ if (typeParameters != null) {
classTypeParameters = <Node>[];
- for (var typeParameter in node.typeParameters!.typeParameters) {
+ for (var typeParameter in typeParameters.typeParameters) {
var api = referenceCollector.collect(
_computeNodeTokenSignature(typeParameter),
enclosingClassName: enclosingClassName,
@@ -238,11 +233,11 @@
NodeKind.TYPE_PARAMETER,
api,
Dependencies.none,
- enclosingClass: enclosingClass!,
+ enclosingClass: enclosingClass,
));
}
classTypeParameters.sort(Node.compare);
- enclosingClass!.setTypeParameters(classTypeParameters);
+ enclosingClass.setTypeParameters(classTypeParameters);
}
var classMembers = <Node>[];
@@ -250,16 +245,22 @@
for (var member in node.members) {
if (member is ConstructorDeclaration) {
hasConstructor = true;
- _addConstructor(classMembers, member);
+ _addConstructor(
+ enclosingClass,
+ enclosingSuperClass,
+ classMembers,
+ member,
+ );
} else if (member is FieldDeclaration) {
_addVariables(
+ enclosingClass,
classMembers,
member.metadata,
member.fields,
hasConstConstructor,
);
} else if (member is MethodDeclaration) {
- _addMethod(classMembers, member);
+ _addMethod(enclosingClass, classMembers, member);
} else {
throw UnimplementedError('(${member.runtimeType}) $member');
}
@@ -271,18 +272,15 @@
NodeKind.CONSTRUCTOR,
Dependencies.none,
Dependencies.none,
- enclosingClass: enclosingClass!,
+ enclosingClass: enclosingClass,
));
}
classMembers.sort(Node.compare);
- enclosingClass!.setClassMembers(classMembers);
+ enclosingClass.setClassMembers(classMembers);
- declaredNodes.add(enclosingClass!);
- enclosingClassName = null;
+ declaredNodes.add(enclosingClass);
enclosingClassNameSignature = null;
- enclosingSuperClass = null;
- enclosingClass = null;
}
void _addClassTypeAlias(ClassTypeAlias node) {
@@ -303,7 +301,12 @@
));
}
- void _addConstructor(List<Node> classMembers, ConstructorDeclaration node) {
+ void _addConstructor(
+ Node enclosingClass,
+ TypeName? enclosingSuperClass,
+ List<Node> classMembers,
+ ConstructorDeclaration node,
+ ) {
var builder = _newApiSignatureBuilder();
_appendMetadataTokens(builder, node.metadata);
_appendFormalParametersTokens(builder, node.parameters);
@@ -311,14 +314,14 @@
var api = referenceCollector.collect(
apiTokenSignature,
- enclosingClassName: enclosingClassName,
+ enclosingClassName: enclosingClass.name.name,
formalParameters: node.parameters,
);
var implTokenSignature = _computeNodeTokenSignature(node.body);
var impl = referenceCollector.collect(
implTokenSignature,
- enclosingClassName: enclosingClassName,
+ enclosingClassName: enclosingClass.name.name,
enclosingSuperClass: enclosingSuperClass,
formalParametersForImpl: node.parameters,
constructorInitializers: node.initializers,
@@ -331,7 +334,7 @@
NodeKind.CONSTRUCTOR,
api,
impl,
- enclosingClass: enclosingClass!,
+ enclosingClass: enclosingClass,
));
}
@@ -392,9 +395,11 @@
for (var directive in units.first.directives) {
if (directive is ExportDirective) {
var refUri = directive.uri.stringValue;
- var importUri = uri.resolve(refUri!);
- var combinators = _getCombinators(directive);
- exports.add(Export(importUri, combinators));
+ if (refUri != null) {
+ var importUri = uri.resolve(refUri);
+ var combinators = _getCombinators(directive);
+ exports.add(Export(importUri, combinators));
+ }
}
}
}
@@ -499,7 +504,11 @@
for (var directive in units.first.directives) {
if (directive is ImportDirective) {
var refUri = directive.uri.stringValue;
- var importUri = uri.resolve(refUri!);
+ if (refUri == null) {
+ continue;
+ }
+
+ var importUri = uri.resolve(refUri);
if (importUri.toString() == 'dart:core') {
hasDartCoreImport = true;
@@ -521,7 +530,11 @@
}
}
- void _addMethod(List<Node> classMembers, MethodDeclaration node) {
+ void _addMethod(
+ Node enclosingClass,
+ List<Node> classMembers,
+ MethodDeclaration node,
+ ) {
var builder = _newApiSignatureBuilder();
_appendMetadataTokens(builder, node.metadata);
_appendNodeTokens(builder, node.returnType);
@@ -541,7 +554,7 @@
// TODO(scheglov) metadata, here and everywhere
var api = referenceCollector.collect(
apiTokenSignature,
- enclosingClassName: enclosingClassName,
+ enclosingClassName: enclosingClass.name.name,
thisNodeName: node.name.name,
typeParameters: node.typeParameters,
formalParameters: node.parameters,
@@ -551,7 +564,7 @@
var implTokenSignature = _computeNodeTokenSignature(node.body);
var impl = referenceCollector.collect(
implTokenSignature,
- enclosingClassName: enclosingClassName,
+ enclosingClassName: enclosingClass.name.name,
thisNodeName: node.name.name,
formalParametersForImpl: node.parameters,
functionBody: node.body,
@@ -559,7 +572,7 @@
var name = LibraryQualifiedName(uri, node.name.name);
classMembers.add(
- Node(name, kind, api, impl, enclosingClass: enclosingClass!),
+ Node(name, kind, api, impl, enclosingClass: enclosingClass),
);
}
@@ -579,6 +592,7 @@
_addGenericTypeAlias(declaration);
} else if (declaration is TopLevelVariableDeclaration) {
_addVariables(
+ null,
declaredNodes,
declaration.metadata,
declaration.variables,
@@ -590,8 +604,13 @@
}
}
- void _addVariables(List<Node> variableNodes, List<Annotation> metadata,
- VariableDeclarationList variables, bool appendInitializerToApi) {
+ void _addVariables(
+ Node? enclosingClass,
+ List<Node> variableNodes,
+ List<Annotation> metadata,
+ VariableDeclarationList variables,
+ bool appendInitializerToApi,
+ ) {
if (variables.isConst || variables.type == null) {
appendInitializerToApi = true;
}
@@ -610,7 +629,7 @@
var apiTokenSignature = builder.toByteList();
var api = referenceCollector.collect(
apiTokenSignature,
- enclosingClassName: enclosingClassName,
+ enclosingClassName: enclosingClass?.name.name,
thisNodeName: variable.name.name,
type: variables.type,
expression: appendInitializerToApi ? initializer : null,
@@ -619,7 +638,7 @@
var implTokenSignature = _computeNodeTokenSignature(initializer);
var impl = referenceCollector.collect(
implTokenSignature,
- enclosingClassName: enclosingClassName,
+ enclosingClassName: enclosingClass?.name.name,
thisNodeName: variable.name.name,
expression: initializer,
);
@@ -668,9 +687,12 @@
ApiSignature _newApiSignatureBuilder() {
var builder = ApiSignature();
builder.addBytes(uriSignature);
+
+ var enclosingClassNameSignature = this.enclosingClassNameSignature;
if (enclosingClassNameSignature != null) {
- builder.addBytes(enclosingClassNameSignature!);
+ builder.addBytes(enclosingClassNameSignature);
}
+
return builder;
}
@@ -692,13 +714,12 @@
// If a simple not named parameter, we don't need its name.
// We should be careful to include also annotations.
- if (parameter is SimpleFormalParameter && parameter.type != null) {
- _appendTokens(
- signature,
- parameter.beginToken,
- parameter.type!.endToken,
- );
- continue;
+ if (parameter is SimpleFormalParameter) {
+ var type = parameter.type;
+ if (type != null) {
+ _appendTokens(signature, parameter.beginToken, type.endToken);
+ continue;
+ }
}
// We don't know anything better than adding the whole parameter.
diff --git a/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart b/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
index 6f7679b..85fe63e 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
@@ -429,9 +429,12 @@
DefaultFormalParameter defaultParameter = parameter;
parameter = defaultParameter.parameter;
}
- if (parameter.identifier != null) {
- _localScopes.add(parameter.identifier!.name);
+
+ var identifier = parameter.identifier;
+ if (identifier != null) {
+ _localScopes.add(identifier.name);
}
+
if (parameter is FieldFormalParameter) {
_visitTypeAnnotation(parameter.type);
// Strongly speaking, we reference a field of the enclosing class.
@@ -462,8 +465,9 @@
parameter = defaultParameter.parameter;
}
- if (parameter.identifier != null) {
- _localScopes.add(parameter.identifier!.name);
+ var identifier = parameter.identifier;
+ if (identifier != null) {
+ _localScopes.add(identifier.name);
}
}
}
@@ -783,8 +787,9 @@
if (node is GenericFunctionType) {
_localScopes.enter();
- if (node.typeParameters != null) {
- var typeParameters = node.typeParameters!.typeParameters;
+ var typeParameterList = node.typeParameters;
+ if (typeParameterList != null) {
+ var typeParameters = typeParameterList.typeParameters;
for (var i = 0; i < typeParameters.length; i++) {
var typeParameter = typeParameters[i];
_localScopes.add(typeParameter.name.name);
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart b/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart
index 7178759..05e4a4b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart
@@ -57,9 +57,11 @@
}
Workspace _buildWorkspace() {
- String path = contextRoot.root.path;
- ContextBuilder builder = ContextBuilder(
- resourceProvider, null /* sdkManager */, null /* contentCache */);
- return ContextBuilder.createWorkspace(resourceProvider, path, builder);
+ var path = contextRoot.root.path;
+ return ContextBuilder.createWorkspace(
+ resourceProvider: resourceProvider,
+ options: ContextBuilderOptions(),
+ rootPath: path,
+ );
}
}
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index da21735..df1ca02 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -2403,9 +2403,8 @@
/// or `null` if this is not a redirecting factory constructor.
ConstructorNameImpl? _redirectedConstructor;
- /// The body of the constructor, or `null` if the constructor does not have a
- /// body.
- FunctionBodyImpl? _body;
+ /// The body of the constructor.
+ FunctionBodyImpl _body;
/// The element associated with this constructor, or `null` if the AST
/// structure has not been resolved or if this constructor could not be
@@ -2450,11 +2449,11 @@
}
@override
- FunctionBody? get body => _body;
+ FunctionBody get body => _body;
@override
- set body(FunctionBody? functionBody) {
- _body = _becomeParentOf(functionBody as FunctionBodyImpl?);
+ set body(FunctionBody functionBody) {
+ _body = _becomeParentOf(functionBody as FunctionBodyImpl);
}
@override
@@ -2473,12 +2472,7 @@
@override
Token get endToken {
- if (_body != null) {
- return _body!.endToken;
- } else if (_initializers.isNotEmpty) {
- return _initializers.endToken!;
- }
- return _parameters.endToken;
+ return _body.endToken;
}
@override
@@ -2539,7 +2533,7 @@
_parameters.accept(visitor);
_initializers.accept(visitor);
_redirectedConstructor?.accept(visitor);
- _body?.accept(visitor);
+ _body.accept(visitor);
}
}
@@ -4903,8 +4897,8 @@
/// part of a top-level getter.
FormalParameterListImpl? _parameters;
- /// The body of the function, or `null` if this is an external function.
- FunctionBodyImpl? _body;
+ /// The body of the function.
+ FunctionBodyImpl _body;
@override
ExecutableElement? declaredElement;
@@ -4922,20 +4916,16 @@
return _typeParameters!.beginToken;
} else if (_parameters != null) {
return _parameters!.beginToken;
- } else if (_body != null) {
- return _body!.beginToken;
}
- // This should never be reached because external functions must be named,
- // hence either the body or the name should be non-null.
- throw StateError("Non-external functions must have a body");
+ return _body.beginToken;
}
@override
- FunctionBody? get body => _body;
+ FunctionBody get body => _body;
@override
- set body(FunctionBody? functionBody) {
- _body = _becomeParentOf(functionBody as FunctionBodyImpl?);
+ set body(FunctionBody functionBody) {
+ _body = _becomeParentOf(functionBody as FunctionBodyImpl);
}
@override
@@ -4944,14 +4934,7 @@
@override
Token get endToken {
- if (_body != null) {
- return _body!.endToken;
- } else if (_parameters != null) {
- return _parameters!.endToken;
- }
- // This should never be reached because external functions must be named,
- // hence either the body or the name should be non-null.
- throw StateError("Non-external functions must have a body");
+ return _body.endToken;
}
@override
@@ -4980,7 +4963,7 @@
void visitChildren(AstVisitor visitor) {
_typeParameters?.accept(visitor);
_parameters?.accept(visitor);
- _body?.accept(visitor);
+ _body.accept(visitor);
}
}
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index dca4023..9caaf9f 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -273,7 +273,7 @@
separator,
initializers,
redirectedConstructor as ConstructorNameImpl?,
- body as FunctionBodyImpl?);
+ body as FunctionBodyImpl);
@override
ConstructorFieldInitializer constructorFieldInitializer(
@@ -607,9 +607,9 @@
@override
FunctionExpression functionExpression(TypeParameterList? typeParameters,
- FormalParameterList? parameters, FunctionBody? body) =>
+ FormalParameterList? parameters, FunctionBody body) =>
FunctionExpressionImpl(typeParameters as TypeParameterListImpl?,
- parameters as FormalParameterListImpl?, body as FunctionBodyImpl?);
+ parameters as FormalParameterListImpl?, body as FunctionBodyImpl);
@override
FunctionExpressionInvocation functionExpressionInvocation(Expression function,
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 199a37f..4335edf 100644
--- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
@@ -333,7 +333,7 @@
safelyVisitNode(node.parameters);
safelyVisitNodeListWithSeparatorAndPrefix(" : ", node.initializers, ", ");
safelyVisitNodeWithPrefix(" = ", node.redirectedConstructor);
- safelyVisitFunctionWithPrefix(" ", node.body!);
+ safelyVisitFunctionWithPrefix(" ", node.body);
}
@override
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index d837988..abae5f8 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -322,7 +322,7 @@
cloneNullableToken(node.separator),
cloneNodeList(node.initializers),
cloneNullableNode(node.redirectedConstructor),
- cloneNullableNode(node.body));
+ cloneNode(node.body));
@override
ConstructorFieldInitializer visitConstructorFieldInitializer(
@@ -573,7 +573,7 @@
@override
FunctionExpression visitFunctionExpression(FunctionExpression node) =>
astFactory.functionExpression(cloneNullableNode(node.typeParameters),
- cloneNullableNode(node.parameters), cloneNullableNode(node.body));
+ cloneNullableNode(node.parameters), cloneNode(node.body));
@override
FunctionExpressionInvocation visitFunctionExpressionInvocation(
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
index 3f8499f..3462422 100644
--- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -95,11 +95,12 @@
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
- if (node.constKeyword != null) {
+ var constKeyword = node.constKeyword;
+ if (constKeyword != null) {
_validateConstructorInitializers(node);
if (node.factoryKeyword == null) {
_validateFieldInitializers(
- node.parent as ClassOrMixinDeclaration, node);
+ node.parent as ClassOrMixinDeclaration, constKeyword);
}
}
_validateDefaultValues(node.parameters);
@@ -148,7 +149,6 @@
var verifier = _ConstLiteralVerifier(
this,
errorCode: CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT,
- forList: true,
listElementType: elementType,
);
for (CollectionElement element in node.elements) {
@@ -170,19 +170,16 @@
if (node.isConst) {
var nodeType = node.staticType as InterfaceType;
var elementType = nodeType.typeArguments[0];
- var duplicateElements = <Expression, Expression>{};
+ var config = _SetVerifierConfig(elementType: elementType);
var verifier = _ConstLiteralVerifier(
this,
errorCode: CompileTimeErrorCode.NON_CONSTANT_SET_ELEMENT,
- forSet: true,
- setElementType: elementType,
- setUniqueValues: <DartObject, Expression>{},
- setDuplicateExpressions: duplicateElements,
+ setConfig: config,
);
for (CollectionElement element in node.elements) {
verifier.verify(element);
}
- for (var duplicateEntry in duplicateElements.entries) {
+ for (var duplicateEntry in config.duplicateElements.entries) {
_errorReporter.reportError(_diagnosticFactory.equalElementsInConstSet(
_errorReporter.source, duplicateEntry.key, duplicateEntry.value));
}
@@ -193,21 +190,20 @@
var keyType = nodeType.typeArguments[0];
var valueType = nodeType.typeArguments[1];
bool reportEqualKeys = true;
- var duplicateKeyElements = <Expression, Expression>{};
+ var config = _MapVerifierConfig(
+ keyType: keyType,
+ valueType: valueType,
+ );
var verifier = _ConstLiteralVerifier(
this,
errorCode: CompileTimeErrorCode.NON_CONSTANT_MAP_ELEMENT,
- forMap: true,
- mapKeyType: keyType,
- mapValueType: valueType,
- mapUniqueKeys: <DartObject, Expression>{},
- mapDuplicateKeyExpressions: duplicateKeyElements,
+ mapConfig: config,
);
for (CollectionElement entry in node.elements) {
verifier.verify(entry);
}
if (reportEqualKeys) {
- for (var duplicateEntry in duplicateKeyElements.entries) {
+ for (var duplicateEntry in config.duplicateKeys.entries) {
_errorReporter.reportError(_diagnosticFactory.equalKeysInConstMap(
_errorReporter.source,
duplicateEntry.key,
@@ -484,8 +480,8 @@
///
/// @param classDeclaration the class which should be validated
/// @param errorSite the site at which errors should be reported.
- void _validateFieldInitializers(ClassOrMixinDeclaration classDeclaration,
- ConstructorDeclaration errorSite) {
+ void _validateFieldInitializers(
+ ClassOrMixinDeclaration classDeclaration, Token constKeyword) {
NodeList<ClassMember> members = classDeclaration.members;
for (ClassMember member in members) {
if (member is FieldDeclaration && !member.isStatic) {
@@ -508,7 +504,7 @@
_errorReporter.reportErrorForToken(
CompileTimeErrorCode
.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
- errorSite.constKeyword!,
+ constKeyword,
[variableDeclaration.name.name]);
}
}
@@ -618,62 +614,34 @@
class _ConstLiteralVerifier {
final ConstantVerifier verifier;
- final Map<DartObject, Expression>? mapUniqueKeys;
- final Map<Expression, Expression>? mapDuplicateKeyExpressions;
final ErrorCode errorCode;
final DartType? listElementType;
- final DartType? mapKeyType;
- final DartType? mapValueType;
- final DartType? setElementType;
- final Map<DartObject, Expression>? setUniqueValues;
- final Map<Expression, Expression>? setDuplicateExpressions;
- final bool forList;
- final bool forMap;
- final bool forSet;
+ final _SetVerifierConfig? setConfig;
+ final _MapVerifierConfig? mapConfig;
_ConstLiteralVerifier(
this.verifier, {
- this.mapUniqueKeys,
- this.mapDuplicateKeyExpressions,
required this.errorCode,
this.listElementType,
- this.mapKeyType,
- this.mapValueType,
- this.setElementType,
- this.setUniqueValues,
- this.setDuplicateExpressions,
- this.forList = false,
- this.forMap = false,
- this.forSet = false,
+ this.mapConfig,
+ this.setConfig,
});
- ErrorCode? get _fromDeferredErrorCode {
- if (forList) {
- return CompileTimeErrorCode
- .NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRARY;
- } else if (forSet) {
- return CompileTimeErrorCode.SET_ELEMENT_FROM_DEFERRED_LIBRARY;
- }
-
- return null;
- }
-
bool verify(CollectionElement element) {
if (element is Expression) {
var value = verifier._validate(element, errorCode);
if (value == null) return false;
- if (_fromDeferredErrorCode != null) {
- verifier._reportErrorIfFromDeferredLibrary(
- element, _fromDeferredErrorCode!);
+ _validateExpressionFromDeferredLibrary(element);
+
+ var listElementType = this.listElementType;
+ if (listElementType != null) {
+ return _validateListExpression(listElementType, element, value);
}
- if (forList) {
- return _validateListExpression(element, value);
- }
-
- if (forSet) {
- return _validateSetExpression(element, value);
+ var setConfig = this.setConfig;
+ if (setConfig != null) {
+ return _validateSetExpression(setConfig, element, value);
}
return true;
@@ -692,15 +660,17 @@
var thenValid = true;
var elseValid = true;
+ var thenElement = element.thenElement;
+ var elseElement = element.elseElement;
if (conditionBool) {
- thenValid = verify(element.thenElement);
- if (element.elseElement != null) {
- elseValid = _reportNotPotentialConstants(element.elseElement!);
+ thenValid = verify(thenElement);
+ if (elseElement != null) {
+ elseValid = _reportNotPotentialConstants(elseElement);
}
} else {
- thenValid = _reportNotPotentialConstants(element.thenElement);
- if (element.elseElement != null) {
- elseValid = verify(element.elseElement!);
+ thenValid = _reportNotPotentialConstants(thenElement);
+ if (elseElement != null) {
+ elseValid = verify(elseElement);
}
}
@@ -714,12 +684,13 @@
verifier._reportErrorIfFromDeferredLibrary(element.expression,
CompileTimeErrorCode.SPREAD_EXPRESSION_FROM_DEFERRED_LIBRARY);
- if (forList || forSet) {
+ if (listElementType != null || setConfig != null) {
return _validateListOrSetSpread(element, value);
}
- if (forMap) {
- return _validateMapSpread(element, value);
+ var mapConfig = this.mapConfig;
+ if (mapConfig != null) {
+ return _validateMapSpread(mapConfig, element, value);
}
return true;
@@ -739,9 +710,9 @@
for (var notConst in notPotentiallyConstants) {
CompileTimeErrorCode errorCode;
- if (forList) {
+ if (listElementType != null) {
errorCode = CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT;
- } else if (forMap) {
+ } else if (mapConfig != null) {
errorCode = CompileTimeErrorCode.NON_CONSTANT_MAP_ELEMENT;
for (AstNode? parent = notConst;
parent != null;
@@ -755,7 +726,7 @@
break;
}
}
- } else if (forSet) {
+ } else if (setConfig != null) {
errorCode = CompileTimeErrorCode.NON_CONSTANT_SET_ELEMENT;
} else {
throw UnimplementedError();
@@ -766,8 +737,23 @@
return false;
}
- bool _validateListExpression(Expression expression, DartObjectImpl value) {
- if (!verifier._runtimeTypeMatch(value, listElementType!)) {
+ void _validateExpressionFromDeferredLibrary(Expression expression) {
+ if (listElementType != null) {
+ verifier._reportErrorIfFromDeferredLibrary(
+ expression,
+ CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRARY,
+ );
+ } else if (setConfig != null) {
+ verifier._reportErrorIfFromDeferredLibrary(
+ expression,
+ CompileTimeErrorCode.SET_ELEMENT_FROM_DEFERRED_LIBRARY,
+ );
+ }
+ }
+
+ bool _validateListExpression(
+ DartType listElementType, Expression expression, DartObjectImpl value) {
+ if (!verifier._runtimeTypeMatch(value, listElementType)) {
verifier._errorReporter.reportErrorForNode(
CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE,
expression,
@@ -787,9 +773,10 @@
bool _validateListOrSetSpread(SpreadElement element, DartObjectImpl value) {
var listValue = value.toListValue();
var setValue = value.toSetValue();
+ var iterableValue = listValue ?? setValue;
- if (listValue == null && setValue == null) {
- if (value.isNull && _isNullableSpread(element)) {
+ if (iterableValue == null) {
+ if (value.isNull && element.isNullAware) {
return true;
}
verifier._errorReporter.reportErrorForNode(
@@ -811,14 +798,15 @@
}
}
- if (forSet) {
- var iterableValue = (listValue ?? setValue)!;
+ var setConfig = this.setConfig;
+ if (setConfig != null) {
for (var item in iterableValue) {
Expression expression = element.expression;
- if (setUniqueValues!.containsKey(item)) {
- setDuplicateExpressions![expression] = setUniqueValues![item]!;
+ var existingValue = setConfig.uniqueValues[item];
+ if (existingValue != null) {
+ setConfig.duplicateElements[expression] = existingValue;
} else {
- setUniqueValues![item] = expression;
+ setConfig.uniqueValues[item] = expression;
}
}
}
@@ -827,7 +815,8 @@
}
bool _validateMapLiteralEntry(MapLiteralEntry entry) {
- if (!forMap) return false;
+ var config = mapConfig;
+ if (config == null) return false;
var keyExpression = entry.key;
var valueExpression = entry.value;
@@ -844,11 +833,11 @@
if (keyValue != null) {
var keyType = keyValue.type;
- if (!verifier._runtimeTypeMatch(keyValue, mapKeyType!)) {
+ if (!verifier._runtimeTypeMatch(keyValue, config.keyType)) {
verifier._errorReporter.reportErrorForNode(
CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE,
keyExpression,
- [keyType, mapKeyType],
+ [keyType, config.keyType],
);
}
@@ -865,19 +854,20 @@
CompileTimeErrorCode.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY,
);
- if (mapUniqueKeys!.containsKey(keyValue)) {
- mapDuplicateKeyExpressions![keyExpression] = mapUniqueKeys![keyValue]!;
+ var existingKey = config.uniqueKeys[keyValue];
+ if (existingKey != null) {
+ config.duplicateKeys[keyExpression] = existingKey;
} else {
- mapUniqueKeys![keyValue] = keyExpression;
+ config.uniqueKeys[keyValue] = keyExpression;
}
}
if (valueValue != null) {
- if (!verifier._runtimeTypeMatch(valueValue, mapValueType!)) {
+ if (!verifier._runtimeTypeMatch(valueValue, config.valueType)) {
verifier._errorReporter.reportErrorForNode(
CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE,
valueExpression,
- [valueValue.type, mapValueType],
+ [valueValue.type, config.valueType],
);
}
@@ -890,8 +880,12 @@
return true;
}
- bool _validateMapSpread(SpreadElement element, DartObjectImpl value) {
- if (value.isNull && _isNullableSpread(element)) {
+ bool _validateMapSpread(
+ _MapVerifierConfig config,
+ SpreadElement element,
+ DartObjectImpl value,
+ ) {
+ if (value.isNull && element.isNullAware) {
return true;
}
var map = value.toMapValue();
@@ -901,11 +895,11 @@
// value being referenced might not be located there (if it's referenced
// through a const variable).
for (var keyValue in map.keys) {
- if (mapUniqueKeys!.containsKey(keyValue)) {
- mapDuplicateKeyExpressions![element.expression] =
- mapUniqueKeys![keyValue]!;
+ var existingKey = config.uniqueKeys[keyValue];
+ if (existingKey != null) {
+ config.duplicateKeys[element.expression] = existingKey;
} else {
- mapUniqueKeys![keyValue] = element.expression;
+ config.uniqueKeys[keyValue] = element.expression;
}
}
return true;
@@ -917,12 +911,16 @@
return false;
}
- bool _validateSetExpression(Expression expression, DartObjectImpl value) {
- if (!verifier._runtimeTypeMatch(value, setElementType!)) {
+ bool _validateSetExpression(
+ _SetVerifierConfig config,
+ Expression expression,
+ DartObjectImpl value,
+ ) {
+ if (!verifier._runtimeTypeMatch(value, config.elementType)) {
verifier._errorReporter.reportErrorForNode(
CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE,
expression,
- [value.type, setElementType],
+ [value.type, config.elementType],
);
return false;
}
@@ -941,17 +939,35 @@
CompileTimeErrorCode.SET_ELEMENT_FROM_DEFERRED_LIBRARY,
);
- if (setUniqueValues!.containsKey(value)) {
- setDuplicateExpressions![expression] = setUniqueValues![value]!;
+ var existingValue = config.uniqueValues[value];
+ if (existingValue != null) {
+ config.duplicateElements[expression] = existingValue;
} else {
- setUniqueValues![value] = expression;
+ config.uniqueValues[value] = expression;
}
return true;
}
+}
- static bool _isNullableSpread(SpreadElement element) {
- return element.spreadOperator.type ==
- TokenType.PERIOD_PERIOD_PERIOD_QUESTION;
- }
+class _MapVerifierConfig {
+ final DartType keyType;
+ final DartType valueType;
+ final Map<DartObject, Expression> uniqueKeys = {};
+ final Map<Expression, Expression> duplicateKeys = {};
+
+ _MapVerifierConfig({
+ required this.keyType,
+ required this.valueType,
+ });
+}
+
+class _SetVerifierConfig {
+ final DartType elementType;
+ final Map<DartObject, Expression> uniqueValues = {};
+ final Map<Expression, Expression> duplicateElements = {};
+
+ _SetVerifierConfig({
+ required this.elementType,
+ });
}
diff --git a/pkg/analyzer/lib/src/dart/element/extensions.dart b/pkg/analyzer/lib/src/dart/element/extensions.dart
index f600bd9..66ba586 100644
--- a/pkg/analyzer/lib/src/dart/element/extensions.dart
+++ b/pkg/analyzer/lib/src/dart/element/extensions.dart
@@ -32,13 +32,20 @@
if (hasDoNotStore) {
return true;
}
+
var ancestor = enclosingElement;
- if (ancestor is ClassElement || ancestor is ExtensionElement) {
- if (ancestor!.hasDoNotStore) {
+ if (ancestor is ClassElement) {
+ if (ancestor.hasDoNotStore) {
+ return true;
+ }
+ ancestor = ancestor.enclosingElement;
+ } else if (ancestor is ExtensionElement) {
+ if (ancestor.hasDoNotStore) {
return true;
}
ancestor = ancestor.enclosingElement;
}
+
return ancestor is CompilationUnitElement &&
ancestor.enclosingElement.hasDoNotStore;
}
diff --git a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
index 530ff1f..4a7f9eb 100644
--- a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
+++ b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
@@ -140,10 +140,12 @@
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
Workspace _buildWorkspace() {
- String path = contextRoot.root.path;
- ContextBuilder builder = ContextBuilder(
- resourceProvider, null /* sdkManager */, null /* contentCache */);
- return ContextBuilder.createWorkspace(resourceProvider, path, builder);
+ var path = contextRoot.root.path;
+ return ContextBuilder.createWorkspace(
+ resourceProvider: resourceProvider,
+ options: ContextBuilderOptions(),
+ rootPath: path,
+ );
}
}
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 f60d683..3b2ef9e 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
@@ -36,7 +36,7 @@
void resolve(FunctionExpression node) {
var isFunctionDeclaration = node.parent is FunctionDeclaration;
- var body = node.body!;
+ var body = node.body;
if (_resolver.flowAnalysis != null) {
if (_resolver.flowAnalysis!.flow != null && !isFunctionDeclaration) {
@@ -64,7 +64,7 @@
if (_resolver.flowAnalysis != null) {
if (_resolver.flowAnalysis!.flow != null && !isFunctionDeclaration) {
- var bodyContext = BodyInferenceContext.of(node.body!);
+ var bodyContext = BodyInferenceContext.of(node.body);
_resolver.checkForBodyMayCompleteNormally(
returnType: bodyContext?.contextType,
body: body,
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
index b5eef7b..033fd97 100644
--- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
@@ -297,7 +297,7 @@
_resolveRedirectedConstructor(node);
node.initializers.accept(this);
- node.body?.accept(this);
+ node.body.accept(this);
});
});
});
@@ -513,7 +513,7 @@
setElementDocumentationComment(element, node);
element.metadata = _createElementAnnotations(node.metadata);
- var body = node.functionExpression.body as FunctionBody;
+ var body = node.functionExpression.body;
if (node.externalKeyword != null || body is NativeFunctionBody) {
element.isExternal = true;
}
@@ -555,7 +555,7 @@
_defineParameters(element.parameters);
_withElementWalker(null, () {
- expression.body!.accept(this);
+ expression.body.accept(this);
});
});
},
@@ -581,7 +581,7 @@
element.hasImplicitReturnType = true;
element.returnType = DynamicTypeImpl.instance;
- FunctionBody body = node.body!;
+ FunctionBody body = node.body;
element.isAsynchronous = body.isAsynchronous;
element.isGenerator = body.isGenerator;
@@ -596,7 +596,7 @@
element.parameters = holder.parameters;
_defineParameters(element.parameters);
- node.body!.accept(this);
+ node.body.accept(this);
});
});
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index 6b1b894..b3136ff 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -341,14 +341,14 @@
if (!_isNonNullableByDefault && node.declaredElement!.isFactory) {
if (node.body is BlockFunctionBody) {
// Check the block for a return statement, if not, create the hint.
- if (!ExitDetector.exits(node.body!)) {
+ if (!ExitDetector.exits(node.body)) {
_errorReporter.reportErrorForNode(
HintCode.MISSING_RETURN, node, [node.returnType.name]);
}
}
}
_checkStrictInferenceInParameters(node.parameters,
- body: node.body!, initializers: node.initializers);
+ body: node.body, initializers: node.initializers);
super.visitConstructorDeclaration(node);
}
@@ -429,7 +429,7 @@
_inDoNotStoreMember = true;
}
try {
- _checkForMissingReturn(node.functionExpression.body!, node);
+ _checkForMissingReturn(node.functionExpression.body, node);
// Return types are inferred only on non-recursive local functions.
if (node.parent is CompilationUnit && !node.isSetter) {
@@ -454,7 +454,7 @@
@override
void visitFunctionExpression(FunctionExpression node) {
if (node.parent is! FunctionDeclaration) {
- _checkForMissingReturn(node.body!, node);
+ _checkForMissingReturn(node.body, node);
}
var functionType = InferenceContext.getContext(node);
if (functionType is! FunctionType) {
diff --git a/pkg/analyzer/lib/src/error/catch_error_verifier.dart b/pkg/analyzer/lib/src/error/catch_error_verifier.dart
index 08a8a52..42a6dc4 100644
--- a/pkg/analyzer/lib/src/error/catch_error_verifier.dart
+++ b/pkg/analyzer/lib/src/error/catch_error_verifier.dart
@@ -62,7 +62,7 @@
var returnStatementVerifier =
_ReturnStatementVerifier(_returnTypeVerifier);
_returnTypeVerifier.enclosingExecutable = catchErrorOnErrorExecutable;
- callback.body!.accept(returnStatementVerifier);
+ callback.body.accept(returnStatementVerifier);
} else {
var callbackType = callback.staticType;
if (callbackType is FunctionType) {
diff --git a/pkg/analyzer/lib/src/error/dead_code_verifier.dart b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
index bce84b9..eea542d 100644
--- a/pkg/analyzer/lib/src/error/dead_code_verifier.dart
+++ b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
@@ -31,18 +31,18 @@
final ErrorReporter _errorReporter;
/// The object used to track the usage of labels within a given label scope.
- _LabelTracker? labelTracker;
+ _LabelTracker? _labelTracker;
DeadCodeVerifier(this._errorReporter);
@override
void visitBreakStatement(BreakStatement node) {
- labelTracker?.recordUsage(node.label?.name);
+ _labelTracker?.recordUsage(node.label?.name);
}
@override
void visitContinueStatement(ContinueStatement node) {
- labelTracker?.recordUsage(node.label?.name);
+ _labelTracker?.recordUsage(node.label?.name);
}
@override
@@ -78,12 +78,9 @@
@override
void visitLabeledStatement(LabeledStatement node) {
- _pushLabels(node.labels);
- try {
+ _withLabelTracker(node.labels, () {
super.visitLabeledStatement(node);
- } finally {
- _popLabels();
- }
+ });
}
@override
@@ -92,12 +89,9 @@
for (SwitchMember member in node.members) {
labels.addAll(member.labels);
}
- _pushLabels(labels);
- try {
+ _withLabelTracker(labels, () {
super.visitSwitchStatement(node);
- } finally {
- _popLabels();
- }
+ });
}
/// Resolve the names in the given [combinator] in the scope of the given
@@ -125,19 +119,18 @@
}
}
- /// Exit the most recently entered label scope after reporting any labels that
- /// were not referenced within that scope.
- void _popLabels() {
- for (Label label in labelTracker!.unusedLabels()) {
- _errorReporter
- .reportErrorForNode(HintCode.UNUSED_LABEL, label, [label.label.name]);
+ void _withLabelTracker(List<Label> labels, void Function() f) {
+ var labelTracker = _LabelTracker(_labelTracker, labels);
+ try {
+ _labelTracker = labelTracker;
+ f();
+ } finally {
+ for (Label label in labelTracker.unusedLabels()) {
+ _errorReporter.reportErrorForNode(
+ HintCode.UNUSED_LABEL, label, [label.label.name]);
+ }
+ _labelTracker = labelTracker.outerTracker;
}
- labelTracker = labelTracker!.outerTracker;
- }
-
- /// Enter a new label scope in which the given [labels] are defined.
- void _pushLabels(List<Label> labels) {
- labelTracker = _LabelTracker(labelTracker, labels);
}
}
@@ -491,13 +484,14 @@
/// not `null`, and is covered by the [node], then we reached the end of
/// the current dead code interval.
void flowEnd(AstNode node) {
- if (_firstDeadNode != null) {
+ var firstDeadNode = _firstDeadNode;
+ if (firstDeadNode != null) {
if (!_containsFirstDeadNode(node)) {
return;
}
- var parent = _firstDeadNode!.parent;
- if (parent is Assertion && identical(_firstDeadNode, parent.message)) {
+ var parent = firstDeadNode.parent;
+ if (parent is Assertion && identical(firstDeadNode, parent.message)) {
// Don't report "dead code" for the message part of an assert statement,
// because this causes nuisance warnings for redundant `!= null`
// asserts.
@@ -505,12 +499,12 @@
// We know that [node] is the first dead node, or contains it.
// So, technically the code code interval ends at the end of [node].
// But we trim it to the last statement for presentation purposes.
- if (node != _firstDeadNode) {
+ if (node != firstDeadNode) {
if (node is FunctionDeclaration) {
- node = node.functionExpression.body!;
+ node = node.functionExpression.body;
}
if (node is FunctionExpression) {
- node = node.body!;
+ node = node.body;
}
if (node is MethodDeclaration) {
node = node.body;
@@ -526,7 +520,7 @@
}
}
- var offset = _firstDeadNode!.offset;
+ var offset = firstDeadNode.offset;
var length = node.end - offset;
_errorReporter.reportErrorForOffset(HintCode.DEAD_CODE, offset, length);
}
@@ -570,10 +564,11 @@
// So, they look unreachable, but this does not make sense.
if (node is Comment) return;
- if (_flowAnalysis == null) return;
- _flowAnalysis!.checkUnreachableNode(node);
+ var flowAnalysis = _flowAnalysis;
+ if (flowAnalysis == null) return;
+ flowAnalysis.checkUnreachableNode(node);
- var flow = _flowAnalysis!.flow;
+ var flow = flowAnalysis.flow;
if (flow == null) return;
if (flow.isReachable) return;
@@ -678,8 +673,8 @@
var index = labelMap[labelName];
if (index != null) {
used[index] = true;
- } else if (outerTracker != null) {
- outerTracker!.recordUsage(labelName);
+ } else {
+ outerTracker?.recordUsage(labelName);
}
}
}
diff --git a/pkg/analyzer/lib/src/error/must_call_super_verifier.dart b/pkg/analyzer/lib/src/error/must_call_super_verifier.dart
index ad1ca30..7898133 100644
--- a/pkg/analyzer/lib/src/error/must_call_super_verifier.dart
+++ b/pkg/analyzer/lib/src/error/must_call_super_verifier.dart
@@ -91,8 +91,9 @@
.any(isConcrete)) {
return true;
}
- if (classElement.supertype != null &&
- isConcrete(classElement.supertype!.element)) {
+
+ var supertype = classElement.supertype;
+ if (supertype != null && isConcrete(supertype.element)) {
return true;
}
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index f0cf878..a90f3ab 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -523,7 +523,7 @@
var element = node.declaredElement!;
_withEnclosingExecutable(element, () {
_checkForInvalidModifierOnBody(
- node.body!, CompileTimeErrorCode.INVALID_MODIFIER_ON_CONSTRUCTOR);
+ node.body, CompileTimeErrorCode.INVALID_MODIFIER_ON_CONSTRUCTOR);
_checkForConstConstructorWithNonFinalField(node, element);
_checkForConstConstructorWithNonConstSuper(node);
_constructorFieldsVerifier.verify(node);
@@ -4077,7 +4077,7 @@
return;
}
// block body (with possible return statement) is checked elsewhere
- FunctionBody body = declaration.body!;
+ FunctionBody body = declaration.body;
if (body is! ExpressionFunctionBody) {
return;
}
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index 16e000f..9b71259 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -18,7 +18,7 @@
static const _allocatorClassName = 'Allocator';
static const _allocateExtensionMethodName = 'call';
static const _allocatorExtensionName = 'AllocatorAlloc';
- static const _carrayClassName = 'CArray';
+ static const _cArrayClassName = 'CArray';
static const _dartFfiLibraryName = 'dart.ffi';
static const _opaqueClassName = 'Opaque';
@@ -61,11 +61,12 @@
var extendsClause = node.extendsClause;
if (extendsClause != null) {
final TypeName superclass = extendsClause.superclass;
- if (_isDartFfiClass(superclass)) {
- final className = superclass.name.staticElement!.name;
+ final ffiClass = superclass.ffiClass;
+ if (ffiClass != null) {
+ final className = ffiClass.name;
if (className == _structClassName) {
inStruct = true;
- if (_isEmptyStruct(node.declaredElement!)) {
+ if (node.declaredElement!.isEmptyStruct) {
_errorReporter.reportErrorForNode(
FfiCode.EMPTY_STRUCT_WARNING, node, [node.name]);
}
@@ -76,7 +77,7 @@
superclass.name,
[node.name.name, superclass.name.name]);
}
- } else if (_isSubtypeOfStruct(superclass)) {
+ } else if (superclass.isStructSubtype) {
_errorReporter.reportErrorForNode(
FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS,
superclass,
@@ -91,10 +92,10 @@
if (superName == _allocatorClassName) {
return;
}
- if (_isDartFfiClass(typename)) {
+ if (typename.ffiClass != null) {
_errorReporter.reportErrorForNode(
subtypeOfFfiCode, typename, [node.name, typename.name]);
- } else if (_isSubtypeOfStruct(typename)) {
+ } else if (typename.isStructSubtype) {
_errorReporter.reportErrorForNode(
subtypeOfStructCode, typename, [node.name, typename.name]);
}
@@ -144,11 +145,9 @@
var element = node.staticElement;
if (element is MethodElement) {
var enclosingElement = element.enclosingElement;
- if (enclosingElement is ExtensionElement) {
- if (_isAllocatorExtension(enclosingElement) &&
- element.name == _allocateExtensionMethodName) {
- _validateAllocate(node);
- }
+ if (enclosingElement.isAllocatorExtension &&
+ element.name == _allocateExtensionMethodName) {
+ _validateAllocate(node);
}
}
super.visitFunctionExpressionInvocation(node);
@@ -159,12 +158,10 @@
var element = node.staticElement;
if (element is MethodElement) {
var enclosingElement = element.enclosingElement;
- if (enclosingElement is ExtensionElement) {
- if (_isNativeStructPointerExtension(enclosingElement) ||
- _isNativeStructCArrayExtension(enclosingElement)) {
- if (element.name == '[]') {
- _validateRefIndexed(node);
- }
+ if (enclosingElement.isNativeStructPointerExtension ||
+ enclosingElement.isNativeStructCArrayExtension) {
+ if (element.name == '[]') {
+ _validateRefIndexed(node);
}
}
}
@@ -175,22 +172,18 @@
var element = node.methodName.staticElement;
if (element is MethodElement) {
Element enclosingElement = element.enclosingElement;
- if (enclosingElement is ClassElement) {
- if (_isPointer(enclosingElement)) {
- if (element.name == 'fromFunction') {
- _validateFromFunction(node, element);
- } else if (element.name == 'elementAt') {
- _validateElementAt(node);
- }
+ if (enclosingElement.isPointer) {
+ if (element.name == 'fromFunction') {
+ _validateFromFunction(node, element);
+ } else if (element.name == 'elementAt') {
+ _validateElementAt(node);
}
- }
- if (enclosingElement is ExtensionElement) {
- if (_isNativeFunctionPointerExtension(enclosingElement)) {
- if (element.name == 'asFunction') {
- _validateAsFunction(node, element);
- }
- } else if (_isDynamicLibraryExtension(enclosingElement) &&
- element.name == 'lookupFunction') {
+ } else if (enclosingElement.isNativeFunctionPointerExtension) {
+ if (element.name == 'asFunction') {
+ _validateAsFunction(node, element);
+ }
+ } else if (enclosingElement.isDynamicLibraryExtension) {
+ if (element.name == 'lookupFunction') {
_validateLookupFunction(node);
}
}
@@ -212,11 +205,9 @@
var element = node.staticElement;
if (element != null) {
var enclosingElement = element.enclosingElement;
- if (enclosingElement is ExtensionElement) {
- if (_isNativeStructPointerExtension(enclosingElement)) {
- if (element.name == 'ref') {
- _validateRefPrefixedIdentifier(node);
- }
+ if (enclosingElement.isNativeStructPointerExtension) {
+ if (element.name == 'ref') {
+ _validateRefPrefixedIdentifier(node);
}
}
}
@@ -228,140 +219,15 @@
var element = node.propertyName.staticElement;
if (element != null) {
var enclosingElement = element.enclosingElement;
- if (enclosingElement is ExtensionElement) {
- if (_isNativeStructPointerExtension(enclosingElement)) {
- if (element.name == 'ref') {
- _validateRefPropertyAccess(node);
- }
+ if (enclosingElement.isNativeStructPointerExtension) {
+ if (element.name == 'ref') {
+ _validateRefPropertyAccess(node);
}
}
}
super.visitPropertyAccess(node);
}
- /// Return `true` if the given [element] represents the extension
- /// `AllocatorAlloc`.
- bool _isAllocatorExtension(Element element) =>
- element.name == _allocatorExtensionName &&
- element.library?.name == _dartFfiLibraryName;
-
- /// Return `true` if the given [element] represents the class `CArray`.
- bool _isCArray(Element? element) =>
- element != null &&
- element.name == _carrayClassName &&
- element.library?.name == _dartFfiLibraryName;
-
- /// Return `true` if the [typeName] is the name of a type from `dart:ffi`.
- bool _isDartFfiClass(TypeName typeName) =>
- _isDartFfiElement(typeName.name.staticElement);
-
- /// Return `true` if the [element] is a class element from `dart:ffi`.
- bool _isDartFfiElement(Element? element) {
- if (element is ConstructorElement) {
- element = element.enclosingElement;
- }
- return element is ClassElement &&
- element.library.name == _dartFfiLibraryName;
- }
-
- /// Return `true` if the given [element] represents the extension
- /// `DynamicLibraryExtension`.
- bool _isDynamicLibraryExtension(Element element) =>
- element.name == 'DynamicLibraryExtension' &&
- element.library?.name == _dartFfiLibraryName;
-
- bool _isEmptyStruct(ClassElement classElement) {
- final fields = classElement.fields;
- var structFieldCount = 0;
- for (final field in fields) {
- final declaredType = field.type;
- if (declaredType.isDartCoreInt) {
- structFieldCount++;
- } else if (declaredType.isDartCoreDouble) {
- structFieldCount++;
- } else if (_isPointer(declaredType.element)) {
- structFieldCount++;
- } else if (_isStructClass(declaredType)) {
- structFieldCount++;
- } else if (_isCArray(declaredType.element)) {
- structFieldCount++;
- }
- }
- return structFieldCount == 0;
- }
-
- bool _isHandle(Element? element) =>
- element != null &&
- element.name == 'Handle' &&
- element.library?.name == _dartFfiLibraryName;
-
- /// Returns `true` iff [nativeType] is a `ffi.NativeFunction<???>` type.
- bool _isNativeFunctionInterfaceType(DartType nativeType) {
- if (nativeType is InterfaceType) {
- final element = nativeType.element;
- if (element.library.name == _dartFfiLibraryName) {
- return element.name == 'NativeFunction' &&
- nativeType.typeArguments.length == 1;
- }
- }
- return false;
- }
-
- bool _isNativeFunctionPointerExtension(Element? element) =>
- element != null &&
- element.name == 'NativeFunctionPointer' &&
- element.library?.name == _dartFfiLibraryName;
-
- bool _isNativeStructCArrayExtension(Element element) =>
- element.name == 'StructCArray' && element.library?.name == 'dart.ffi';
-
- bool _isNativeStructPointerExtension(Element element) =>
- element.name == 'StructPointer' && element.library?.name == 'dart.ffi';
-
- /// Returns `true` iff [nativeType] is a `ffi.NativeType` type.
- bool _isNativeTypeInterfaceType(DartType nativeType) {
- if (nativeType is InterfaceType) {
- final element = nativeType.element;
- if (element.library.name == _dartFfiLibraryName) {
- return element.name == 'NativeType';
- }
- }
- return false;
- }
-
- /// Returns `true` iff [nativeType] is a opaque type, i.e. a subtype of `Opaque`.
- bool _isOpaqueClass(DartType nativeType) {
- if (nativeType is InterfaceType) {
- final superType = nativeType.element.supertype;
- if (superType == null) {
- return false;
- }
- final superClassElement = superType.element;
- if (superClassElement.library.name == _dartFfiLibraryName) {
- return superClassElement.name == _opaqueClassName;
- }
- }
- return false;
- }
-
- /// Return `true` if the given [element] represents the class `Pointer`.
- bool _isPointer(Element? element) =>
- element != null &&
- element.name == 'Pointer' &&
- element.library?.name == _dartFfiLibraryName;
-
- /// Returns `true` iff [nativeType] is a `ffi.Pointer<???>` type.
- bool _isPointerInterfaceType(DartType nativeType) {
- if (nativeType is InterfaceType) {
- final element = nativeType.element;
- if (element.library.name == _dartFfiLibraryName) {
- return element.name == 'Pointer' &&
- nativeType.typeArguments.length == 1;
- }
- }
- return false;
- }
-
/// Returns `true` if [nativeType] is a C type that has a size.
bool _isSized(DartType nativeType) {
switch (_primitiveNativeType(nativeType)) {
@@ -376,48 +242,15 @@
case _PrimitiveDartType.none:
break;
}
- if (_isStructClass(nativeType)) {
+ if (nativeType.isStructSubtype) {
return true;
}
- if (_isPointer(nativeType.element)) {
+ if (nativeType.isPointer) {
return true;
}
return false;
}
- /// Returns `true` iff [nativeType] is a struct type.
- bool _isStructClass(DartType nativeType) {
- if (nativeType is InterfaceType) {
- final superType = nativeType.element.supertype;
- if (superType == null) {
- return false;
- }
- final superClassElement = superType.element;
- if (superClassElement.library.name == _dartFfiLibraryName) {
- return superClassElement.name == _structClassName &&
- nativeType.typeArguments.isEmpty;
- }
- }
- return false;
- }
-
- /// Return `true` if the [typeName] represents a subtype of `Struct`.
- bool _isSubtypeOfStruct(TypeName typeName) {
- var superType = typeName.name.staticElement;
- if (superType is ClassElement) {
- bool isStruct(InterfaceType? type) {
- return type != null &&
- type.element.name == _structClassName &&
- type.element.library.name == _dartFfiLibraryName;
- }
-
- return isStruct(superType.supertype) ||
- superType.interfaces.any(isStruct) ||
- superType.mixins.any(isStruct);
- }
- return false;
- }
-
/// Validates that the given type is a valid dart:ffi native function
/// signature.
bool _isValidFfiNativeFunctionType(DartType nativeType) {
@@ -454,19 +287,19 @@
(primitiveType != _PrimitiveDartType.void_ || allowVoid)) {
return true;
}
- if (_isNativeFunctionInterfaceType(nativeType)) {
+ if (nativeType.isNativeFunction) {
return _isValidFfiNativeFunctionType(nativeType.typeArguments.single);
}
- if (_isPointerInterfaceType(nativeType)) {
+ if (nativeType.isPointer) {
final nativeArgumentType = nativeType.typeArguments.single;
return _isValidFfiNativeType(nativeArgumentType,
allowVoid: true, allowEmptyStruct: true) ||
- _isStructClass(nativeArgumentType) ||
- _isNativeTypeInterfaceType(nativeArgumentType);
+ nativeArgumentType.isStructSubtype ||
+ nativeArgumentType.isNativeType;
}
- if (_isStructClass(nativeType)) {
+ if (nativeType.isStructSubtype) {
if (!allowEmptyStruct) {
- if (_isEmptyStruct(nativeType.element)) {
+ if (nativeType.element.isEmptyStruct) {
// TODO(dartbug.com/36780): This results in an error message not
// mentioning empty structs at all.
return false;
@@ -474,10 +307,10 @@
}
return true;
}
- if (_isOpaqueClass(nativeType)) {
+ if (nativeType.isOpaqueSubtype) {
return true;
}
- if (allowCArray && _isCArray(nativeType.element)) {
+ if (allowCArray && nativeType.isCArray) {
return _isValidFfiNativeType(nativeType.typeArguments.single,
allowVoid: false, allowEmptyStruct: false);
}
@@ -490,7 +323,7 @@
_PrimitiveDartType _primitiveNativeType(DartType nativeType) {
if (nativeType is InterfaceType) {
final element = nativeType.element;
- if (element.library.name == _dartFfiLibraryName) {
+ if (element.isFfiClass) {
final String name = element.name;
if (_primitiveIntegerNativeTypes.contains(name)) {
return _PrimitiveDartType.int;
@@ -547,7 +380,7 @@
bool requiredFound = false;
List<Annotation> extraAnnotations = [];
for (Annotation annotation in annotations) {
- if (_isDartFfiElement(annotation.element)) {
+ if (annotation.element.ffiClass != null) {
if (requiredFound) {
extraAnnotations.add(annotation);
} else {
@@ -587,11 +420,9 @@
}
var target = node.realTarget!;
var targetType = target.staticType;
- if (targetType is InterfaceType &&
- _isPointer(targetType.element) &&
- targetType.typeArguments.length == 1) {
+ if (targetType is InterfaceType && targetType.isPointer) {
final DartType T = targetType.typeArguments[0];
- if (!_isNativeFunctionInterfaceType(T) ||
+ if (!T.isNativeFunction ||
!_isValidFfiNativeFunctionType(
(T as InterfaceType).typeArguments.single)) {
final AstNode errorNode =
@@ -688,9 +519,7 @@
void _validateElementAt(MethodInvocation node) {
var targetType = node.realTarget?.staticType;
- if (targetType is InterfaceType &&
- _isPointer(targetType.element) &&
- targetType.typeArguments.length == 1) {
+ if (targetType is InterfaceType && targetType.isPointer) {
final DartType T = targetType.typeArguments[0];
if (!_isValidFfiNativeType(T, allowVoid: true, allowEmptyStruct: true)) {
@@ -721,18 +550,18 @@
_validateAnnotations(fieldType, annotations, _PrimitiveDartType.int);
} else if (declaredType.isDartCoreDouble) {
_validateAnnotations(fieldType, annotations, _PrimitiveDartType.double);
- } else if (_isPointer(declaredType.element)) {
+ } else if (declaredType.isPointer) {
_validateNoAnnotations(annotations);
- } else if (_isCArray(declaredType.element)) {
+ } else if (declaredType.isCArray) {
final typeArg = (declaredType as InterfaceType).typeArguments.single;
if (!_isSized(typeArg)) {
_errorReporter.reportErrorForNode(FfiCode.NON_SIZED_TYPE_ARGUMENT,
- fieldType, [_carrayClassName, typeArg.toString()]);
+ fieldType, [_cArrayClassName, typeArg.toString()]);
}
_validateSizeOfAnnotation(fieldType, annotations);
- } else if (_isStructClass(declaredType)) {
+ } else if (declaredType.isStructSubtype) {
final clazz = (declaredType as InterfaceType).element;
- if (_isEmptyStruct(clazz)) {
+ if (clazz.isEmptyStruct) {
_errorReporter
.reportErrorForNode(FfiCode.EMPTY_STRUCT, node, [clazz.name]);
}
@@ -777,9 +606,9 @@
// TODO(brianwilkerson) Validate that `f` is a top-level function.
final DartType R = (T as FunctionType).returnType;
if ((FT as FunctionType).returnType.isVoid ||
- _isPointer(R.element) ||
- _isHandle(R.element) ||
- _isStructClass(R)) {
+ R.isPointer ||
+ R.isHandle ||
+ R.isStructSubtype) {
if (argCount != 1) {
_errorReporter.reportErrorForNode(
FfiCode.INVALID_EXCEPTION_VALUE, node.argumentList.arguments[1]);
@@ -826,7 +655,7 @@
/// Validate that none of the [annotations] are from `dart:ffi`.
void _validateNoAnnotations(NodeList<Annotation> annotations) {
for (Annotation annotation in annotations) {
- if (_isDartFfiElement(annotation.element)) {
+ if (annotation.element.ffiClass != null) {
_errorReporter.reportErrorForNode(
FfiCode.ANNOTATION_ON_POINTER_FIELD, annotation);
}
@@ -886,7 +715,7 @@
final ffiSizeAnnotations = annotations.where((annotation) {
final element = annotation.element;
return element is ConstructorElement &&
- _isDartFfiElement(element) &&
+ element.ffiClass != null &&
element.enclosingElement.name == 'CArraySize';
}).toList();
@@ -922,3 +751,195 @@
handle,
none,
}
+
+extension on Element? {
+ /// Return `true` if this represents the extension `AllocatorAlloc`.
+ bool get isAllocatorExtension {
+ final element = this;
+ return element is ExtensionElement &&
+ element.name == FfiVerifier._allocatorExtensionName &&
+ element.isFfiExtension;
+ }
+
+ bool get isNativeFunctionPointerExtension {
+ final element = this;
+ return element is ExtensionElement &&
+ element.name == 'NativeFunctionPointer' &&
+ element.isFfiExtension;
+ }
+
+ bool get isNativeStructCArrayExtension {
+ final element = this;
+ return element is ExtensionElement &&
+ element.name == 'StructCArray' &&
+ element.isFfiExtension;
+ }
+
+ bool get isNativeStructPointerExtension {
+ final element = this;
+ return element is ExtensionElement &&
+ element.name == 'StructPointer' &&
+ element.isFfiExtension;
+ }
+
+ /// Return `true` if this represents the extension `DynamicLibraryExtension`.
+ bool get isDynamicLibraryExtension {
+ final element = this;
+ return element is ExtensionElement &&
+ element.name == 'DynamicLibraryExtension' &&
+ element.isFfiExtension;
+ }
+
+ /// Return `true` if this represents the class `Pointer`.
+ bool get isPointer {
+ final element = this;
+ return element is ClassElement &&
+ element.name == 'Pointer' &&
+ element.isFfiClass;
+ }
+
+ /// If this is a class element from `dart:ffi`, return it.
+ ClassElement? get ffiClass {
+ var element = this;
+ if (element is ConstructorElement) {
+ element = element.enclosingElement;
+ }
+ if (element is ClassElement && element.isFfiClass) {
+ return element;
+ }
+ return null;
+ }
+}
+
+extension on ClassElement {
+ bool get isEmptyStruct {
+ for (final field in fields) {
+ final declaredType = field.type;
+ if (declaredType.isDartCoreInt) {
+ return false;
+ } else if (declaredType.isDartCoreDouble) {
+ return false;
+ } else if (declaredType.isPointer) {
+ return false;
+ } else if (declaredType.isStructSubtype) {
+ return false;
+ } else if (declaredType.isCArray) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool get isFfiClass {
+ return library.name == FfiVerifier._dartFfiLibraryName;
+ }
+}
+
+extension on ExtensionElement {
+ bool get isFfiExtension {
+ return library.name == FfiVerifier._dartFfiLibraryName;
+ }
+}
+
+extension on DartType {
+ /// Return `true` if this represents the class `CArray`.
+ bool get isCArray {
+ final self = this;
+ if (self is InterfaceType) {
+ final element = self.element;
+ return element.name == FfiVerifier._cArrayClassName && element.isFfiClass;
+ }
+ return false;
+ }
+
+ bool get isPointer {
+ final self = this;
+ return self is InterfaceType && self.element.isPointer;
+ }
+
+ bool get isHandle {
+ final self = this;
+ if (self is InterfaceType) {
+ final element = self.element;
+ return element.name == 'Handle' && element.isFfiClass;
+ }
+ return false;
+ }
+
+ /// Returns `true` iff this is a `ffi.NativeFunction<???>` type.
+ bool get isNativeFunction {
+ final self = this;
+ if (self is InterfaceType) {
+ final element = self.element;
+ return element.name == 'NativeFunction' && element.isFfiClass;
+ }
+ return false;
+ }
+
+ /// Returns `true` iff this is a `ffi.NativeType` type.
+ bool get isNativeType {
+ final self = this;
+ if (self is InterfaceType) {
+ final element = self.element;
+ return element.name == 'NativeType' && element.isFfiClass;
+ }
+ return false;
+ }
+
+ /// Returns `true` iff this is a opaque type, i.e. a subtype of `Opaque`.
+ bool get isOpaqueSubtype {
+ final self = this;
+ if (self is InterfaceType) {
+ final superType = self.element.supertype;
+ if (superType != null) {
+ final superClassElement = superType.element;
+ return superClassElement.name == FfiVerifier._opaqueClassName &&
+ superClassElement.isFfiClass;
+ }
+ }
+ return false;
+ }
+
+ bool get isStruct {
+ final self = this;
+ if (self is InterfaceType) {
+ final element = self.element;
+ return element.name == FfiVerifier._structClassName && element.isFfiClass;
+ }
+ return false;
+ }
+
+ /// Returns `true` if this is a struct type, i.e. a subtype of `Struct`.
+ bool get isStructSubtype {
+ final self = this;
+ if (self is InterfaceType) {
+ final superType = self.element.supertype;
+ if (superType != null) {
+ return superType.isStruct;
+ }
+ }
+ return false;
+ }
+}
+
+extension on TypeName {
+ /// If this is a name of class from `dart:ffi`, return it.
+ ClassElement? get ffiClass {
+ return name.staticElement.ffiClass;
+ }
+
+ /// Return `true` if this represents a subtype of `Struct`.
+ bool get isStructSubtype {
+ var element = name.staticElement;
+ if (element is ClassElement) {
+ bool isStruct(InterfaceType? type) {
+ return type != null && type.isStruct;
+ }
+
+ return isStruct(element.supertype) ||
+ element.interfaces.any(isStruct) ||
+ element.mixins.any(isStruct);
+ }
+ return false;
+ }
+}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 9e441f9..b648902 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1162,7 +1162,7 @@
flowAnalysis!.topLevelDeclaration_enter(node, node.parameters, node.body);
flowAnalysis!.executableDeclaration_enter(node, node.parameters, false);
} else {
- _promoteManager.enterFunctionBody(node.body!);
+ _promoteManager.enterFunctionBody(node.body);
}
var returnType = _enclosingFunction!.type.returnType;
@@ -1172,14 +1172,14 @@
if (flowAnalysis != null) {
if (node.factoryKeyword != null) {
- var bodyContext = BodyInferenceContext.of(node.body!);
+ var bodyContext = BodyInferenceContext.of(node.body);
checkForBodyMayCompleteNormally(
returnType: bodyContext?.contextType,
- body: node.body!,
+ body: node.body,
errorNode: node,
);
}
- flowAnalysis!.executableDeclaration_exit(node.body!, false);
+ flowAnalysis!.executableDeclaration_exit(node.body, false);
flowAnalysis!.topLevelDeclaration_exit();
nullSafetyDeadCodeVerifier.flowEnd(node);
} else {
@@ -1406,7 +1406,7 @@
isLocal,
);
} else {
- _promoteManager.enterFunctionBody(node.functionExpression.body!);
+ _promoteManager.enterFunctionBody(node.functionExpression.body);
}
var functionType = _enclosingFunction!.type;
@@ -1417,15 +1417,15 @@
if (flowAnalysis != null) {
// TODO(scheglov) encapsulate
var bodyContext = BodyInferenceContext.of(
- node.functionExpression.body!,
+ node.functionExpression.body,
);
checkForBodyMayCompleteNormally(
returnType: bodyContext?.contextType,
- body: node.functionExpression.body!,
+ body: node.functionExpression.body,
errorNode: node.name,
);
flowAnalysis!.executableDeclaration_exit(
- node.functionExpression.body!,
+ node.functionExpression.body,
isLocal,
);
if (isLocal) {
@@ -2607,7 +2607,7 @@
}
void visitConstructorDeclarationInScope(ConstructorDeclaration node) {
- node.body?.accept(this);
+ node.body.accept(this);
}
@override
diff --git a/pkg/analyzer/lib/src/lint/project.dart b/pkg/analyzer/lib/src/lint/project.dart
index 110bc63..759dddc 100644
--- a/pkg/analyzer/lib/src/lint/project.dart
+++ b/pkg/analyzer/lib/src/lint/project.dart
@@ -74,8 +74,9 @@
bool isApi(Element element) => _apiModel.contains(element);
String _calculateName() {
+ var pubspec = this.pubspec;
if (pubspec != null) {
- var nameEntry = pubspec!.name;
+ var nameEntry = pubspec.name;
if (nameEntry != null) {
return nameEntry.value.text!;
}
diff --git a/pkg/analyzer/lib/src/summary/base.dart b/pkg/analyzer/lib/src/summary/base.dart
index a3106ed..c29a315 100644
--- a/pkg/analyzer/lib/src/summary/base.dart
+++ b/pkg/analyzer/lib/src/summary/base.dart
@@ -45,34 +45,3 @@
const TopLevel([this.fileIdentifier]);
}
-
-/// Annotation used in the summary IDL to indicate the field name that is used
-/// to distinguish variants, or logical views on the same physical layout of
-/// fields.
-class Variant {
- final String fieldName;
-
- const Variant(this.fieldName);
-}
-
-/// Annotation used in the summary IDL to indicate the id of a field that
-/// represents a logical field. The set of ids used by a class must cover the
-/// contiguous range from 0 to N-1, where N is the number of fields. All
-/// logical fields must have the same type, which will become the type of the
-/// actual field.
-///
-/// In order to preserve forwards and backwards compatibility, id numbers must
-/// be stable between releases. So when new fields are added they should take
-/// the next available id without renumbering other fields.
-class VariantId {
- /// The ID of the actual field.
- final int value;
-
- /// The value of the variant field in [Variant].
- final Object? variant;
-
- /// The list of variant values for which this field exists.
- final List<Object>? variantList;
-
- const VariantId(this.value, {this.variant, this.variantList});
-}
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index ae7d510..cf03d4d 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -495,7 +495,7 @@
),
initializers,
redirectedConstructor,
- null,
+ AstTestFactory.emptyFunctionBody(),
) as ConstructorDeclarationImpl;
node.linkedContext = LinkedContext(
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
index 6e7a6d3..84007bd 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
@@ -860,8 +860,8 @@
var body = node.body;
_writeByte(
AstBinaryFlags.encode(
- isAsync: body?.isAsynchronous ?? false,
- isGenerator: body?.isGenerator ?? false,
+ isAsync: body.isAsynchronous,
+ isGenerator: body.isGenerator,
),
);
diff --git a/pkg/analyzer/lib/src/summary2/ast_text_printer.dart b/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
index a5c3518..3c6f084 100644
--- a/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
@@ -212,9 +212,9 @@
node.name?.accept(this);
node.parameters.accept(this);
_token(node.separator);
- _nodeList(node.initializers, node.body!.beginToken);
+ _nodeList(node.initializers, node.body.beginToken);
node.redirectedConstructor?.accept(this);
- node.body!.accept(this);
+ node.body.accept(this);
}
@override
@@ -473,7 +473,7 @@
void visitFunctionExpression(FunctionExpression node) {
node.typeParameters?.accept(this);
node.parameters?.accept(this);
- node.body!.accept(this);
+ node.body.accept(this);
}
@override
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index 12d1a56..bde642f 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -501,7 +501,7 @@
} else if (node is FunctionDeclaration) {
return isAsynchronous(node.functionExpression);
} else if (node is FunctionExpression) {
- return node.body!.isAsynchronous;
+ return node.body.isAsynchronous;
} else if (node is MethodDeclaration) {
return node.body.isAsynchronous;
} else {
@@ -580,7 +580,7 @@
} else if (node is FunctionDeclaration) {
return isGenerator(node.functionExpression);
} else if (node is FunctionExpression) {
- return node.body!.isGenerator;
+ return node.body.isGenerator;
} else if (node is MethodDeclaration) {
return node.body.isGenerator;
} else {
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index a587c44..257f912 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -314,16 +314,18 @@
@override
void visitForPartsWithDeclarations(ForPartsWithDeclarations node) {
- if (node.condition != null) {
- checkBoolean(node.condition!);
+ var condition = node.condition;
+ if (condition != null) {
+ checkBoolean(condition);
}
node.visitChildren(this);
}
@override
void visitForPartsWithExpression(ForPartsWithExpression node) {
- if (node.condition != null) {
- checkBoolean(node.condition!);
+ var condition = node.condition;
+ if (condition != null) {
+ checkBoolean(condition);
}
node.visitChildren(this);
}
@@ -370,10 +372,11 @@
@override
void visitListLiteral(ListLiteral node) {
DartType type = DynamicTypeImpl.instance;
- if (node.typeArguments != null) {
- NodeList<TypeAnnotation> targs = node.typeArguments!.arguments;
- if (targs.isNotEmpty) {
- type = targs[0].type!;
+ var typeArgumentList = node.typeArguments;
+ if (typeArgumentList != null) {
+ var typeArguments = typeArgumentList.arguments;
+ if (typeArguments.isNotEmpty) {
+ type = typeArguments[0].type!;
}
} else {
DartType staticType = node.typeOrThrow;
@@ -437,11 +440,12 @@
@override
void visitSetOrMapLiteral(SetOrMapLiteral node) {
+ var typeArgumentsList = node.typeArguments;
if (node.isMap) {
DartType keyType = DynamicTypeImpl.instance;
DartType valueType = DynamicTypeImpl.instance;
- if (node.typeArguments != null) {
- NodeList<TypeAnnotation> typeArguments = node.typeArguments!.arguments;
+ if (typeArgumentsList != null) {
+ NodeList<TypeAnnotation> typeArguments = typeArgumentsList.arguments;
if (typeArguments.isNotEmpty) {
keyType = typeArguments[0].type!;
}
@@ -460,8 +464,8 @@
}
} else if (node.isSet) {
DartType type = DynamicTypeImpl.instance;
- if (node.typeArguments != null) {
- NodeList<TypeAnnotation> typeArguments = node.typeArguments!.arguments;
+ if (typeArgumentsList != null) {
+ NodeList<TypeAnnotation> typeArguments = typeArgumentsList.arguments;
if (typeArguments.isNotEmpty) {
type = typeArguments[0].type!;
}
@@ -502,13 +506,12 @@
void visitVariableDeclaration(VariableDeclaration node) {
var variableElement = node.declaredElement;
var parent = node.parent;
- if (variableElement != null &&
+ if (variableElement is PropertyInducingElement &&
parent is VariableDeclarationList &&
- parent.type == null &&
- node.initializer != null) {
- if (variableElement.kind == ElementKind.TOP_LEVEL_VARIABLE ||
- variableElement.kind == ElementKind.FIELD) {
- _validateTopLevelInitializer(variableElement.name!, node.initializer!);
+ parent.type == null) {
+ var initializer = node.initializer;
+ if (initializer != null) {
+ _validateTopLevelInitializer(variableElement.name, initializer);
}
}
node.visitChildren(this);
@@ -890,14 +893,12 @@
}
var e = _getKnownElement(expr);
- if (e is FunctionElement || e is MethodElement && e.isStatic) {
+ if (e is FunctionElement) {
+ _recordMessage(expr, CompileTimeErrorCode.INVALID_CAST_FUNCTION,
+ [e.name, from, to]);
+ } else if (e is MethodElement && e.isStatic) {
_recordMessage(
- expr,
- e is MethodElement
- ? CompileTimeErrorCode.INVALID_CAST_METHOD
- : CompileTimeErrorCode.INVALID_CAST_FUNCTION,
- [e!.name, from, to]);
- return;
+ expr, CompileTimeErrorCode.INVALID_CAST_METHOD, [e.name, from, to]);
}
}
}
diff --git a/pkg/analyzer/lib/src/test_utilities/find_element.dart b/pkg/analyzer/lib/src/test_utilities/find_element.dart
index b44613c..53cdcc4 100644
--- a/pkg/analyzer/lib/src/test_utilities/find_element.dart
+++ b/pkg/analyzer/lib/src/test_utilities/find_element.dart
@@ -19,7 +19,7 @@
ExportElement? result;
for (var export in unitElement.library.exports) {
- var exportedUri = export.exportedLibrary!.source.uri.toString();
+ var exportedUri = export.exportedLibrary?.source.uri.toString();
if (exportedUri == targetUri) {
if (result != null) {
throw StateError('Not unique: $targetUri');
@@ -51,7 +51,7 @@
ImportElement? importElement;
for (var import in unitElement.library.imports) {
- var importedUri = import.importedLibrary!.source.uri.toString();
+ var importedUri = import.importedLibrary?.source.uri.toString();
if (importedUri == targetUri) {
if (importElement == null) {
importElement = import;
diff --git a/pkg/analyzer/test/generated/expression_parser_test.dart b/pkg/analyzer/test/generated/expression_parser_test.dart
index 4dbc53b..14eaa8d 100644
--- a/pkg/analyzer/test/generated/expression_parser_test.dart
+++ b/pkg/analyzer/test/generated/expression_parser_test.dart
@@ -804,8 +804,8 @@
Expression expression = parseExpression('() async {}');
var functionExpression = expression as FunctionExpression;
expect(functionExpression.body, isNotNull);
- expect(functionExpression.body!.isAsynchronous, isTrue);
- expect(functionExpression.body!.isGenerator, isFalse);
+ expect(functionExpression.body.isAsynchronous, isTrue);
+ expect(functionExpression.body.isGenerator, isFalse);
expect(functionExpression.parameters, isNotNull);
}
@@ -813,8 +813,8 @@
Expression expression = parseExpression('() async* {}');
var functionExpression = expression as FunctionExpression;
expect(functionExpression.body, isNotNull);
- expect(functionExpression.body!.isAsynchronous, isTrue);
- expect(functionExpression.body!.isGenerator, isTrue);
+ expect(functionExpression.body.isAsynchronous, isTrue);
+ expect(functionExpression.body.isGenerator, isTrue);
expect(functionExpression.parameters, isNotNull);
}
@@ -822,8 +822,8 @@
Expression expression = parseExpression('() {}');
var functionExpression = expression as FunctionExpression;
expect(functionExpression.body, isNotNull);
- expect(functionExpression.body!.isAsynchronous, isFalse);
- expect(functionExpression.body!.isGenerator, isFalse);
+ expect(functionExpression.body.isAsynchronous, isFalse);
+ expect(functionExpression.body.isGenerator, isFalse);
expect(functionExpression.parameters, isNotNull);
}
@@ -831,8 +831,8 @@
Expression expression = parseExpression('() sync* {}');
var functionExpression = expression as FunctionExpression;
expect(functionExpression.body, isNotNull);
- expect(functionExpression.body!.isAsynchronous, isFalse);
- expect(functionExpression.body!.isGenerator, isTrue);
+ expect(functionExpression.body.isAsynchronous, isFalse);
+ expect(functionExpression.body.isGenerator, isTrue);
expect(functionExpression.parameters, isNotNull);
}
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index 304b425..ded3bea 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -171,7 +171,7 @@
void check(String name, Asserter<InterfaceType> typeTest) {
FunctionDeclaration test = AstFinder.getTopLevelFunction(unit, name);
- var body = test.functionExpression.body as FunctionBody;
+ var body = test.functionExpression.body;
Expression returnExp;
if (body is ExpressionFunctionBody) {
returnExp = body.expression;
@@ -538,7 +538,7 @@
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer as FunctionExpression;
- FunctionBody body = exp.body!;
+ FunctionBody body = exp.body;
if (body is ExpressionFunctionBody) {
return body.expression;
} else {
@@ -791,7 +791,7 @@
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer as FunctionExpression;
- FunctionBody body = exp.body!;
+ FunctionBody body = exp.body;
if (body is ExpressionFunctionBody) {
return body.expression;
} else {
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index 0483996..baefdb9 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -236,7 +236,7 @@
''');
builderOptions.defaultPackageFilePath = packageFilePath;
- Packages packages = builder.createPackageMap(projectPath);
+ Packages packages = _createPackageMap(projectPath);
_assertPackages(
packages,
{
@@ -257,7 +257,7 @@
bar:${toUriStr('/pkg/bar')}
''');
- Packages packages = builder.createPackageMap(projectPath);
+ Packages packages = _createPackageMap(projectPath);
_assertPackages(
packages,
{
@@ -278,7 +278,7 @@
bar:${toUriStr('/pkg/bar')}
''');
- Packages packages = builder.createPackageMap(projectPath);
+ Packages packages = _createPackageMap(projectPath);
_assertPackages(
packages,
{
@@ -291,13 +291,13 @@
void test_createPackageMap_none() {
String rootPath = convertPath('/root');
newFolder(rootPath);
- Packages packages = builder.createPackageMap(rootPath);
+ Packages packages = _createPackageMap(rootPath);
expect(packages.packages, isEmpty);
}
void test_createPackageMap_rootDoesNotExist() {
String rootPath = convertPath('/root');
- Packages packages = builder.createPackageMap(rootPath);
+ Packages packages = _createPackageMap(rootPath);
expect(packages.packages, isEmpty);
}
@@ -396,39 +396,34 @@
newFile('/workspace/.packages');
newFolder('/workspace/.dart_tool/build/generated/project/lib');
newFile('/workspace/pubspec.yaml', content: 'name: project');
- Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
- convertPath('/workspace/project/lib/lib.dart'), builder);
+ Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
expect(workspace, TypeMatcher<PackageBuildWorkspace>());
}
void test_createWorkspace_hasPackagesFile_hasPubspec() {
newFile('/workspace/.packages');
newFile('/workspace/pubspec.yaml', content: 'name: project');
- Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
- convertPath('/workspace/project/lib/lib.dart'), builder);
+ Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
expect(workspace, TypeMatcher<PubWorkspace>());
}
void test_createWorkspace_hasPackagesFile_noMarkerFiles() {
newFile('/workspace/.packages');
- Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
- convertPath('/workspace/project/lib/lib.dart'), builder);
+ Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
expect(workspace, TypeMatcher<BasicWorkspace>());
}
void test_createWorkspace_noPackagesFile_hasBazelMarkerFiles() {
newFile('/workspace/WORKSPACE');
newFolder('/workspace/bazel-genfiles');
- Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
- convertPath('/workspace/project/lib/lib.dart'), builder);
+ Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
expect(workspace, TypeMatcher<BazelWorkspace>());
}
void test_createWorkspace_noPackagesFile_hasDartToolAndPubspec() {
newFolder('/workspace/.dart_tool/build/generated/project/lib');
newFile('/workspace/pubspec.yaml', content: 'name: project');
- Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
- convertPath('/workspace/project/lib/lib.dart'), builder);
+ Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
expect(workspace, TypeMatcher<PackageBuildWorkspace>());
}
@@ -440,21 +435,18 @@
"configVersion": 2,
"packages": []
}''');
- Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
- convertPath('/workspace/project/lib/lib.dart'), builder);
+ Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
expect(workspace, TypeMatcher<GnWorkspace>());
}
void test_createWorkspace_noPackagesFile_hasPubspec() {
newFile('/workspace/pubspec.yaml', content: 'name: project');
- Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
- convertPath('/workspace/project/lib/lib.dart'), builder);
+ Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
expect(workspace, TypeMatcher<PubWorkspace>());
}
void test_createWorkspace_noPackagesFile_noMarkerFiles() {
- Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
- convertPath('/workspace/project/lib/lib.dart'), builder);
+ Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
expect(workspace, TypeMatcher<BasicWorkspace>());
}
@@ -741,6 +733,22 @@
}
}
+ Packages _createPackageMap(String rootPath) {
+ return ContextBuilder.createPackageMap(
+ resourceProvider: resourceProvider,
+ options: builderOptions,
+ rootPath: rootPath,
+ );
+ }
+
+ Workspace _createWorkspace(String posixPath) {
+ return ContextBuilder.createWorkspace(
+ resourceProvider: resourceProvider,
+ options: ContextBuilderOptions(),
+ rootPath: convertPath(posixPath),
+ );
+ }
+
_defineMockLintRules() {
_mockLintRule = _MockLintRule('mock_lint_rule');
Registry.ruleRegistry.register(_mockLintRule);
diff --git a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
index cf43a2a..b580419 100644
--- a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
+++ b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
@@ -34,11 +34,12 @@
var contextUnit = LinterContextUnit(result.content!, result.unit!);
final libraryPath = result.libraryElement.source.fullName;
- final builder = ContextBuilder(
- resourceProvider, null /* sdkManager */, null /* contentCache */);
// todo (pq): get workspace from analysis context
- final workspace =
- ContextBuilder.createWorkspace(resourceProvider, libraryPath, builder);
+ final workspace = ContextBuilder.createWorkspace(
+ resourceProvider: resourceProvider,
+ options: ContextBuilderOptions(),
+ rootPath: libraryPath,
+ );
final workspacePackage = workspace.findPackageFor(libraryPath);
context = LinterContextImpl(
diff --git a/pkg/analyzer/tool/summary/generate.dart b/pkg/analyzer/tool/summary/generate.dart
index 2c495ae..a4b1c37 100644
--- a/pkg/analyzer/tool/summary/generate.dart
+++ b/pkg/analyzer/tool/summary/generate.dart
@@ -173,32 +173,9 @@
return json.encode(s);
}
- List<String> _computeVariants(idl_model.ClassDeclaration cls) {
- var allVariants = <String>{};
- for (var field in cls.fields) {
- var logicalFields = field.logicalProperties?.values;
- if (logicalFields != null) {
- for (var logicalField in logicalFields) {
- allVariants.addAll(logicalField.variants);
- }
- }
- }
- return allVariants.toList()..sort();
- }
-
bool _isNullable(idl_model.FieldType type) {
return !type.isList && _idl.classes.containsKey(type.typeName);
}
-
- String _variantAssertStatement(
- idl_model.ClassDeclaration class_,
- idl_model.LogicalProperty property,
- ) {
- var assertCondition = property.variants
- .map((key) => '${class_.variantField} == idl.$key')
- .join(' || ');
- return 'assert($assertCondition);';
- }
}
class _BuilderGenerator extends _BaseGenerator {
@@ -263,41 +240,8 @@
List<idl_model.FieldDeclaration> sortedFields = cls.fields.toList()
..sort((idl_model.FieldDeclaration a, idl_model.FieldDeclaration b) =>
a.id.compareTo(b.id));
- if (cls.variantField != null) {
- var firstVariant = true;
- for (var variant in _computeVariants(cls)) {
- if (firstVariant) {
- firstVariant = false;
- } else {
- out('else');
- }
- out('if (${cls.variantField} == idl.$variant) {');
- indent(() {
- for (var field in sortedFields) {
- var logicalProperties = field.logicalProperties;
- if (logicalProperties != null) {
- for (var logicalEntry in logicalProperties.entries) {
- var logicalName = logicalEntry.key;
- var logicalProperty = logicalEntry.value;
- if (logicalProperty.variants.contains(variant)) {
- writeField(
- logicalName,
- field.type,
- logicalProperty.isInformative,
- );
- }
- }
- } else {
- writeField(field.name, field.type, field.isInformative);
- }
- }
- });
- out('}');
- }
- } else {
- for (idl_model.FieldDeclaration field in sortedFields) {
- writeField('_${field.name}', field.type, field.isInformative);
- }
+ for (idl_model.FieldDeclaration field in sortedFields) {
+ writeField('_${field.name}', field.type, field.isInformative);
}
});
out('}');
@@ -305,55 +249,13 @@
void _generateConstructors() {
out();
- if (cls.variantField != null) {
- for (var variant in _computeVariants(cls)) {
- var constructorName = variant.split('.')[1];
- out('$builderName.$constructorName({');
-
- for (var field in cls.fields) {
- var logicalProperties = field.logicalProperties;
- if (logicalProperties != null) {
- for (var logicalEntry in logicalProperties.entries) {
- var logicalName = logicalEntry.key;
- var logicalProperty = logicalEntry.value;
- if (logicalProperty.variants.contains(variant)) {
- out('${encodedType2(field.type)} $logicalName,');
- }
- }
- }
- }
-
- out('}) : ');
-
- out('_${cls.variantField} = idl.$variant');
-
- var separator = ',';
- for (var field in cls.fields) {
- var logicalProperties = field.logicalProperties;
- if (logicalProperties != null) {
- for (var logicalEntry in logicalProperties.entries) {
- var logicalName = logicalEntry.key;
- var logicalProperty = logicalEntry.value;
- if (logicalProperty.variants.contains(variant)) {
- out('$separator _${field.name} = $logicalName');
- separator = ', ';
- }
- }
- }
- }
-
- out(';');
- out();
- }
- } else {
- out('$builderName({${constructorParams.join(', ')}})');
- List<idl_model.FieldDeclaration> fields = cls.fields.toList();
- for (int i = 0; i < fields.length; i++) {
- idl_model.FieldDeclaration field = fields[i];
- String prefix = i == 0 ? ' : ' : ' ';
- String suffix = i == fields.length - 1 ? ';' : ',';
- out('${prefix}_${field.name} = ${field.name}$suffix');
- }
+ out('$builderName({${constructorParams.join(', ')}})');
+ List<idl_model.FieldDeclaration> fields = cls.fields.toList();
+ for (int i = 0; i < fields.length; i++) {
+ idl_model.FieldDeclaration field = fields[i];
+ String prefix = i == 0 ? ' : ' : ' ';
+ String suffix = i == fields.length - 1 ? ';' : ',';
+ out('${prefix}_${field.name} = ${field.name}$suffix');
}
}
@@ -483,41 +385,8 @@
}
indent(() {
- if (cls.variantField != null) {
- var firstVariant = true;
- for (var variant in _computeVariants(cls)) {
- if (firstVariant) {
- firstVariant = false;
- } else {
- out('else');
- }
- out('if (${cls.variantField} == idl.$variant) {');
- indent(() {
- for (var field in cls.fields) {
- var logicalProperties = field.logicalProperties;
- if (logicalProperties != null) {
- for (var logicalEntry in logicalProperties.entries) {
- var logicalName = logicalEntry.key;
- var logicalProperty = logicalEntry.value;
- if (logicalProperty.variants.contains(variant)) {
- writeField(
- logicalName,
- field.type,
- logicalProperty.isInformative,
- );
- }
- }
- } else {
- writeField(field.name, field.type, field.isInformative);
- }
- }
- });
- out('}');
- }
- } else {
- for (idl_model.FieldDeclaration field in cls.fields) {
- writeField('_${field.name}', field.type, field.isInformative);
- }
+ for (idl_model.FieldDeclaration field in cls.fields) {
+ writeField('_${field.name}', field.type, field.isInformative);
}
});
out('}');
@@ -535,53 +404,22 @@
out('@override');
out('Null get $fieldName => ${_BaseGenerator._throwDeprecated};');
} else {
- var logicalProperties = field.logicalProperties;
- if (logicalProperties != null) {
- for (var logicalEntry in logicalProperties.entries) {
- var logicalName = logicalEntry.key;
- var logicalProperty = logicalEntry.value;
- out('@override');
- out('$typeStr get $logicalName {');
- indent(() {
- out(_variantAssertStatement(cls, logicalProperty));
- out('return _${field.name}$defSuffix;');
- });
- out('}');
- out();
- }
- } else {
- out('@override');
- var nn = _isNullable(field.type) ? '?' : '';
- out('$typeStr$nn get $fieldName => _$fieldName$defSuffix;');
- }
+ var nn = _isNullable(field.type) ? '?' : '';
+
+ out('@override');
+ out('$typeStr$nn get $fieldName => _$fieldName$defSuffix;');
out();
constructorParams.add('$typeStr? $fieldName');
outDoc(field.documentation);
- if (logicalProperties != null) {
- for (var logicalEntry in logicalProperties.entries) {
- var logicalName = logicalEntry.key;
- var logicalProperty = logicalEntry.value;
- out('set $logicalName($typeStr value) {');
- indent(() {
- out(_variantAssertStatement(cls, logicalProperty));
- _generateNonNegativeInt(fieldType);
- out('_variantField_${field.id} = value;');
- });
- out('}');
- out();
- }
- } else {
- var nn = _isNullable(field.type) ? '?' : '';
- out('set $fieldName($typeStr$nn value) {');
- indent(() {
- _generateNonNegativeInt(fieldType);
- out('this._$fieldName = value;');
- });
- out('}');
- }
+ out('set $fieldName($typeStr$nn value) {');
+ indent(() {
+ _generateNonNegativeInt(fieldType);
+ out('this._$fieldName = value;');
+ });
+ out('}');
}
}
}
@@ -743,7 +581,6 @@
bool isDeprecated = false;
String? fileIdentifier;
String clsName = decl.name;
- String? variantField;
for (Annotation annotation in decl.metadata) {
var arguments = annotation.arguments;
if (arguments != null &&
@@ -767,23 +604,6 @@
annotation.name == 'deprecated' &&
annotation.constructorName == null) {
isDeprecated = true;
- } else if (arguments != null &&
- annotation.name == 'Variant' &&
- annotation.constructorName == null) {
- if (arguments.length == 1) {
- Expression arg = arguments[0];
- if (arg is StringLiteral) {
- variantField = arg.stringValue;
- } else {
- throw Exception(
- 'Class `$clsName`: @Variant argument must be a string literal',
- );
- }
- } else if (arguments.isNotEmpty) {
- throw Exception(
- 'Class `$clsName`: @Variant requires 1 argument',
- );
- }
}
}
idl_model.ClassDeclaration cls = idl_model.ClassDeclaration(
@@ -792,7 +612,6 @@
isTopLevel: isTopLevel,
fileIdentifier: fileIdentifier,
isDeprecated: isDeprecated,
- variantField: variantField,
);
_idl.classes[clsName] = cls;
String expectedBase = 'base.SummaryClass';
@@ -912,7 +731,6 @@
}
int? id;
- List<String>? variants;
bool isDeprecated = false;
bool isInformative = false;
@@ -944,51 +762,6 @@
isDeprecated = true;
} else if (annotation.name == 'informative') {
isInformative = true;
- } else if (annotation.name == 'VariantId') {
- if (id != null) {
- throw Exception('Cannot specify both @Id and @VariantId ($getter)');
- }
- if (variants != null) {
- throw Exception('Duplicate @VariantId annotation ($getter)');
- }
-
- if (arguments == null) {
- throw Exception('@VariantId must be given arguments ($desc)');
- }
- if (arguments.length != 2) {
- throw Exception(
- '@VariantId must be given exactly two arguments ($desc)',
- );
- }
-
- var idExpression = arguments[0];
- if (idExpression is IntegerLiteral) {
- id = idExpression.value;
- } else {
- throw Exception(
- '@VariantId argument must be an integer literal ($desc)',
- );
- }
-
- var variantExpression = arguments[1];
- if (variantExpression is NamedExpression) {
- if (variantExpression.name == 'variant') {
- variants = [variantExpression.expression.toCode()];
- } else if (variantExpression.name == 'variantList') {
- variants = (variantExpression.expression as ListLiteral)
- .elements
- .map((e) => e.toCode())
- .toList();
- } else {
- throw Exception(
- 'Only "key" or "keyList" expected in @VariantId ($desc)',
- );
- }
- } else {
- throw Exception(
- 'The second argument of @VariantId must be named ($desc)',
- );
- }
}
}
if (id == null) {
@@ -997,67 +770,14 @@
var fieldType = idl_model.FieldType(type.name, isList);
- String name = getter.name;
- Map<String, idl_model.LogicalProperty>? logicalProperties;
- if (variants != null) {
- var fieldsWithSameId =
- cls.allFields.where((field) => field.id == id).toList();
- if (fieldsWithSameId.isNotEmpty) {
- var existingField = fieldsWithSameId.single;
- var logicalProperties = existingField.logicalProperties;
- if (logicalProperties == null) {
- throw Exception('$desc: id $id is already used as a non-variant '
- 'field: ${existingField.name}');
- }
-
- for (var variant in variants) {
- for (var entry in logicalProperties.entries) {
- if (entry.value.variants.contains(variant)) {
- var logicalName = entry.key;
- throw Exception('$desc: id $id is already used for $logicalName');
- }
- }
- }
-
- if (existingField.type != fieldType) {
- throw Exception(
- '$desc: id $id is already used with type ${existingField.type}',
- );
- }
-
- if (logicalProperties[getter.name] != null) {
- throw Exception(
- '$desc: logical property ${getter.name} is already used',
- );
- }
-
- logicalProperties[getter.name] = idl_model.LogicalProperty(
- isDeprecated: isDeprecated,
- isInformative: isInformative,
- variants: variants,
- );
- return;
- } else {
- name = 'variantField_$id';
- logicalProperties = <String, idl_model.LogicalProperty>{
- getter.name: idl_model.LogicalProperty(
- isDeprecated: isDeprecated,
- isInformative: isInformative,
- variants: variants,
- ),
- };
- }
- }
-
cls.allFields.add(
idl_model.FieldDeclaration(
documentation: _getNodeDoc(getter),
- name: name,
+ name: getter.name,
type: fieldType,
id: id,
isDeprecated: isDeprecated,
isInformative: isInformative,
- logicalProperties: logicalProperties,
),
);
}
@@ -1281,40 +1001,22 @@
out('@override');
out('Null get $fieldName => ${_BaseGenerator._throwDeprecated};');
} else {
- var logicalProperties = field.logicalProperties;
- if (logicalProperties != null) {
- for (var logicalEntry in logicalProperties.entries) {
- var logicalName = logicalEntry.key;
- var logicalProperty = logicalEntry.value;
- out('@override');
- out('$returnType get $logicalName {');
- indent(() {
- out(_variantAssertStatement(cls, logicalProperty));
- String readExpr =
- '$readCode.vTableGet(_bc, _bcOffset, $index, $def)';
- out('return _$fieldName ??= $readExpr;');
- });
- out('}');
- out();
- }
+ out('@override');
+ if (_isNullable(type)) {
+ out('$returnType? get $fieldName {');
} else {
- out('@override');
- if (_isNullable(type)) {
- out('$returnType? get $fieldName {');
- } else {
- out('$returnType get $fieldName {');
- }
- indent(() {
- String readExpr;
- if (_isNullable(type)) {
- readExpr = '$readCode.vTableGetOrNull(_bc, _bcOffset, $index)';
- } else {
- readExpr = '$readCode.vTableGet(_bc, _bcOffset, $index, $def)';
- }
- out('return _$fieldName ??= $readExpr;');
- });
- out('}');
+ out('$returnType get $fieldName {');
}
+ indent(() {
+ String readExpr;
+ if (_isNullable(type)) {
+ readExpr = '$readCode.vTableGetOrNull(_bc, _bcOffset, $index)';
+ } else {
+ readExpr = '$readCode.vTableGet(_bc, _bcOffset, $index, $def)';
+ }
+ out('return _$fieldName ??= $readExpr;');
+ });
+ out('}');
}
}
});
@@ -1389,52 +1091,15 @@
indent(() {
out('Map<String, Object> _result = <String, Object>{};');
- if (cls.variantField != null) {
- indent(() {
- for (idl_model.FieldDeclaration field in cls.fields) {
- if (field.logicalProperties == null) {
- var localName = 'local_${field.name}';
- out('var $localName = ${field.name};');
- var condition = jsonCondition(field.type, localName);
- var storeField = jsonStore(field.type, field.name, localName);
- writeConditionalStatement(condition, storeField);
- }
- }
- for (var variant in _computeVariants(cls)) {
- out('if (${cls.variantField} == idl.$variant) {');
- indent(() {
- for (idl_model.FieldDeclaration field in cls.fields) {
- var logicalProperties = field.logicalProperties;
- if (logicalProperties != null) {
- for (var logicalEntry in logicalProperties.entries) {
- var logicalName = logicalEntry.key;
- var logicalProperty = logicalEntry.value;
- if (logicalProperty.variants.contains(variant)) {
- var localName = 'local_${field.name}';
- out('var $localName = ${field.name};');
- var condition = jsonCondition(field.type, localName);
- var storeField =
- jsonStore(field.type, logicalName, localName);
- writeConditionalStatement(condition, storeField);
- }
- }
- }
- }
- });
- out('}');
- }
- });
- } else {
- indent(() {
- for (idl_model.FieldDeclaration field in cls.fields) {
- var localName = 'local_${field.name}';
- out('var $localName = ${field.name};');
- String condition = jsonCondition(field.type, localName);
- String storeField = jsonStore(field.type, field.name, localName);
- writeConditionalStatement(condition, storeField);
- }
- });
- }
+ indent(() {
+ for (idl_model.FieldDeclaration field in cls.fields) {
+ var localName = 'local_${field.name}';
+ out('var $localName = ${field.name};');
+ String condition = jsonCondition(field.type, localName);
+ String storeField = jsonStore(field.type, field.name, localName);
+ writeConditionalStatement(condition, storeField);
+ }
+ });
out('return _result;');
});
@@ -1443,43 +1108,14 @@
// Write toMap().
out('@override');
- if (cls.variantField != null) {
- out('Map<String, Object> toMap() {');
- for (var variant in _computeVariants(cls)) {
- out('if (${cls.variantField} == idl.$variant) {');
- indent(() {
- out('return {');
- for (idl_model.FieldDeclaration field in cls.fields) {
- var logicalProperties = field.logicalProperties;
- if (logicalProperties != null) {
- for (var logicalEntry in logicalProperties.entries) {
- var logicalName = logicalEntry.key;
- var logicalProperty = logicalEntry.value;
- if (logicalProperty.variants.contains(variant)) {
- out('${quoted(logicalName)}: $logicalName,');
- }
- }
- } else {
- String fieldName = field.name;
- out('${quoted(fieldName)}: $fieldName,');
- }
- }
- out('};');
- });
- out('}');
+ out('Map<String, Object?> toMap() => {');
+ indent(() {
+ for (idl_model.FieldDeclaration field in cls.fields) {
+ String fieldName = field.name;
+ out('${quoted(fieldName)}: $fieldName,');
}
- out('throw StateError("Unexpected \$${cls.variantField}");');
- out('}');
- } else {
- out('Map<String, Object?> toMap() => {');
- indent(() {
- for (idl_model.FieldDeclaration field in cls.fields) {
- String fieldName = field.name;
- out('${quoted(fieldName)}: $fieldName,');
- }
- });
- out('};');
- }
+ });
+ out('};');
out();
// Write toString().
out('@override');
diff --git a/pkg/analyzer/tool/summary/idl_model.dart b/pkg/analyzer/tool/summary/idl_model.dart
index 0b78425..6da5456 100644
--- a/pkg/analyzer/tool/summary/idl_model.dart
+++ b/pkg/analyzer/tool/summary/idl_model.dart
@@ -21,15 +21,12 @@
/// Indicates whether the class has the `deprecated` annotation.
final bool isDeprecated;
- final String? variantField;
-
ClassDeclaration({
required String? documentation,
required this.fileIdentifier,
required String name,
required this.isDeprecated,
required this.isTopLevel,
- required this.variantField,
}) : super(documentation, name);
/// Get the non-deprecated fields defined in the class.
@@ -77,9 +74,6 @@
/// Indicates whether the field is informative.
final bool isInformative;
- /// Maps logical property names to logical property.
- final Map<String, LogicalProperty>? logicalProperties;
-
FieldDeclaration({
required String? documentation,
required String name,
@@ -87,7 +81,6 @@
required this.id,
required this.isDeprecated,
required this.isInformative,
- required this.logicalProperties,
}) : super(documentation, name);
}
@@ -129,21 +122,3 @@
/// Enums defined in the IDL.
final Map<String, EnumDeclaration> enums = <String, EnumDeclaration>{};
}
-
-/// Information about a logical property mapped to a single data fields.
-class LogicalProperty {
- /// Indicates whether the property is deprecated.
- final bool isDeprecated;
-
- /// Indicates whether the property is informative.
- final bool isInformative;
-
- /// Names of variants in which this property is available.
- final List<String> variants;
-
- LogicalProperty({
- required this.isDeprecated,
- required this.isInformative,
- required this.variants,
- });
-}
diff --git a/pkg/dartdev/test/analytics_test.dart b/pkg/dartdev/test/analytics_test.dart
index 8c74972..6158b0d 100644
--- a/pkg/dartdev/test/analytics_test.dart
+++ b/pkg/dartdev/test/analytics_test.dart
@@ -20,6 +20,33 @@
void main() {
group('DisabledAnalytics', disabledAnalyticsObject);
+ test('Analytics control smoke test', () {
+ final p = project(logAnalytics: true);
+ var result = p.runSync(['--disable-analytics']);
+ expect(result.stdout, contains('''
+ ╔════════════════════════════════════════════════════════════════════════════╗
+ ║ Anonymous analytics reporting disabled. In order to enable it, run: ║
+ ║ ║
+ ║ dart --enable-analytics ║
+ ║ ║
+ ╚════════════════════════════════════════════════════════════════════════════╝
+'''));
+
+ result = p.runSync(['--enable-analytics']);
+ expect(result.stdout, contains('''
+ ╔════════════════════════════════════════════════════════════════════════════╗
+ ║ The Dart tool uses Google Analytics to anonymously report feature usage ║
+ ║ statistics and to send basic crash reports. This data is used to help ║
+ ║ improve the Dart platform and tools over time. ║
+ ║ ║
+ ║ To disable reporting of anonymous analytics, run: ║
+ ║ ║
+ ║ dart --disable-analytics ║
+ ║ ║
+ ╚════════════════════════════════════════════════════════════════════════════╝
+'''));
+ });
+
group('Sending analytics', () {
test('help', () {
final p = project(logAnalytics: true);
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart
index a424674..b198669 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart
@@ -20,7 +20,7 @@
Pointer<Coordinate> next;
- factory Coordinate.allocate(
+ factory Coordinate.allocate(
Allocator allocator, double x, double y, Pointer<Coordinate> next) {
return allocator<Coordinate>().ref
..x = x
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
index 94630fc..8c4ed96 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
@@ -12,10 +12,10 @@
import "package:ffi/ffi.dart";
@#C3
-@#C8
+@#C9
class Coordinate extends ffi::Struct {
@#C3
- static final field core::int* #sizeOf = (#C11).{core::List::[]}(ffi::_abi());
+ static final field core::int* #sizeOf = (#C12).{core::List::[]}(ffi::_abi());
@#C3
constructor #fromTypedDataBase(dynamic #pointer) → dynamic
: super ffi::Struct::_fromPointer(#pointer)
@@ -39,17 +39,17 @@
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
get x() → core::double*
- return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C13).{core::List::[]}(ffi::_abi()));
+ return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()));
set x(core::double* #v) → void
- return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C13).{core::List::[]}(ffi::_abi()), #v);
+ return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()), #v);
get y() → core::double*
- return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()));
+ return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()));
set y(core::double* #v) → void
- return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()), #v);
+ return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()), #v);
get next() → ffi::Pointer<self::Coordinate*>*
- return ffi::_fromAddress<self::Coordinate*>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi())));
+ return ffi::_fromAddress<self::Coordinate*>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi())));
set next(ffi::Pointer<self::Coordinate*>* #v) → void
- return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi()), #v.{ffi::Pointer::address});
+ return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi()), #v.{ffi::Pointer::address});
}
static method main() → dynamic {}
@@ -61,16 +61,17 @@
#C5 = TypeLiteralConstant(ffi::Double)
#C6 = TypeLiteralConstant(ffi::Pointer<ffi::NativeType>)
#C7 = <core::Type>[#C5, #C5, #C6]
- #C8 = core::pragma {name:#C4, options:#C7}
- #C9 = 24
- #C10 = 20
- #C11 = <core::int*>[#C9, #C10, #C9]
- #C12 = 0
- #C13 = <core::int*>[#C12, #C12, #C12]
- #C14 = 8
- #C15 = <core::int*>[#C14, #C14, #C14]
- #C16 = 16
- #C17 = <core::int*>[#C16, #C16, #C16]
+ #C8 = ffi::_FfiStructLayout {fieldTypes:#C7}
+ #C9 = core::pragma {name:#C4, options:#C8}
+ #C10 = 24
+ #C11 = 20
+ #C12 = <core::int*>[#C10, #C11, #C10]
+ #C13 = 0
+ #C14 = <core::int*>[#C13, #C13, #C13]
+ #C15 = 8
+ #C16 = <core::int*>[#C15, #C15, #C15]
+ #C17 = 16
+ #C18 = <core::int*>[#C17, #C17, #C17]
}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.1.expect
index f93c1a3..08f11e7 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.1.expect
@@ -4,10 +4,10 @@
import "dart:ffi";
@#C3
- @#C8
+ @#C9
class Coordinate extends dart.ffi::Struct {
@#C3
- static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+ static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
@#C3
constructor #fromTypedDataBase(dynamic #pointer) → dynamic
: super dart.ffi::Struct::_fromPointer(#pointer)
@@ -27,17 +27,17 @@
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -59,14 +59,15 @@
#C5 = TypeLiteralConstant(dart.ffi::Double)
#C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
#C7 = <dart.core::Type>[#C5, #C5, #C6]
- #C8 = dart.core::pragma {name:#C4, options:#C7}
- #C9 = 24
- #C10 = 20
- #C11 = <dart.core::int*>[#C9, #C10, #C9]
- #C12 = 0
- #C13 = <dart.core::int*>[#C12, #C12, #C12]
- #C14 = 8
- #C15 = <dart.core::int*>[#C14, #C14, #C14]
- #C16 = 16
- #C17 = <dart.core::int*>[#C16, #C16, #C16]
+ #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+ #C9 = dart.core::pragma {name:#C4, options:#C8}
+ #C10 = 24
+ #C11 = 20
+ #C12 = <dart.core::int*>[#C10, #C11, #C10]
+ #C13 = 0
+ #C14 = <dart.core::int*>[#C13, #C13, #C13]
+ #C15 = 8
+ #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C17 = 16
+ #C18 = <dart.core::int*>[#C17, #C17, #C17]
}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.2.expect
index 466b63f..77ff6cd 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.2.expect
@@ -4,10 +4,10 @@
import "dart:ffi";
@#C3
- @#C8
+ @#C9
class Coordinate extends dart.ffi::Struct {
@#C3
- static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+ static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
@#C3
constructor #fromTypedDataBase(dynamic #pointer) → dynamic
: super dart.ffi::Struct::_fromPointer(#pointer)
@@ -27,17 +27,17 @@
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -63,14 +63,15 @@
#C5 = TypeLiteralConstant(dart.ffi::Double)
#C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
#C7 = <dart.core::Type>[#C5, #C5, #C6]
- #C8 = dart.core::pragma {name:#C4, options:#C7}
- #C9 = 24
- #C10 = 20
- #C11 = <dart.core::int*>[#C9, #C10, #C9]
- #C12 = 0
- #C13 = <dart.core::int*>[#C12, #C12, #C12]
- #C14 = 8
- #C15 = <dart.core::int*>[#C14, #C14, #C14]
- #C16 = 16
- #C17 = <dart.core::int*>[#C16, #C16, #C16]
+ #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+ #C9 = dart.core::pragma {name:#C4, options:#C8}
+ #C10 = 24
+ #C11 = 20
+ #C12 = <dart.core::int*>[#C10, #C11, #C10]
+ #C13 = 0
+ #C14 = <dart.core::int*>[#C13, #C13, #C13]
+ #C15 = 8
+ #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C17 = 16
+ #C18 = <dart.core::int*>[#C17, #C17, #C17]
}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_02.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_02.yaml.world.1.expect
index 5d79437..a42b6b2 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_02.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_02.yaml.world.1.expect
@@ -4,10 +4,10 @@
import "dart:ffi";
@#C3
- @#C8
+ @#C9
class Coordinate extends dart.ffi::Struct {
@#C3
- static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+ static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
@#C3
constructor #fromTypedDataBase(dynamic #pointer) → dynamic
: super dart.ffi::Struct::_fromPointer(#pointer)
@@ -27,17 +27,17 @@
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -60,14 +60,15 @@
#C5 = TypeLiteralConstant(dart.ffi::Double)
#C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
#C7 = <dart.core::Type>[#C5, #C5, #C6]
- #C8 = dart.core::pragma {name:#C4, options:#C7}
- #C9 = 24
- #C10 = 20
- #C11 = <dart.core::int*>[#C9, #C10, #C9]
- #C12 = 0
- #C13 = <dart.core::int*>[#C12, #C12, #C12]
- #C14 = 8
- #C15 = <dart.core::int*>[#C14, #C14, #C14]
- #C16 = 16
- #C17 = <dart.core::int*>[#C16, #C16, #C16]
+ #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+ #C9 = dart.core::pragma {name:#C4, options:#C8}
+ #C10 = 24
+ #C11 = 20
+ #C12 = <dart.core::int*>[#C10, #C11, #C10]
+ #C13 = 0
+ #C14 = <dart.core::int*>[#C13, #C13, #C13]
+ #C15 = 8
+ #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C17 = 16
+ #C18 = <dart.core::int*>[#C17, #C17, #C17]
}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect
index f93c1a3..08f11e7 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect
@@ -4,10 +4,10 @@
import "dart:ffi";
@#C3
- @#C8
+ @#C9
class Coordinate extends dart.ffi::Struct {
@#C3
- static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+ static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
@#C3
constructor #fromTypedDataBase(dynamic #pointer) → dynamic
: super dart.ffi::Struct::_fromPointer(#pointer)
@@ -27,17 +27,17 @@
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -59,14 +59,15 @@
#C5 = TypeLiteralConstant(dart.ffi::Double)
#C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
#C7 = <dart.core::Type>[#C5, #C5, #C6]
- #C8 = dart.core::pragma {name:#C4, options:#C7}
- #C9 = 24
- #C10 = 20
- #C11 = <dart.core::int*>[#C9, #C10, #C9]
- #C12 = 0
- #C13 = <dart.core::int*>[#C12, #C12, #C12]
- #C14 = 8
- #C15 = <dart.core::int*>[#C14, #C14, #C14]
- #C16 = 16
- #C17 = <dart.core::int*>[#C16, #C16, #C16]
+ #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+ #C9 = dart.core::pragma {name:#C4, options:#C8}
+ #C10 = 24
+ #C11 = 20
+ #C12 = <dart.core::int*>[#C10, #C11, #C10]
+ #C13 = 0
+ #C14 = <dart.core::int*>[#C13, #C13, #C13]
+ #C15 = 8
+ #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C17 = 16
+ #C18 = <dart.core::int*>[#C17, #C17, #C17]
}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect
index 01f4106..4d29471 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect
@@ -4,10 +4,10 @@
import "dart:ffi";
@#C3
- @#C8
+ @#C9
class Coordinate extends dart.ffi::Struct {
@#C3
- static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+ static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
@#C3
constructor #fromTypedDataBase(dynamic #pointer) → dynamic
: super dart.ffi::Struct::_fromPointer(#pointer)
@@ -27,17 +27,17 @@
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -60,14 +60,15 @@
#C5 = TypeLiteralConstant(dart.ffi::Double)
#C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
#C7 = <dart.core::Type>[#C5, #C5, #C6]
- #C8 = dart.core::pragma {name:#C4, options:#C7}
- #C9 = 24
- #C10 = 20
- #C11 = <dart.core::int*>[#C9, #C10, #C9]
- #C12 = 0
- #C13 = <dart.core::int*>[#C12, #C12, #C12]
- #C14 = 8
- #C15 = <dart.core::int*>[#C14, #C14, #C14]
- #C16 = 16
- #C17 = <dart.core::int*>[#C16, #C16, #C16]
+ #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+ #C9 = dart.core::pragma {name:#C4, options:#C8}
+ #C10 = 24
+ #C11 = 20
+ #C12 = <dart.core::int*>[#C10, #C11, #C10]
+ #C13 = 0
+ #C14 = <dart.core::int*>[#C13, #C13, #C13]
+ #C15 = 8
+ #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C17 = 16
+ #C18 = <dart.core::int*>[#C17, #C17, #C17]
}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect
index 2c057af..6f18d43 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect
@@ -4,10 +4,10 @@
import "dart:ffi";
@#C3
- @#C8
+ @#C9
class Coordinate extends dart.ffi::Struct {
@#C3
- static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+ static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
@#C3
constructor #fromTypedDataBase(dynamic #pointer) → dynamic
: super dart.ffi::Struct::_fromPointer(#pointer)
@@ -28,17 +28,17 @@
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -61,14 +61,15 @@
#C5 = TypeLiteralConstant(dart.ffi::Double)
#C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
#C7 = <dart.core::Type>[#C5, #C5, #C6]
- #C8 = dart.core::pragma {name:#C4, options:#C7}
- #C9 = 24
- #C10 = 20
- #C11 = <dart.core::int*>[#C9, #C10, #C9]
- #C12 = 0
- #C13 = <dart.core::int*>[#C12, #C12, #C12]
- #C14 = 8
- #C15 = <dart.core::int*>[#C14, #C14, #C14]
- #C16 = 16
- #C17 = <dart.core::int*>[#C16, #C16, #C16]
+ #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+ #C9 = dart.core::pragma {name:#C4, options:#C8}
+ #C10 = 24
+ #C11 = 20
+ #C12 = <dart.core::int*>[#C10, #C11, #C10]
+ #C13 = 0
+ #C14 = <dart.core::int*>[#C13, #C13, #C13]
+ #C15 = 8
+ #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C17 = 16
+ #C18 = <dart.core::int*>[#C17, #C17, #C17]
}
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
index 79439bc..e8d0533 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
@@ -12,30 +12,30 @@
import "package:ffi/ffi.dart";
@#C3
-@#C8
+@#C9
class Coordinate extends ffi::Struct {
@#C3
- static final field core::int* #sizeOf = (#C11).{core::List::[]}(ffi::_abi())/*isLegacy*/;
+ static final field core::int* #sizeOf = (#C12).{core::List::[]}(ffi::_abi())/*isLegacy*/;
@#C3
constructor #fromTypedDataBase(dynamic #pointer) → dynamic
: super ffi::Struct::_fromPointer(#pointer)
;
- @#C12
+ @#C13
get x() → core::double
- return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()));
- @#C12
+ return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()));
+ @#C13
set x(core::double #externalFieldValue) → void
- return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()), #externalFieldValue);
- @#C12
+ return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()), #externalFieldValue);
+ @#C13
get y() → core::double
- return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()));
- @#C12
+ return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi()));
+ @#C13
set y(core::double #externalFieldValue) → void
- return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()), #externalFieldValue);
+ return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi()), #externalFieldValue);
get next() → ffi::Pointer<self::Coordinate>
- return ffi::_fromAddress<self::Coordinate>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi())));
+ return ffi::_fromAddress<self::Coordinate>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C19).{core::List::[]}(ffi::_abi())));
set next(ffi::Pointer<self::Coordinate> #externalFieldValue) → void
- return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address});
+ return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C19).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address});
static factory allocate(ffi::Allocator allocator, core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
return let final self::Coordinate #t1 = new self::Coordinate::#fromTypedDataBase(allocator.{ffi::Allocator::allocate}<self::Coordinate>(self::Coordinate::#sizeOf)!) in block {
#t1.{self::Coordinate::x} = x;
@@ -54,17 +54,18 @@
#C5 = TypeLiteralConstant(ffi::Double)
#C6 = TypeLiteralConstant(ffi::Pointer<ffi::NativeType>)
#C7 = <core::Type>[#C5, #C5, #C6]
- #C8 = core::pragma {name:#C4, options:#C7}
- #C9 = 24
- #C10 = 20
- #C11 = <core::int*>[#C9, #C10, #C9]
- #C12 = ffi::Double {}
- #C13 = 0
- #C14 = <core::int*>[#C13, #C13, #C13]
- #C15 = 8
- #C16 = <core::int*>[#C15, #C15, #C15]
- #C17 = 16
- #C18 = <core::int*>[#C17, #C17, #C17]
+ #C8 = ffi::_FfiStructLayout {fieldTypes:#C7}
+ #C9 = core::pragma {name:#C4, options:#C8}
+ #C10 = 24
+ #C11 = 20
+ #C12 = <core::int*>[#C10, #C11, #C10]
+ #C13 = ffi::Double {}
+ #C14 = 0
+ #C15 = <core::int*>[#C14, #C14, #C14]
+ #C16 = 8
+ #C17 = <core::int*>[#C16, #C16, #C16]
+ #C18 = 16
+ #C19 = <core::int*>[#C18, #C18, #C18]
}
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
index 79439bc..e8d0533 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
@@ -12,30 +12,30 @@
import "package:ffi/ffi.dart";
@#C3
-@#C8
+@#C9
class Coordinate extends ffi::Struct {
@#C3
- static final field core::int* #sizeOf = (#C11).{core::List::[]}(ffi::_abi())/*isLegacy*/;
+ static final field core::int* #sizeOf = (#C12).{core::List::[]}(ffi::_abi())/*isLegacy*/;
@#C3
constructor #fromTypedDataBase(dynamic #pointer) → dynamic
: super ffi::Struct::_fromPointer(#pointer)
;
- @#C12
+ @#C13
get x() → core::double
- return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()));
- @#C12
+ return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()));
+ @#C13
set x(core::double #externalFieldValue) → void
- return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()), #externalFieldValue);
- @#C12
+ return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()), #externalFieldValue);
+ @#C13
get y() → core::double
- return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()));
- @#C12
+ return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi()));
+ @#C13
set y(core::double #externalFieldValue) → void
- return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()), #externalFieldValue);
+ return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi()), #externalFieldValue);
get next() → ffi::Pointer<self::Coordinate>
- return ffi::_fromAddress<self::Coordinate>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi())));
+ return ffi::_fromAddress<self::Coordinate>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C19).{core::List::[]}(ffi::_abi())));
set next(ffi::Pointer<self::Coordinate> #externalFieldValue) → void
- return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address});
+ return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C19).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address});
static factory allocate(ffi::Allocator allocator, core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
return let final self::Coordinate #t1 = new self::Coordinate::#fromTypedDataBase(allocator.{ffi::Allocator::allocate}<self::Coordinate>(self::Coordinate::#sizeOf)!) in block {
#t1.{self::Coordinate::x} = x;
@@ -54,17 +54,18 @@
#C5 = TypeLiteralConstant(ffi::Double)
#C6 = TypeLiteralConstant(ffi::Pointer<ffi::NativeType>)
#C7 = <core::Type>[#C5, #C5, #C6]
- #C8 = core::pragma {name:#C4, options:#C7}
- #C9 = 24
- #C10 = 20
- #C11 = <core::int*>[#C9, #C10, #C9]
- #C12 = ffi::Double {}
- #C13 = 0
- #C14 = <core::int*>[#C13, #C13, #C13]
- #C15 = 8
- #C16 = <core::int*>[#C15, #C15, #C15]
- #C17 = 16
- #C18 = <core::int*>[#C17, #C17, #C17]
+ #C8 = ffi::_FfiStructLayout {fieldTypes:#C7}
+ #C9 = core::pragma {name:#C4, options:#C8}
+ #C10 = 24
+ #C11 = 20
+ #C12 = <core::int*>[#C10, #C11, #C10]
+ #C13 = ffi::Double {}
+ #C14 = 0
+ #C15 = <core::int*>[#C14, #C14, #C14]
+ #C16 = 8
+ #C17 = <core::int*>[#C16, #C16, #C16]
+ #C18 = 16
+ #C19 = <core::int*>[#C18, #C18, #C18]
}
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index 5ead392..209e4df 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -214,6 +214,8 @@
final Class opaqueClass;
final Class pointerClass;
final Class structClass;
+ final Class ffiStructLayoutClass;
+ final Field ffiStructLayoutTypesField;
final Procedure allocateMethod;
final Procedure allocatorAllocateMethod;
final Procedure castMethod;
@@ -245,6 +247,9 @@
/// Classes corresponding to [NativeType], indexed by [NativeType].
final List<Class> nativeTypesClasses;
+ Library currentLibrary;
+ IndexedLibrary currentLibraryIndex;
+
FfiTransformer(this.index, this.coreTypes, this.hierarchy,
this.diagnosticReporter, this.referenceFromIndex)
: env = new TypeEnvironment(coreTypes, hierarchy),
@@ -274,6 +279,9 @@
opaqueClass = index.getClass('dart:ffi', 'Opaque'),
pointerClass = index.getClass('dart:ffi', 'Pointer'),
structClass = index.getClass('dart:ffi', 'Struct'),
+ ffiStructLayoutClass = index.getClass('dart:ffi', '_FfiStructLayout'),
+ ffiStructLayoutTypesField =
+ index.getMember('dart:ffi', '_FfiStructLayout', 'fieldTypes'),
allocateMethod = index.getMember('dart:ffi', 'AllocatorAlloc', 'call'),
allocatorAllocateMethod =
index.getMember('dart:ffi', 'Allocator', 'allocate'),
@@ -331,6 +339,16 @@
'DynamicLibraryExtension',
LibraryIndex.tearoffPrefix + 'lookupFunction');
+ @override
+ TreeNode visitLibrary(Library node) {
+ assert(currentLibrary == null);
+ currentLibrary = node;
+ currentLibraryIndex = referenceFromIndex?.lookupLibrary(node);
+ final result = super.visitLibrary(node);
+ currentLibrary = null;
+ return result;
+ }
+
/// Computes the Dart type corresponding to a ffi.[NativeType], returns null
/// if it is not a valid NativeType.
///
@@ -436,6 +454,111 @@
Arguments([StaticInvocation(abiMethod, Arguments([]))]),
listElementAt);
}
+
+ /// Generates an expression that returns a new `Pointer<dartType>` offset
+ /// by [offset] from [pointer].
+ ///
+ /// Sample output:
+ ///
+ /// ```
+ /// _fromAddress<dartType>(pointer.address + #offset)
+ /// ```
+ Expression _pointerOffset(Expression pointer, Expression offset,
+ DartType dartType, int fileOffset) =>
+ StaticInvocation(
+ fromAddressInternal,
+ Arguments([
+ MethodInvocation(
+ PropertyGet(pointer, addressGetter.name, addressGetter)
+ ..fileOffset = fileOffset,
+ numAddition.name,
+ Arguments([offset]),
+ numAddition)
+ ], types: [
+ dartType
+ ]))
+ ..fileOffset = fileOffset;
+
+ /// Generates an expression that returns a new `TypedData` offset
+ /// by [offset] from [typedData].
+ ///
+ /// Sample output:
+ ///
+ /// ```
+ /// TypedData #typedData = typedData;
+ /// #typedData.buffer.asInt8List(#typedData.offsetInBytes + offset, length)
+ /// ```
+ Expression _typedDataOffset(Expression typedData, Expression offset,
+ Expression length, int fileOffset) {
+ final typedDataVar = VariableDeclaration("#typedData",
+ initializer: typedData,
+ type: InterfaceType(typedDataClass, Nullability.nonNullable))
+ ..fileOffset = fileOffset;
+ return Let(
+ typedDataVar,
+ MethodInvocation(
+ PropertyGet(VariableGet(typedDataVar), typedDataBufferGetter.name,
+ typedDataBufferGetter)
+ ..fileOffset = fileOffset,
+ byteBufferAsUint8List.name,
+ Arguments([
+ MethodInvocation(
+ PropertyGet(
+ VariableGet(typedDataVar),
+ typedDataOffsetInBytesGetter.name,
+ typedDataOffsetInBytesGetter)
+ ..fileOffset = fileOffset,
+ numAddition.name,
+ Arguments([offset]),
+ numAddition),
+ length
+ ]),
+ byteBufferAsUint8List));
+ }
+
+ /// Generates an expression that returns a new `TypedDataBase` offset
+ /// by [offset] from [typedDataBase].
+ ///
+ /// If [typedDataBase] is a `Pointer`, returns a `Pointer<dartType>`.
+ /// If [typedDataBase] is a `TypedData` returns a `TypedData`.
+ ///
+ /// Sample output:
+ ///
+ /// ```
+ /// Object #typedDataBase = typedDataBase;
+ /// int #offset = offset;
+ /// #typedDataBase is Pointer ?
+ /// _pointerOffset<dartType>(#typedDataBase, #offset) :
+ /// _typedDataOffset((#typedDataBase as TypedData), #offset, length)
+ /// ```
+ Expression typedDataBaseOffset(Expression typedDataBase, Expression offset,
+ Expression length, DartType dartType, int fileOffset) {
+ final typedDataBaseVar = VariableDeclaration("#typedDataBase",
+ initializer: typedDataBase, type: coreTypes.objectNonNullableRawType)
+ ..fileOffset = fileOffset;
+ final offsetVar = VariableDeclaration("#offset",
+ initializer: offset, type: coreTypes.intNonNullableRawType)
+ ..fileOffset = fileOffset;
+ return BlockExpression(
+ Block([typedDataBaseVar, offsetVar]),
+ ConditionalExpression(
+ IsExpression(VariableGet(typedDataBaseVar),
+ InterfaceType(pointerClass, Nullability.nonNullable)),
+ _pointerOffset(VariableGet(typedDataBaseVar),
+ VariableGet(offsetVar), dartType, fileOffset),
+ _typedDataOffset(
+ StaticInvocation(
+ unsafeCastMethod,
+ Arguments([
+ VariableGet(typedDataBaseVar)
+ ], types: [
+ InterfaceType(typedDataClass, Nullability.nonNullable)
+ ])),
+ VariableGet(offsetVar),
+ length,
+ fileOffset),
+ coreTypes.objectNonNullableRawType));
+ }
}
/// Contains all information collected by _FfiDefinitionTransformer that is
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index b06c63f..5c114c2 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -104,7 +104,7 @@
Map<Class, IndexedClass> indexedStructClasses = {};
Map<Class, Set<Class>> structClassDependencies = {};
Map<Class, bool> fieldsValid = {};
- Map<Class, Map<Abi, StructLayout>> structLayouts = {};
+ Map<Class, StructNativeTypeCfe> structCache = {};
Map<Field, Procedure> replacedGetters = {};
Map<Field, Procedure> replacedSetters = {};
@@ -150,12 +150,11 @@
e.name.length,
e.fileUri);
});
+ } else {
+ // Only visit the ones without cycles.
+ visitClassInTopologicalOrder(component.single);
}
});
-
- final structClassesSorted = connectedComponents.expand((i) => i).toList();
-
- structClassesSorted.forEach(visitClassInTopologicalOrder);
}
@override
@@ -216,6 +215,9 @@
}
bool _isPointerType(DartType type) {
+ if (type is InvalidType) {
+ return false;
+ }
return env.isSubtypeOf(
type,
InterfaceType(pointerClass, Nullability.legacy, [
@@ -226,6 +228,9 @@
}
bool _isStructSubtype(DartType type) {
+ if (type is InvalidType) {
+ return false;
+ }
return env.isSubtypeOf(type, InterfaceType(structClass, Nullability.legacy),
SubtypeCheckMode.ignoringNullabilities);
}
@@ -272,6 +277,8 @@
f.fileOffset,
f.name.text.length,
f.fileUri);
+ // This class is invalid, but continue reporting other errors on it.
+ success = false;
}
}
final nativeTypeAnnos = _getNativeTypeAnnotations(f).toList();
@@ -283,6 +290,8 @@
f.fileOffset,
f.name.text.length,
f.fileUri);
+ // This class is invalid, but continue reporting other errors on it.
+ success = false;
}
if (_isStructSubtype(type)) {
final clazz = (type as InterfaceType).classNode;
@@ -294,6 +303,8 @@
f.fileOffset,
f.name.text.length,
f.fileUri);
+ // This class is invalid, but continue reporting other errors on it.
+ success = false;
} else {
final DartType nativeType = InterfaceType(
nativeTypesClasses[_getFieldType(nativeTypeAnnos.first).index],
@@ -311,6 +322,7 @@
f.fileOffset,
1,
f.location.file);
+ // This class is invalid, but continue reporting other errors on it.
success = false;
}
}
@@ -364,8 +376,7 @@
///
/// Returns the total size of the struct (for all ABIs).
Map<Abi, int> _replaceFields(Class node, IndexedClass indexedClass) {
- final classes = <Class>[];
- final types = <NativeType>[];
+ final types = <NativeTypeCfe>[];
final fields = <int, Field>{};
final getters = <int, Procedure>{};
final setters = <int, Procedure>{};
@@ -374,14 +385,12 @@
for (final Member m in _structFieldMembers(node)) {
final dartType = _structFieldMemberType(m);
- NativeType nativeType;
- Class clazz;
+ NativeTypeCfe type;
if (_isPointerType(dartType)) {
- nativeType = NativeType.kPointer;
- clazz = pointerClass;
+ type = PointerNativeTypeCfe();
} else if (_isStructSubtype(dartType)) {
- nativeType = NativeType.kStruct;
- clazz = (dartType as InterfaceType).classNode;
+ final clazz = (dartType as InterfaceType).classNode;
+ type = structCache[clazz];
if (emptyStructs.contains(clazz)) {
diagnosticReporter.report(
templateFfiEmptyStruct.withArguments(clazz.name),
@@ -392,15 +401,14 @@
} else {
final nativeTypeAnnos = _getNativeTypeAnnotations(m).toList();
if (nativeTypeAnnos.length == 1) {
- clazz = nativeTypeAnnos.first;
- nativeType = _getFieldType(clazz);
+ final clazz = nativeTypeAnnos.first;
+ final nativeType = _getFieldType(clazz);
+ type = PrimitiveNativeTypeCfe(nativeType, clazz);
}
}
- if ((m is Field || (m is Procedure && m.isGetter)) &&
- nativeType != null) {
- types.add(nativeType);
- classes.add(clazz);
+ if ((m is Field || (m is Procedure && m.isGetter)) && type != null) {
+ types.add(type);
if (m is Field) {
fields[i] = m;
}
@@ -417,8 +425,8 @@
}
}
- _annoteStructWithFields(node, classes);
- if (classes.isEmpty) {
+ _annoteStructWithFields(node, types);
+ if (types.isEmpty) {
diagnosticReporter.report(
templateFfiEmptyStructWarning.withArguments(node.name),
node.fileOffset,
@@ -427,11 +435,9 @@
emptyStructs.add(node);
}
- final structLayout = <Abi, StructLayout>{};
- for (final Abi abi in Abi.values) {
- structLayout[abi] = _calculateStructLayout(types, classes, abi);
- }
- structLayouts[node] = structLayout;
+ final structType = StructNativeTypeCfe(node, types);
+ structCache[node] = structType;
+ final structLayout = structType.layout;
for (final i in fields.keys) {
final fieldOffsets = structLayout
@@ -449,11 +455,8 @@
final fieldOffsets = structLayout
.map((Abi abi, StructLayout v) => MapEntry(abi, v.offsets[i]));
Procedure getter = getters[i];
- getter.function.body = _generateGetterStatement(
- getter.function.returnType,
- types[i],
- getter.fileOffset,
- fieldOffsets);
+ getter.function.body = types[i].generateGetterStatement(
+ getter.function.returnType, getter.fileOffset, fieldOffsets, this);
getter.isExternal = false;
}
@@ -461,207 +464,38 @@
final fieldOffsets = structLayout
.map((Abi abi, StructLayout v) => MapEntry(abi, v.offsets[i]));
Procedure setter = setters[i];
- setter.function.body = _generateSetterStatement(
+ setter.function.body = types[i].generateSetterStatement(
setter.function.positionalParameters.single.type,
- types[i],
setter.fileOffset,
fieldOffsets,
- setter.function.positionalParameters.single);
+ setter.function.positionalParameters.single,
+ this);
setter.isExternal = false;
}
return structLayout.map((k, v) => MapEntry(k, v.size));
}
- void _annoteStructWithFields(Class node, List<Class> fieldTypes) {
- final types = fieldTypes.map((Class c) {
- List<DartType> typeArg = const [];
- if (c == pointerClass) {
- typeArg = [
- InterfaceType(pointerClass.superclass, Nullability.nonNullable)
- ];
- }
- return TypeLiteralConstant(
- InterfaceType(c, Nullability.nonNullable, typeArg));
- }).toList();
+ void _annoteStructWithFields(Class node, List<NativeTypeCfe> types) {
+ List<Constant> constants =
+ types.map((t) => t.generateConstant(this)).toList();
node.addAnnotation(ConstantExpression(
InstanceConstant(pragmaClass.reference, [], {
pragmaName.getterReference: StringConstant("vm:ffi:struct-fields"),
- // TODO(dartbug.com/38158): Wrap list in class to be able to encode
- // more information when needed.
- pragmaOptions.getterReference: ListConstant(
- InterfaceType(typeClass, Nullability.nonNullable), types)
+ pragmaOptions.getterReference:
+ InstanceConstant(ffiStructLayoutClass.reference, [], {
+ ffiStructLayoutTypesField.getterReference: ListConstant(
+ InterfaceType(typeClass, Nullability.nonNullable), constants)
+ })
}),
InterfaceType(pragmaClass, Nullability.nonNullable, [])));
}
- Statement _generateGetterStatement(DartType dartType, NativeType type,
- int fileOffset, Map<Abi, int> offsets) {
- final bool isPointer = type == NativeType.kPointer;
- final bool isStruct = type == NativeType.kStruct;
-
- // Sample output:
- // int get x => _loadInt8(pointer, offset);
- //
- // Treat Pointer fields different to get correct behavior without casts:
- // Pointer<Int8> get x =>
- // _fromAddress<Int8>(_loadIntPtr(pointer, offset));
- //
- // Nested structs:
- // MyStruct get x =>
- // MyStruct.#fromTypedDataBase(
- // _addressOf is Pointer ?
- // _fromAddress<MyStruct>((_addressOf as Pointer).address + offset) :
- // (_addressOf as TypedData).buffer.asInt8List(
- // (_addressOf as TypedData).offsetInBytes + offset,
- // size
- // )
- // );
- if (isStruct) {
- final clazz = (dartType as InterfaceType).classNode;
- final constructor = clazz.constructors
- .firstWhere((c) => c.name == Name("#fromTypedDataBase"));
- final lengths =
- structLayouts[clazz].map((key, value) => MapEntry(key, value.size));
- Expression thisDotAddressOf() =>
- PropertyGet(ThisExpression(), addressOfField.name, addressOfField)
- ..fileOffset = fileOffset;
- return ReturnStatement(ConstructorInvocation(
- constructor,
- Arguments([
- ConditionalExpression(
- IsExpression(thisDotAddressOf(),
- InterfaceType(pointerClass, Nullability.legacy)),
- StaticInvocation(
- fromAddressInternal,
- Arguments([
- MethodInvocation(
- PropertyGet(thisDotAddressOf(), addressGetter.name,
- addressGetter)
- ..fileOffset = fileOffset,
- numAddition.name,
- Arguments([runtimeBranchOnLayout(offsets)]),
- numAddition)
- ], types: [
- dartType
- ]))
- ..fileOffset = fileOffset,
- MethodInvocation(
- PropertyGet(
- StaticInvocation(
- unsafeCastMethod,
- Arguments([
- thisDotAddressOf()
- ], types: [
- InterfaceType(typedDataClass, Nullability.legacy)
- ]))
- ..fileOffset = fileOffset,
- typedDataBufferGetter.name,
- typedDataBufferGetter)
- ..fileOffset = fileOffset,
- byteBufferAsUint8List.name,
- Arguments([
- MethodInvocation(
- PropertyGet(
- StaticInvocation(
- unsafeCastMethod,
- Arguments([
- thisDotAddressOf()
- ], types: [
- InterfaceType(
- typedDataClass, Nullability.legacy)
- ]))
- ..fileOffset = fileOffset,
- typedDataOffsetInBytesGetter.name,
- typedDataOffsetInBytesGetter)
- ..fileOffset = fileOffset,
- numAddition.name,
- Arguments([runtimeBranchOnLayout(offsets)]),
- numAddition),
- runtimeBranchOnLayout(lengths)
- ]),
- byteBufferAsUint8List),
- InterfaceType(objectClass, Nullability.nonNullable))
- ]))
- ..fileOffset = fileOffset);
- }
- final loadMethod =
- isPointer ? loadMethods[NativeType.kIntptr] : loadMethods[type];
- Expression getterReturnValue = StaticInvocation(
- loadMethod,
- Arguments([
- PropertyGet(ThisExpression(), addressOfField.name, addressOfField)
- ..fileOffset = fileOffset,
- runtimeBranchOnLayout(offsets)
- ]))
- ..fileOffset = fileOffset;
- if (isPointer) {
- final typeArg = (dartType as InterfaceType).typeArguments.single;
- getterReturnValue = StaticInvocation(
- fromAddressInternal, Arguments([getterReturnValue], types: [typeArg]))
- ..fileOffset = fileOffset;
- }
- return ReturnStatement(getterReturnValue);
- }
-
- Statement _generateSetterStatement(DartType dartType, NativeType type,
- int fileOffset, Map<Abi, int> offsets, VariableDeclaration argument) {
- final bool isPointer = type == NativeType.kPointer;
- final bool isStruct = type == NativeType.kStruct;
-
- // Sample output:
- // set x(int v) => _storeInt8(pointer, offset, v);
- //
- // Treat Pointer fields different to get correct behavior without casts:
- // set x(Pointer<Int8> v) =>
- // _storeIntPtr(pointer, offset, (v as Pointer<Int8>).address);
- //
- // Nested structs:
- // set x(MyStruct v) =>
- // _memCopy(this._address, offset, v._address, 0, size);
- if (isStruct) {
- final clazz = (dartType as InterfaceType).classNode;
- final lengths =
- structLayouts[clazz].map((key, value) => MapEntry(key, value.size));
- return ReturnStatement(StaticInvocation(
- memCopy,
- Arguments([
- PropertyGet(ThisExpression(), addressOfField.name, addressOfField)
- ..fileOffset = fileOffset,
- runtimeBranchOnLayout(offsets),
- PropertyGet(
- VariableGet(argument), addressOfField.name, addressOfField)
- ..fileOffset = fileOffset,
- ConstantExpression(IntConstant(0)),
- runtimeBranchOnLayout(lengths),
- ]))
- ..fileOffset = fileOffset);
- }
- final storeMethod =
- isPointer ? storeMethods[NativeType.kIntptr] : storeMethods[type];
- Expression argumentExpression = VariableGet(argument)
- ..fileOffset = fileOffset;
- if (isPointer) {
- argumentExpression =
- PropertyGet(argumentExpression, addressGetter.name, addressGetter)
- ..fileOffset = fileOffset;
- }
- return ReturnStatement(StaticInvocation(
- storeMethod,
- Arguments([
- PropertyGet(ThisExpression(), addressOfField.name, addressOfField)
- ..fileOffset = fileOffset,
- runtimeBranchOnLayout(offsets),
- argumentExpression
- ]))
- ..fileOffset = fileOffset);
- }
-
- List<Procedure> _generateMethodsForField(Field field, NativeType type,
+ List<Procedure> _generateMethodsForField(Field field, NativeTypeCfe type,
Map<Abi, int> offsets, IndexedClass indexedClass) {
- final getterStatement =
- _generateGetterStatement(field.type, type, field.fileOffset, offsets);
+ final getterStatement = type.generateGetterStatement(
+ field.type, field.fileOffset, offsets, this);
final Procedure getter = Procedure(field.name, ProcedureKind.Getter,
FunctionNode(getterStatement, returnType: field.type),
fileUri: field.fileUri,
@@ -674,8 +508,8 @@
final VariableDeclaration argument =
VariableDeclaration('#v', type: field.type)
..fileOffset = field.fileOffset;
- final setterStatement = _generateSetterStatement(
- field.type, type, field.fileOffset, offsets, argument);
+ final setterStatement = type.generateSetterStatement(
+ field.type, field.fileOffset, offsets, argument, this);
setter = Procedure(
field.name,
ProcedureKind.Setter,
@@ -711,64 +545,6 @@
struct.addField(sizeOf);
}
- int _sizeInBytes(NativeType type, Class clazz, Abi abi) {
- if (type == NativeType.kStruct) {
- final structLayout = structLayouts[clazz];
- if (structLayout == null) {
- // We have a cycle, so we don't know the size.
- return 0;
- }
- return structLayout[abi].size;
- }
- final int size = nativeTypeSizes[type.index];
- if (size == WORD_SIZE) {
- return wordSize[abi];
- }
- return size;
- }
-
- int _alignmentOf(NativeType type, Class clazz, Abi abi) {
- if (type == NativeType.kStruct) {
- final structLayout = structLayouts[clazz];
- if (structLayout == null) {
- // We have a cycle, so we don't know the size.
- return 0;
- }
- return structLayout[abi].alignment;
- }
- final int alignment = nonSizeAlignment[abi][type];
- if (alignment != null) return alignment;
- return _sizeInBytes(type, clazz, abi);
- }
-
- int _alignOffset(int offset, int alignment) {
- final int remainder = offset % alignment;
- if (remainder != 0) {
- offset -= remainder;
- offset += alignment;
- }
- return offset;
- }
-
- // Keep consistent with runtime/vm/compiler/ffi/native_type.cc
- // NativeCompoundType::FromNativeTypes.
- StructLayout _calculateStructLayout(
- List<NativeType> types, List<Class> classes, Abi abi) {
- int offset = 0;
- final offsets = <int>[];
- int structAlignment = 1;
- for (int i = 0; i < types.length; i++) {
- final int size = _sizeInBytes(types[i], classes[i], abi);
- final int alignment = _alignmentOf(types[i], classes[i], abi);
- offset = _alignOffset(offset, alignment);
- offsets.add(offset);
- offset += size;
- structAlignment = math.max(structAlignment, alignment);
- }
- final int size = _alignOffset(offset, structAlignment);
- return StructLayout(size, structAlignment, offsets);
- }
-
void _makeEntryPoint(Annotatable node) {
node.addAnnotation(ConstantExpression(
InstanceConstant(pragmaClass.reference, [], {
@@ -811,3 +587,275 @@
StructLayout(this.size, this.alignment, this.offsets);
}
+
+/// AST node wrapper for native types.
+///
+/// This algebraic data structure does not stand on its own but refers
+/// intimately to AST nodes such as [Class].
+abstract class NativeTypeCfe {
+ /// The size in bytes per [Abi].
+ Map<Abi, int> get size;
+
+ /// The alignment inside structs in bytes per [Abi].
+ ///
+ /// This is not the alignment on stack, this is only calculated in the VM.
+ Map<Abi, int> get alignment;
+
+ /// Generates a Constant representing the type which is consumed by the VM.
+ ///
+ /// Takes [transformer] to be able to lookup classes and methods.
+ ///
+ /// See runtime/vm/compiler/ffi/native_type.cc:NativeType::FromAbstractType.
+ Constant generateConstant(FfiTransformer transformer);
+
+ /// Generates the return statement for a struct field getter with this type.
+ ///
+ /// Takes [transformer] to be able to lookup classes and methods.
+ ReturnStatement generateGetterStatement(DartType dartType, int fileOffset,
+ Map<Abi, int> offsets, FfiTransformer transformer);
+
+ /// Generates the return statement for a struct field setter with this type.
+ ///
+ /// Takes [transformer] to be able to lookup classes and methods.
+ ReturnStatement generateSetterStatement(
+ DartType dartType,
+ int fileOffset,
+ Map<Abi, int> offsets,
+ VariableDeclaration argument,
+ FfiTransformer transformer);
+}
+
+class PrimitiveNativeTypeCfe implements NativeTypeCfe {
+ final NativeType nativeType;
+
+ final Class clazz;
+
+ PrimitiveNativeTypeCfe(this.nativeType, this.clazz);
+
+ @override
+ Map<Abi, int> get size {
+ final int size = nativeTypeSizes[nativeType.index];
+ if (size == WORD_SIZE) {
+ return wordSize;
+ }
+ return Map.fromEntries(Abi.values.map((abi) => MapEntry(abi, size)));
+ }
+
+ @override
+ Map<Abi, int> get alignment => Map.fromEntries(Abi.values.map(
+ (abi) => MapEntry(abi, nonSizeAlignment[abi][nativeType] ?? size[abi])));
+
+ @override
+ Constant generateConstant(FfiTransformer transformer) =>
+ TypeLiteralConstant(InterfaceType(clazz, Nullability.nonNullable));
+
+ /// Sample output for `int get x =>`:
+ ///
+ /// ```
+ /// _loadInt8(_addressOf, offset);
+ /// ```
+ @override
+ ReturnStatement generateGetterStatement(DartType dartType, int fileOffset,
+ Map<Abi, int> offsets, FfiTransformer transformer) =>
+ ReturnStatement(StaticInvocation(
+ transformer.loadMethods[nativeType],
+ Arguments([
+ PropertyGet(ThisExpression(), transformer.addressOfField.name,
+ transformer.addressOfField)
+ ..fileOffset = fileOffset,
+ transformer.runtimeBranchOnLayout(offsets)
+ ]))
+ ..fileOffset = fileOffset);
+
+ /// Sample output for `set x(int #v) =>`:
+ ///
+ /// ```
+ /// _storeInt8(_addressOf, offset, #v);
+ /// ```
+ @override
+ ReturnStatement generateSetterStatement(
+ DartType dartType,
+ int fileOffset,
+ Map<Abi, int> offsets,
+ VariableDeclaration argument,
+ FfiTransformer transformer) =>
+ ReturnStatement(StaticInvocation(
+ transformer.storeMethods[nativeType],
+ Arguments([
+ PropertyGet(ThisExpression(), transformer.addressOfField.name,
+ transformer.addressOfField)
+ ..fileOffset = fileOffset,
+ transformer.runtimeBranchOnLayout(offsets),
+ VariableGet(argument)
+ ]))
+ ..fileOffset = fileOffset);
+}
+
+class PointerNativeTypeCfe implements NativeTypeCfe {
+ @override
+ Map<Abi, int> get size => wordSize;
+
+ @override
+ Map<Abi, int> get alignment => wordSize;
+
+ @override
+ Constant generateConstant(FfiTransformer transformer) => TypeLiteralConstant(
+ InterfaceType(transformer.pointerClass, Nullability.nonNullable, [
+ InterfaceType(
+ transformer.pointerClass.superclass, Nullability.nonNullable)
+ ]));
+
+ /// Sample output for `Pointer<Int8> get x =>`:
+ ///
+ /// ```
+ /// _fromAddress<Int8>(_loadIntPtr(_addressOf, offset));
+ /// ```
+ @override
+ ReturnStatement generateGetterStatement(DartType dartType, int fileOffset,
+ Map<Abi, int> offsets, FfiTransformer transformer) =>
+ ReturnStatement(StaticInvocation(
+ transformer.fromAddressInternal,
+ Arguments([
+ StaticInvocation(
+ transformer.loadMethods[NativeType.kIntptr],
+ Arguments([
+ PropertyGet(ThisExpression(), transformer.addressOfField.name,
+ transformer.addressOfField)
+ ..fileOffset = fileOffset,
+ transformer.runtimeBranchOnLayout(offsets)
+ ]))
+ ..fileOffset = fileOffset
+ ], types: [
+ (dartType as InterfaceType).typeArguments.single
+ ]))
+ ..fileOffset = fileOffset);
+
+ /// Sample output for `set x(Pointer<Int8> #v) =>`:
+ ///
+ /// ```
+ /// _storeIntPtr(_addressOf, offset, (#v as Pointer<Int8>).address);
+ /// ```
+ @override
+ ReturnStatement generateSetterStatement(
+ DartType dartType,
+ int fileOffset,
+ Map<Abi, int> offsets,
+ VariableDeclaration argument,
+ FfiTransformer transformer) =>
+ ReturnStatement(StaticInvocation(
+ transformer.storeMethods[NativeType.kIntptr],
+ Arguments([
+ PropertyGet(ThisExpression(), transformer.addressOfField.name,
+ transformer.addressOfField)
+ ..fileOffset = fileOffset,
+ transformer.runtimeBranchOnLayout(offsets),
+ PropertyGet(VariableGet(argument), transformer.addressGetter.name,
+ transformer.addressGetter)
+ ..fileOffset = fileOffset
+ ]))
+ ..fileOffset = fileOffset);
+}
+
+class StructNativeTypeCfe implements NativeTypeCfe {
+ final Class clazz;
+
+ final List<NativeTypeCfe> members;
+
+ final Map<Abi, StructLayout> layout;
+
+ factory StructNativeTypeCfe(Class clazz, List<NativeTypeCfe> members) {
+ final layout = Map.fromEntries(
+ Abi.values.map((abi) => MapEntry(abi, _calculateLayout(members, abi))));
+ return StructNativeTypeCfe._(clazz, members, layout);
+ }
+
+ // Keep consistent with runtime/vm/compiler/ffi/native_type.cc
+ // NativeCompoundType::FromNativeTypes.
+ static StructLayout _calculateLayout(List<NativeTypeCfe> types, Abi abi) {
+ int offset = 0;
+ final offsets = <int>[];
+ int structAlignment = 1;
+ for (int i = 0; i < types.length; i++) {
+ final int size = types[i].size[abi];
+ final int alignment = types[i].alignment[abi];
+ offset = _alignOffset(offset, alignment);
+ offsets.add(offset);
+ offset += size;
+ structAlignment = math.max(structAlignment, alignment);
+ }
+ final int size = _alignOffset(offset, structAlignment);
+ return StructLayout(size, structAlignment, offsets);
+ }
+
+ StructNativeTypeCfe._(this.clazz, this.members, this.layout);
+
+ @override
+ Map<Abi, int> get size =>
+ layout.map((abi, layout) => MapEntry(abi, layout.size));
+
+ @override
+ Map<Abi, int> get alignment =>
+ layout.map((abi, layout) => MapEntry(abi, layout.alignment));
+
+ @override
+ Constant generateConstant(FfiTransformer transformer) =>
+ TypeLiteralConstant(InterfaceType(clazz, Nullability.nonNullable));
+
+ /// Sample output for `MyStruct get x =>`:
+ ///
+ /// ```
+ /// MyStruct.#fromTypedDataBase(
+ /// typedDataBaseOffset(_addressOf, offset, size, dartType)
+ /// );
+ /// ```
+ @override
+ ReturnStatement generateGetterStatement(DartType dartType, int fileOffset,
+ Map<Abi, int> offsets, FfiTransformer transformer) {
+ final constructor = clazz.constructors
+ .firstWhere((c) => c.name == Name("#fromTypedDataBase"));
+
+ return ReturnStatement(ConstructorInvocation(
+ constructor,
+ Arguments([
+ transformer.typedDataBaseOffset(
+ PropertyGet(ThisExpression(), transformer.addressOfField.name,
+ transformer.addressOfField)
+ ..fileOffset = fileOffset,
+ transformer.runtimeBranchOnLayout(offsets),
+ transformer.runtimeBranchOnLayout(size),
+ dartType,
+ fileOffset)
+ ]))
+ ..fileOffset = fileOffset);
+ }
+
+ /// Sample output for `set x(MyStruct #v) =>`:
+ ///
+ /// ```
+ /// _memCopy(_addressOf, offset, #v._addressOf, 0, size);
+ /// ```
+ @override
+ ReturnStatement generateSetterStatement(
+ DartType dartType,
+ int fileOffset,
+ Map<Abi, int> offsets,
+ VariableDeclaration argument,
+ FfiTransformer transformer) =>
+ ReturnStatement(StaticInvocation(
+ transformer.memCopy,
+ Arguments([
+ PropertyGet(ThisExpression(), transformer.addressOfField.name,
+ transformer.addressOfField)
+ ..fileOffset = fileOffset,
+ transformer.runtimeBranchOnLayout(offsets),
+ PropertyGet(VariableGet(argument), transformer.addressOfField.name,
+ transformer.addressOfField)
+ ..fileOffset = fileOffset,
+ ConstantExpression(IntConstant(0)),
+ transformer.runtimeBranchOnLayout(size),
+ ]))
+ ..fileOffset = fileOffset);
+}
+
+int _alignOffset(int offset, int alignment) =>
+ ((offset + alignment - 1) ~/ alignment) * alignment;
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 1f0aba6..c03f4b4 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -76,9 +76,7 @@
final Set<Class> emptyStructs;
StaticTypeContext _staticTypeContext;
- Library currentLibrary;
bool get isFfiLibrary => currentLibrary == ffiLibrary;
- IndexedLibrary currentLibraryIndex;
// Used to create private top-level fields with unique names for each
// callback.
@@ -98,8 +96,6 @@
@override
TreeNode visitLibrary(Library node) {
- currentLibrary = node;
- currentLibraryIndex = referenceFromIndex?.lookupLibrary(node);
callbackCount = 0;
return super.visitLibrary(node);
}
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index 1bc116d..e60f6c8 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -523,7 +523,8 @@
// The analytics flags are a special case as we don't have a target script
// or DartDev command but we still want to launch DartDev.
DartDevIsolate::set_should_run_dart_dev(true);
-
+ dart_options->AddArgument(enable_dartdev_analytics ? "--enable-analytics"
+ : "--disable-analytics");
return true;
}
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index a90d4de..11b7f60 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -225,13 +225,13 @@
DEFINE_NATIVE_ENTRY(LibraryPrefix_isLoaded, 0, 1) {
const LibraryPrefix& prefix =
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
- return Bool::Get(prefix.is_loaded()).ptr();
+ return Bool::Get(isolate->IsPrefixLoaded(prefix)).ptr();
}
DEFINE_NATIVE_ENTRY(LibraryPrefix_setLoaded, 0, 1) {
const LibraryPrefix& prefix =
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
- prefix.set_is_loaded(true);
+ isolate->SetPrefixIsLoaded(prefix);
return Instance::null();
}
diff --git a/runtime/tests/vm/dart/deferred_isolate_test.dart b/runtime/tests/vm/dart/deferred_isolate_test.dart
new file mode 100644
index 0000000..d056b31
--- /dev/null
+++ b/runtime/tests/vm/dart/deferred_isolate_test.dart
@@ -0,0 +1,28 @@
+// 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.
+
+// Verify deferred library status is per-isolate, not per-isolate-group.
+
+// VMOptions=--enable_isolate_groups --experimental_enable_isolate_groups_jit
+
+import 'dart:async';
+import 'dart:isolate';
+import 'package:expect/expect.dart';
+
+import "splay_test.dart" deferred as splay;
+
+worker(SendPort sendPort) {
+ Expect.throws(() => splay.main(),
+ (e) => e.toString() == "Deferred library splay was not loaded.");
+ sendPort.send(true);
+}
+
+main() async {
+ await splay.loadLibrary();
+ splay.main();
+ final receivePort = ReceivePort();
+ Isolate.spawn(worker, receivePort.sendPort);
+ Expect.isTrue(await receivePort.first);
+ receivePort.close();
+}
diff --git a/runtime/tests/vm/dart_2/deferred_isolate_test.dart b/runtime/tests/vm/dart_2/deferred_isolate_test.dart
new file mode 100644
index 0000000..d056b31
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deferred_isolate_test.dart
@@ -0,0 +1,28 @@
+// 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.
+
+// Verify deferred library status is per-isolate, not per-isolate-group.
+
+// VMOptions=--enable_isolate_groups --experimental_enable_isolate_groups_jit
+
+import 'dart:async';
+import 'dart:isolate';
+import 'package:expect/expect.dart';
+
+import "splay_test.dart" deferred as splay;
+
+worker(SendPort sendPort) {
+ Expect.throws(() => splay.main(),
+ (e) => e.toString() == "Deferred library splay was not loaded.");
+ sendPort.send(true);
+}
+
+main() async {
+ await splay.loadLibrary();
+ splay.main();
+ final receivePort = ReceivePort();
+ Isolate.spawn(worker, receivePort.sendPort);
+ Expect.isTrue(await receivePort.first);
+ receivePort.close();
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 44a7888..964aafd 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -279,6 +279,10 @@
dart_2/null_safety_autodetection_in_kernel_compiler_test: SkipByDesign # Test needs to run from source
dart_2/snapshot_depfile_test: SkipByDesign # Test needs to run from source
+[ $compiler == dartkp && ($arch == simarm || $arch == simarm64) ]
+dart/causal_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
+dart_2/causal_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
+
[ $compiler == dartkp && ($runtime == dart_precompiled || $runtime == vm) ]
dart/redirection_type_shuffling_test: SkipByDesign # Includes dart:mirrors.
dart/spawn_shutdown_test: SkipSlow
diff --git a/runtime/vm/bitmap.cc b/runtime/vm/bitmap.cc
index 334c46b..52c32db 100644
--- a/runtime/vm/bitmap.cc
+++ b/runtime/vm/bitmap.cc
@@ -42,11 +42,13 @@
void BitmapBuilder::Set(intptr_t bit_offset, bool value) {
if (!InRange(bit_offset)) {
length_ = bit_offset + 1;
- // Bits not covered by the backing store are implicitly false.
- if (!value) return;
- // Grow the backing store if necessary.
- intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
- if (byte_offset >= data_size_in_bytes_) {
+ }
+
+ // Bits not covered by the backing store are implicitly false.
+ // Grow the backing store if necessary.
+ if (value) {
+ if (!InBackingStore(bit_offset)) {
+ intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
uint8_t* old_data = data_;
intptr_t old_size = data_size_in_bytes_;
data_size_in_bytes_ =
@@ -57,8 +59,13 @@
memmove(data_, old_data, old_size);
memset(&data_[old_size], 0, (data_size_in_bytes_ - old_size));
}
+ ASSERT(InBackingStore(bit_offset));
}
- SetBit(bit_offset, value);
+
+ // Set bit if in backing store.
+ if (InBackingStore(bit_offset)) {
+ SetBit(bit_offset, value);
+ }
}
void BitmapBuilder::SetRange(intptr_t min, intptr_t max, bool value) {
diff --git a/runtime/vm/bitmap.h b/runtime/vm/bitmap.h
index ed08009..1fce760 100644
--- a/runtime/vm/bitmap.h
+++ b/runtime/vm/bitmap.h
@@ -60,6 +60,11 @@
return (offset < length_);
}
+ bool InBackingStore(intptr_t bit_offset) {
+ intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
+ return byte_offset < data_size_in_bytes_;
+ }
+
// Get/Set a bit that is known to be covered by the backing store.
bool GetBit(intptr_t bit_offset) const;
void SetBit(intptr_t bit_offset, bool value);
diff --git a/runtime/vm/bitmap_test.cc b/runtime/vm/bitmap_test.cc
index c3cd203..2fdab17 100644
--- a/runtime/vm/bitmap_test.cc
+++ b/runtime/vm/bitmap_test.cc
@@ -131,4 +131,14 @@
EXPECT(builder1->Get(900));
}
+ISOLATE_UNIT_TEST_CASE(BitmapBuilder_Regress44946) {
+ BitmapBuilder* builder1 = new BitmapBuilder();
+ EXPECT_EQ(0, builder1->Length());
+
+ builder1->Set(10000, false);
+ EXPECT_EQ(10001, builder1->Length());
+ builder1->Set(9999, true);
+ EXPECT(builder1->Get(9999));
+}
+
} // namespace dart
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index b623a08..45bced2 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -3360,7 +3360,6 @@
ReadFromTo(prefix);
prefix->untag()->num_imports_ = d->Read<uint16_t>();
prefix->untag()->is_deferred_load_ = d->Read<bool>();
- prefix->untag()->is_loaded_ = !prefix->untag()->is_deferred_load_;
}
}
};
diff --git a/runtime/vm/compiler/assembler/disassembler_arm.cc b/runtime/vm/compiler/assembler/disassembler_arm.cc
index 2195070..946c402 100644
--- a/runtime/vm/compiler/assembler/disassembler_arm.cc
+++ b/runtime/vm/compiler/assembler/disassembler_arm.cc
@@ -104,24 +104,11 @@
Print(cond_names[instr->ConditionField()]);
}
-// These register names are defined in a way to match the native disassembler
-// formatting, except for register alias pp (r5).
-// See for example the command "objdump -d <binary file>".
-static const char* reg_names[kNumberOfCpuRegisters] = {
-#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
- "r0", "r1", "r2", "r3", "r4", "pp", "r6", "fp",
- "r8", "r9", "thr", "r11", "ip", "sp", "lr", "pc",
-#else
- "r0", "r1", "r2", "r3", "r4", "pp", "r6", "r7",
- "r8", "r9", "thr", "fp", "ip", "sp", "lr", "pc",
-#endif
-};
-
// Print the register name according to the active name converter.
void ARMDecoder::PrintRegister(int reg) {
ASSERT(0 <= reg);
ASSERT(reg < kNumberOfCpuRegisters);
- Print(reg_names[reg]);
+ Print(cpu_reg_names[reg]);
}
void ARMDecoder::PrintSRegister(int reg) {
diff --git a/runtime/vm/compiler/assembler/disassembler_arm64.cc b/runtime/vm/compiler/assembler/disassembler_arm64.cc
index e0992ae..fad4210 100644
--- a/runtime/vm/compiler/assembler/disassembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/disassembler_arm64.cc
@@ -80,15 +80,6 @@
buffer_[buffer_pos_] = '\0';
}
-// These register names are defined in a way to match the native disassembler
-// formatting, except for register aliases ctx (r9), pp (r10) and sp (r19).
-// See for example the command "objdump -d <binary file>".
-static const char* reg_names[kNumberOfCpuRegisters] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
- "r11", "r12", "r13", "r14", "r15", "ip0", "ip1", "r18", "sp", "r20", "r21",
- "nr", "r23", "r24", "r25", "thr", "pp", "ctx", "fp", "lr", "r31",
-};
-
// Print the register name according to the active name converter.
void ARM64Decoder::PrintRegister(int reg, R31Type r31t) {
ASSERT(0 <= reg);
@@ -97,7 +88,7 @@
const char* rstr = (r31t == R31IsZR) ? "zr" : "csp";
Print(rstr);
} else {
- Print(reg_names[reg]);
+ Print(cpu_reg_names[reg]);
}
}
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index ce2f680..acb987e 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -2266,13 +2266,15 @@
bool FlowGraphInliner::FunctionHasPreferInlinePragma(const Function& function) {
Object& options = Object::Handle();
return Library::FindPragma(dart::Thread::Current(), /*only_core=*/false,
- function, Symbols::vm_prefer_inline(), &options);
+ function, Symbols::vm_prefer_inline(),
+ /*multiple=*/false, &options);
}
bool FlowGraphInliner::FunctionHasNeverInlinePragma(const Function& function) {
Object& options = Object::Handle();
return Library::FindPragma(dart::Thread::Current(), /*only_core=*/false,
- function, Symbols::vm_never_inline(), &options);
+ function, Symbols::vm_never_inline(),
+ /*multiple=*/false, &options);
}
bool FlowGraphInliner::AlwaysInline(const Function& function) {
@@ -2891,7 +2893,6 @@
(*entry)->InheritDeoptTarget(Z, call);
Instruction* cursor = *entry;
-
// Generates a template for the load, either a dynamic conditional
// that dispatches on external and internal storage, or a single
// case that deals with either external or internal storage.
diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc
index 03d3c39..d63933e 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination.cc
+++ b/runtime/vm/compiler/backend/redundancy_elimination.cc
@@ -4230,7 +4230,8 @@
Object& options = Object::Handle();
return Library::FindPragma(dart::Thread::Current(),
/*only_core=*/false, function,
- Symbols::vm_unsafe_no_interrupts(), &options);
+ Symbols::vm_unsafe_no_interrupts(),
+ /*multiple=*/false, &options);
}
void CheckStackOverflowElimination::EliminateStackOverflow(FlowGraph* graph) {
diff --git a/runtime/vm/compiler/backend/type_propagator_test.cc b/runtime/vm/compiler/backend/type_propagator_test.cc
index a278009..1090bc9 100644
--- a/runtime/vm/compiler/backend/type_propagator_test.cc
+++ b/runtime/vm/compiler/backend/type_propagator_test.cc
@@ -467,7 +467,7 @@
auto expected_can_be_smi = [&](const Field& f) {
auto& options = Object::Handle();
return lib.FindPragma(thread, /*only_core=*/false, f, pragma_can_be_smi,
- &options);
+ /*multiple=*/false, &options);
};
const auto& cls = Class::Handle(GetClass(lib, "C"));
diff --git a/runtime/vm/compiler/ffi/native_type.cc b/runtime/vm/compiler/ffi/native_type.cc
index 7e1ade5..0e0d125 100644
--- a/runtime/vm/compiler/ffi/native_type.cc
+++ b/runtime/vm/compiler/ffi/native_type.cc
@@ -366,21 +366,57 @@
// User-defined structs.
const auto& cls = Class::Handle(zone, type.type_class());
- auto& options = Object::Handle(zone);
+ auto& pragmas = Object::Handle(zone);
Library::FindPragma(dart::Thread::Current(), /*only_core=*/false, cls,
- Symbols::vm_ffi_struct_fields(), &options);
- ASSERT(!options.IsNull());
- ASSERT(options.IsArray());
+ Symbols::vm_ffi_struct_fields(), /*multiple=*/true,
+ &pragmas);
+ ASSERT(!pragmas.IsNull());
+ ASSERT(pragmas.IsGrowableObjectArray());
+ const auto& pragmas_array = GrowableObjectArray::Cast(pragmas);
+ auto& pragma = Instance::Handle(zone);
+ auto& clazz = Class::Handle(zone);
+ auto& library = Library::Handle(zone);
+ for (intptr_t i = 0; i < pragmas_array.Length(); i++) {
+ pragma ^= pragmas_array.At(i);
+ clazz ^= pragma.clazz();
+ library ^= clazz.library();
+ if (String::Handle(zone, clazz.UserVisibleName())
+ .Equals(Symbols::FfiStructLayout()) &&
+ String::Handle(zone, library.url()).Equals(Symbols::DartFfi())) {
+ break;
+ }
+ }
- const auto& field_types = Array::Cast(options);
+ const auto& struct_layout = pragma;
+ const auto& struct_layout_class = clazz;
+ ASSERT(String::Handle(zone, struct_layout_class.UserVisibleName())
+ .Equals(Symbols::FfiStructLayout()));
+ ASSERT(String::Handle(zone, library.url()).Equals(Symbols::DartFfi()));
+ const auto& struct_layout_fields = Array::Handle(zone, clazz.fields());
+ ASSERT(struct_layout_fields.Length() == 1);
+ const auto& field =
+ Field::Handle(zone, Field::RawCast(struct_layout_fields.At(0)));
+ ASSERT(String::Handle(zone, field.name()).Equals(Symbols::FfiFieldTypes()));
+ const auto& field_types =
+ Array::Handle(zone, Array::RawCast(struct_layout.GetField(field)));
+
+ auto& field_instance = Instance::Handle(zone);
auto& field_type = AbstractType::Handle(zone);
auto& field_native_types = *new (zone) ZoneGrowableArray<const NativeType*>(
zone, field_types.Length());
for (intptr_t i = 0; i < field_types.Length(); i++) {
- field_type ^= field_types.At(i);
- const NativeType& field_native_type =
- NativeType::FromAbstractType(zone, field_type);
- field_native_types.Add(&field_native_type);
+ field_instance ^= field_types.At(i);
+ if (field_instance.IsAbstractType()) {
+ // Subtype of NativeType: Struct, native integer or native float.
+ field_type ^= field_types.At(i);
+ const auto& field_native_type =
+ NativeType::FromAbstractType(zone, field_type);
+ field_native_types.Add(&field_native_type);
+ } else {
+ // Inline array.
+ // TODO(http://dartbug.com/35763): Implement this.
+ UNIMPLEMENTED();
+ }
}
return NativeCompoundType::FromNativeTypes(zone, field_native_types);
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index c931003..f8fd87c 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -1121,7 +1121,8 @@
Object& options = Object::Handle(Z);
if (!Library::FindPragma(thread_, /*only_core=*/false, function,
- Symbols::vm_trace_entrypoints(), &options) ||
+ Symbols::vm_trace_entrypoints(), /*multiple=*/false,
+ &options) ||
options.IsNull() || !options.IsClosure()) {
return Drop();
}
diff --git a/runtime/vm/compiler/method_recognizer.cc b/runtime/vm/compiler/method_recognizer.cc
index 3abd57b..6a6bd41 100644
--- a/runtime/vm/compiler/method_recognizer.cc
+++ b/runtime/vm/compiler/method_recognizer.cc
@@ -29,7 +29,8 @@
auto Z = T->zone();
auto& option = Object::Handle(Z);
if (Library::FindPragma(T, /*only_core=*/true, function_or_field,
- Symbols::vm_exact_result_type(), &option)) {
+ Symbols::vm_exact_result_type(),
+ /*multiple=*/false, &option)) {
if (option.IsType()) {
return Type::Cast(option).type_class_id();
} else if (option.IsString()) {
@@ -82,7 +83,8 @@
auto Z = T->zone();
auto& option = Object::Handle(Z);
if (Library::FindPragma(T, /*only_core=*/true, function_or_field,
- Symbols::vm_non_nullable_result_type(), &option)) {
+ Symbols::vm_non_nullable_result_type(),
+ /*multiple=*/false, &option)) {
return true;
}
@@ -203,9 +205,9 @@
? &Function::Handle(function.ForwardingTarget())
: &function;
Object& options = Object::Handle();
- bool is_recognized =
- Library::FindPragma(Thread::Current(), /*only_core=*/true, *functionp,
- Symbols::vm_recognized(), &options);
+ bool is_recognized = Library::FindPragma(
+ Thread::Current(), /*only_core=*/true, *functionp,
+ Symbols::vm_recognized(), /*multiple=*/false, &options);
if (!is_recognized) return false;
if (kind == nullptr) return true;
diff --git a/runtime/vm/constants_arm.cc b/runtime/vm/constants_arm.cc
index 1f33275..21ae852 100644
--- a/runtime/vm/constants_arm.cc
+++ b/runtime/vm/constants_arm.cc
@@ -13,8 +13,13 @@
using dart::bit_cast;
const char* cpu_reg_names[kNumberOfCpuRegisters] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "ctx", "pp", "fp", "ip", "sp", "lr", "pc",
+#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
+ "r0", "r1", "r2", "r3", "r4", "pp", "r6", "fp",
+ "r8", "r9", "thr", "r11", "ip", "sp", "lr", "pc",
+#else
+ "r0", "r1", "r2", "r3", "r4", "pp", "r6", "r7",
+ "r8", "r9", "thr", "fp", "ip", "sp", "lr", "pc",
+#endif
};
const char* fpu_reg_names[kNumberOfFpuRegisters] = {
diff --git a/runtime/vm/constants_arm64.cc b/runtime/vm/constants_arm64.cc
index e0999b9..7945838 100644
--- a/runtime/vm/constants_arm64.cc
+++ b/runtime/vm/constants_arm64.cc
@@ -13,7 +13,7 @@
const char* cpu_reg_names[kNumberOfCpuRegisters] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
"r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21",
- "nr", "r23", "r24", "ip0", "ip1", "pp", "ctx", "fp", "lr", "r31",
+ "nr", "r23", "r24", "ip0", "ip1", "pp", "r28", "fp", "lr", "r31",
};
const char* fpu_reg_names[kNumberOfFpuRegisters] = {
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index d5242f1..da4d058 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -21,9 +21,9 @@
ECX = 1,
EDX = 2,
EBX = 3,
- ESP = 4,
- EBP = 5,
- ESI = 6,
+ ESP = 4, // SP
+ EBP = 5, // FP
+ ESI = 6, // THR
EDI = 7,
kNumberOfCpuRegisters = 8,
kNoRegister = -1, // Signals an illegal register.
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index 8ebeb8e..d8ffa7c 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -21,8 +21,8 @@
RCX = 1,
RDX = 2,
RBX = 3,
- RSP = 4,
- RBP = 5,
+ RSP = 4, // SP
+ RBP = 5, // FP
RSI = 6,
RDI = 7,
R8 = 8,
@@ -31,8 +31,8 @@
R11 = 11,
R12 = 12,
R13 = 13,
- R14 = 14,
- R15 = 15,
+ R14 = 14, // THR
+ R15 = 15, // PP
kNumberOfCpuRegisters = 16,
kNoRegister = -1, // Signals an illegal register.
};
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 76e5444..c1259f2 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -978,6 +978,8 @@
const UserTag& default_tag = UserTag::Handle(UserTag::DefaultTag());
I->set_current_tag(default_tag);
+ I->init_loaded_prefixes_set_storage();
+
return Error::null();
}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 84cb544..5fff56a 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1661,6 +1661,24 @@
#define REUSABLE_HANDLE_INITIALIZERS(object) object##_handle_(nullptr),
+class LibraryPrefixMapTraits {
+ public:
+ static bool ReportStats() { return false; }
+ static const char* Name() { return "LibraryPrefixMapTraits"; }
+
+ static bool IsMatch(const Object& a, const Object& b) {
+ if (!a.IsLibraryPrefix() || !b.IsLibraryPrefix()) {
+ return false;
+ }
+ return a.ptr() == b.ptr();
+ }
+
+ static uword Hash(const Object& obj) {
+ auto& prefix = LibraryPrefix::Cast(obj);
+ return String::Hash(prefix.name());
+ }
+};
+
// TODO(srdjan): Some Isolate monitors can be shared. Replace their usage with
// that shared monitor.
Isolate::Isolate(IsolateGroup* isolate_group,
@@ -1699,7 +1717,8 @@
sticky_error_(Error::null()),
spawn_count_monitor_(),
handler_info_cache_(),
- catch_entry_moves_cache_() {
+ catch_entry_moves_cache_(),
+ loaded_prefixes_set_storage_(nullptr) {
cached_object_store_ = object_store_shared_ptr_.get();
cached_class_table_table_ = group()->class_table_->table();
FlagsCopyFrom(api_flags);
@@ -2621,6 +2640,9 @@
deopt_context()->VisitObjectPointers(visitor);
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
+
+ visitor->VisitPointer(
+ reinterpret_cast<ObjectPtr*>(&loaded_prefixes_set_storage_));
}
void IsolateGroup::ReleaseStoreBuffers() {
@@ -2639,6 +2661,27 @@
}
}
+void Isolate::init_loaded_prefixes_set_storage() {
+ ASSERT(loaded_prefixes_set_storage_ == nullptr);
+ loaded_prefixes_set_storage_ =
+ HashTables::New<UnorderedHashSet<LibraryPrefixMapTraits> >(4);
+}
+
+bool Isolate::IsPrefixLoaded(const LibraryPrefix& prefix) const {
+ UnorderedHashSet<LibraryPrefixMapTraits> loaded_prefixes_set(
+ loaded_prefixes_set_storage_);
+ bool result = loaded_prefixes_set.GetOrNull(prefix) != Object::null();
+ loaded_prefixes_set.Release();
+ return result;
+}
+
+void Isolate::SetPrefixIsLoaded(const LibraryPrefix& prefix) {
+ UnorderedHashSet<LibraryPrefixMapTraits> loaded_prefixes_set(
+ loaded_prefixes_set_storage_);
+ loaded_prefixes_set.InsertOrGet(prefix);
+ loaded_prefixes_set_storage_ = loaded_prefixes_set.Release().ptr();
+}
+
void IsolateGroup::EnableIncrementalBarrier(
MarkingStack* marking_stack,
MarkingStack* deferred_marking_stack) {
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index ceca443..fefa565 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -1460,6 +1460,10 @@
regexp_backtracking_stack_cache_ = std::move(stack);
}
+ void init_loaded_prefixes_set_storage();
+ bool IsPrefixLoaded(const LibraryPrefix& prefix) const;
+ void SetPrefixIsLoaded(const LibraryPrefix& prefix);
+
private:
friend class Dart; // Init, InitOnce, Shutdown.
friend class IsolateKillerVisitor; // Kill().
@@ -1694,6 +1698,8 @@
static Monitor* isolate_creation_monitor_;
static bool creation_enabled_;
+ ArrayPtr loaded_prefixes_set_storage_;
+
#define REUSABLE_FRIEND_DECLARATION(name) \
friend class Reusable##name##HandleScope;
REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION)
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index dcb54c3..4b38596 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -3621,6 +3621,7 @@
bool only_core,
const Object& obj,
const String& pragma_name,
+ bool multiple,
Object* options) {
auto IG = T->isolate_group();
auto Z = T->zone();
@@ -3666,6 +3667,13 @@
Field::Handle(Z, pragma_class.LookupField(Symbols::options()));
auto& pragma = Object::Handle(Z);
+ bool found = false;
+ auto& options_value = Object::Handle(Z);
+ auto& results = GrowableObjectArray::Handle(Z);
+ if (multiple) {
+ ASSERT(options != nullptr);
+ results ^= GrowableObjectArray::New(1);
+ }
for (intptr_t i = 0; i < metadata.Length(); ++i) {
pragma = metadata.At(i);
if (pragma.clazz() != pragma_class.ptr() ||
@@ -3673,13 +3681,22 @@
pragma_name.ptr()) {
continue;
}
+ options_value = Instance::Cast(pragma).GetField(pragma_options_field);
+ found = true;
+ if (multiple) {
+ results.Add(options_value);
+ continue;
+ }
if (options != nullptr) {
- *options = Instance::Cast(pragma).GetField(pragma_options_field);
+ *options = options_value.ptr();
}
return true;
}
- return false;
+ if (found && options != nullptr) {
+ *options = results.ptr();
+ }
+ return found;
}
bool Function::IsDynamicInvocationForwarderName(const String& name) {
@@ -13450,7 +13467,6 @@
result.set_num_imports(0);
result.set_importer(importer);
result.StoreNonPointer(&result.untag()->is_deferred_load_, deferred_load);
- result.StoreNonPointer(&result.untag()->is_loaded_, !deferred_load);
result.set_imports(Array::Handle(Array::New(kInitialSize)));
result.AddImport(import);
return result.ptr();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 0739a20..5cf9f6c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -4658,12 +4658,16 @@
// If [only_core] is true, then the annotations on the object will only
// be inspected if it is part of a core library.
//
+ // If [multiple] is true, then sets [options] to an GrowableObjectArray
+ // containing all results and [options] may not be nullptr.
+ //
// WARNING: If the isolate received an [UnwindError] this function will not
// return and rather unwinds until the enclosing setjmp() handler.
static bool FindPragma(Thread* T,
bool only_core,
const Object& object,
const String& pragma_name,
+ bool multiple = false,
Object* options = nullptr);
ClassPtr toplevel_class() const { return untag()->toplevel_class(); }
@@ -6144,11 +6148,9 @@
explicit Comments(const Array& comments);
// Layout of entries describing comments.
- enum {
- kPCOffsetEntry = 0, // PC offset to a comment as a Smi.
- kCommentEntry, // Comment text as a String.
- kNumberOfEntries
- };
+ enum {kPCOffsetEntry = 0, // PC offset to a comment as a Smi.
+ kCommentEntry, // Comment text as a String.
+ kNumberOfEntries};
const Array& comments_;
String& string_;
@@ -7262,10 +7264,6 @@
void AddImport(const Namespace& import) const;
bool is_deferred_load() const { return untag()->is_deferred_load_; }
- bool is_loaded() const { return untag()->is_loaded_; }
- void set_is_loaded(bool value) const {
- return StoreNonPointer(&untag()->is_loaded_, value);
- }
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(UntaggedLibraryPrefix));
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index e9c33b4..d4472ac 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -852,12 +852,9 @@
original_name = original_prefix.name();
if (!name.Equals(original_name)) continue;
- if (original_prefix.is_loaded()) {
- prefix.set_is_loaded(true);
- }
-
- // The old prefix may be captured in the message queue for a pending load
- // completion. This pending load should carry to the new prefix.
+ // The replacement of the old prefix with the new prefix
+ // in Isolate::loaded_prefixes_set_ implicitly carried
+ // the loaded state over to the new prefix.
context->AddBecomeMapping(original_prefix, prefix);
}
}
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 8c041a2..ca51cc9 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -2239,7 +2239,6 @@
}
uint16_t num_imports_; // Number of library entries in libraries_.
bool is_deferred_load_;
- bool is_loaded_;
};
class UntaggedTypeArguments : public UntaggedInstance {
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 39dfa25..631c7a8 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -124,6 +124,7 @@
V(FfiCallback, "_FfiCallback") \
V(FfiDouble, "Double") \
V(FfiDynamicLibrary, "DynamicLibrary") \
+ V(FfiFieldTypes, "fieldTypes") \
V(FfiFloat, "Float") \
V(FfiInt16, "Int16") \
V(FfiInt32, "Int32") \
@@ -133,6 +134,7 @@
V(FfiNativeFunction, "NativeFunction") \
V(FfiNativeType, "NativeType") \
V(FfiPointer, "Pointer") \
+ V(FfiStructLayout, "_FfiStructLayout") \
V(FfiTrampolineData, "FfiTrampolineData") \
V(FfiUint16, "Uint16") \
V(FfiUint32, "Uint32") \
diff --git a/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart b/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart
index 8fad967..489dd6e 100644
--- a/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart
@@ -10,3 +10,11 @@
@pragma("vm:entry-point")
abstract class Struct extends NativeType {}
+
+@pragma("vm:entry-point")
+class _FfiStructLayout {
+ @pragma("vm:entry-point")
+ final List<Type> fieldTypes;
+
+ const _FfiStructLayout(this.fieldTypes);
+}
diff --git a/tools/VERSION b/tools/VERSION
index a31069b..de4905b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 26
+PRERELEASE 27
PRERELEASE_PATCH 0
\ No newline at end of file