Version 2.16.0-19.0.dev
Merge commit 'db642a008af38273faee13066f246f8659637673' into 'dev'
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index 629101e..10e4cf9 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -482,7 +482,9 @@
return (node is ast.InvocationExpression &&
!node.argumentList.beginToken.isSynthetic) ||
(node is ast.InstanceCreationExpression &&
- !node.argumentList.beginToken.isSynthetic);
+ !node.argumentList.beginToken.isSynthetic) ||
+ // "ClassName.^()" will appear as accessing a property named '('.
+ (node is ast.PropertyAccess && node.propertyName.name.startsWith('('));
}
Iterable<CompletionItem> _pluginResultsToItems(
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
index 30935d6..72903a8 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
@@ -60,11 +60,12 @@
'Requests not before server is initilized');
}
- final lineInfo = server.getLineInfo(data.file);
+ final file = data.file;
+ final lineInfo = server.getLineInfo(file);
if (lineInfo == null) {
return error(
ErrorCodes.InternalError,
- 'Line info not available for ${data.file}',
+ 'Line info not available for $file',
null,
);
}
@@ -99,7 +100,7 @@
_latestCompletionItem = item;
while (item == _latestCompletionItem && timer.elapsed < timeout) {
try {
- final analysisDriver = server.getAnalysisDriver(data.file);
+ final analysisDriver = server.getAnalysisDriver(file);
final session = analysisDriver?.currentSession;
// We shouldn't not get a driver/session, but if we did perhaps the file
@@ -139,7 +140,7 @@
var newInsertText = item.insertText ?? item.label;
final builder = ChangeBuilder(session: session);
- await builder.addDartFileEdit(data.file, (builder) {
+ await builder.addDartFileEdit(file, (builder) {
final result = builder.importLibraryElement(library.uri);
if (result.prefix != null) {
newInsertText = '${result.prefix}.$newInsertText';
@@ -152,9 +153,9 @@
final changes = builder.sourceChange;
final thisFilesChanges =
- changes.edits.where((e) => e.file == data.file).toList();
+ changes.edits.where((e) => e.file == file).toList();
final otherFilesChanges =
- changes.edits.where((e) => e.file != data.file).toList();
+ changes.edits.where((e) => e.file != file).toList();
// If this completion involves editing other files, we'll need to build
// a command that the client will call to apply those edits later.
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
index 415f155..4a949c4 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
@@ -16,6 +16,7 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/source/source_range.dart';
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/src/utilities/library.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
@@ -150,22 +151,6 @@
return false;
}
- /// Returns the relative URI from the passed [library] to the given [path].
- ///
- /// If the [path] is not in the [library]'s directory, `null` is returned.
- String? _getRelativeUriFromLibrary(LibraryElement library, String path) {
- var librarySource = library.librarySource;
- var pathContext = resourceProvider.pathContext;
- var libraryDirectory = pathContext.dirname(librarySource.fullName);
- var sourceDirectory = pathContext.dirname(path);
- if (pathContext.isWithin(libraryDirectory, path) ||
- pathContext.isWithin(sourceDirectory, libraryDirectory)) {
- var relativeFile = pathContext.relative(path, from: libraryDirectory);
- return pathContext.split(relativeFile).join('/');
- }
- return null;
- }
-
Iterable<CorrectionProducer> _importExtensionInLibrary(
Uri uri, DartType targetType, String memberName) sync* {
// Look to see whether the library at the [uri] is already imported. If it
@@ -207,25 +192,28 @@
/// Returns a list of one or two import corrections.
///
- /// If [relativeUri] is `null`, only one correction, with an absolute import
- /// path, is returned. Otherwise, a correction with an absolute import path
- /// and a correction with a relative path are returned. If the
+ /// If [includeRelativeFix] is `false`, only one correction, with an absolute
+ /// import path, is returned. Otherwise, a correction with an absolute import
+ /// path and a correction with a relative path are returned. If the
/// `prefer_relative_imports` lint rule is enabled, the relative path is
/// returned first.
- Iterable<CorrectionProducer> _importLibrary(FixKind fixKind, Uri library,
- [String? relativeUri]) {
- if (relativeUri == null || relativeUri.isEmpty) {
+ Iterable<CorrectionProducer> _importLibrary(
+ FixKind fixKind,
+ Uri library, {
+ bool includeRelativeFix = false,
+ }) {
+ if (!includeRelativeFix) {
return [_ImportAbsoluteLibrary(fixKind, library)];
}
if (isLintEnabled(LintNames.prefer_relative_imports)) {
return [
- _ImportRelativeLibrary(fixKind, relativeUri),
+ _ImportRelativeLibrary(fixKind, library),
_ImportAbsoluteLibrary(fixKind, library),
];
} else {
return [
_ImportAbsoluteLibrary(fixKind, library),
- _ImportRelativeLibrary(fixKind, relativeUri),
+ _ImportRelativeLibrary(fixKind, library),
];
}
}
@@ -312,10 +300,13 @@
// Good: direct declaration.
fixKind = DartFixKind.IMPORT_LIBRARY_PROJECT1;
}
- // Add the fix.
- var relativeUri =
- _getRelativeUriFromLibrary(libraryElement, declaration.path);
- yield* _importLibrary(fixKind, declaration.uri, relativeUri);
+ // If both files are in the same package's lib folder, also include a
+ // relative import.
+ var includeRelativeUri = canBeRelativeImport(
+ declaration.uri, libraryElement.librarySource.uri);
+ // Add the fix(es).
+ yield* _importLibrary(fixKind, declaration.uri,
+ includeRelativeFix: includeRelativeUri);
}
}
@@ -415,7 +406,9 @@
@override
Future<void> compute(ChangeBuilder builder) async {
await builder.addDartFileEdit(file, (builder) {
- _uriText = builder.importLibrary(_library);
+ if (builder is DartFileEditBuilderImpl) {
+ _uriText = builder.importLibraryWithAbsoluteUri(_library);
+ }
});
}
}
@@ -532,12 +525,14 @@
class _ImportRelativeLibrary extends CorrectionProducer {
final FixKind _fixKind;
- final String _relativeURI;
+ final Uri _library;
- _ImportRelativeLibrary(this._fixKind, this._relativeURI);
+ String _uriText = '';
+
+ _ImportRelativeLibrary(this._fixKind, this._library);
@override
- List<Object> get fixArguments => [_relativeURI];
+ List<Object> get fixArguments => [_uriText];
@override
FixKind get fixKind => _fixKind;
@@ -546,7 +541,7 @@
Future<void> compute(ChangeBuilder builder) async {
await builder.addDartFileEdit(file, (builder) {
if (builder is DartFileEditBuilderImpl) {
- builder.importLibraryWithRelativeUri(_relativeURI);
+ _uriText = builder.importLibraryWithRelativeUri(_library);
}
});
}
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index 9ccf020..cbacc55 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -4,9 +4,11 @@
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/src/lsp/constants.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:collection/collection.dart';
+import 'package:linter/src/rules.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -234,6 +236,21 @@
insertText: 'myFunction',
);
+ Future<void> test_completeFunctionCalls_existingArgList_member_noPrefix() =>
+ // https://github.com/Dart-Code/Dart-Code/issues/3672
+ checkCompleteFunctionCallInsertText(
+ '''
+ class Aaaaa {
+ static foo(int a) {}
+ }
+ void f() {
+ Aaaaa.[[^]]()
+ }
+ ''',
+ 'foo(…)',
+ insertText: 'foo',
+ );
+
Future<void> test_completeFunctionCalls_existingArgList_namedConstructor() =>
checkCompleteFunctionCallInsertText(
'''
@@ -1606,6 +1623,36 @@
expect(resolved.detail, isNull);
}
+ Future<void> test_suggestionSets_importsPackageUri() async {
+ newFile(
+ join(projectFolderPath, 'lib', 'my_class.dart'),
+ content: 'class MyClass {}',
+ );
+
+ final content = '''
+void f() {
+ MyClas^
+}
+ ''';
+
+ final expectedContent = '''
+import 'package:test/my_class.dart';
+
+void f() {
+ MyClass
+}
+ ''';
+
+ final completionLabel = 'MyClass';
+
+ await _checkCompletionEdits(
+ mainFileUri,
+ content,
+ completionLabel,
+ expectedContent,
+ );
+ }
+
Future<void>
test_suggestionSets_includesReexportedSymbolsForEachFile() async {
newFile(
@@ -2003,6 +2050,78 @@
'''));
}
+ Future<void> test_suggestionSets_preferRelativeImportsLib_insideLib() async {
+ _enableLints([LintNames.prefer_relative_imports]);
+ final importingFilePath =
+ join(projectFolderPath, 'lib', 'nested1', 'main.dart');
+ final importingFileUri = Uri.file(importingFilePath);
+ final importedFilePath =
+ join(projectFolderPath, 'lib', 'nested2', 'imported.dart');
+
+ // Create a file that will be auto-imported from completion.
+ newFile(importedFilePath, content: 'class MyClass {}');
+
+ final content = '''
+void f() {
+ MyClas^
+}
+ ''';
+
+ final expectedContent = '''
+import '../nested2/imported.dart';
+
+void f() {
+ MyClass
+}
+ ''';
+
+ final completionLabel = 'MyClass';
+
+ await _checkCompletionEdits(
+ importingFileUri,
+ content,
+ completionLabel,
+ expectedContent,
+ );
+ }
+
+ Future<void> test_suggestionSets_preferRelativeImportsLib_outsideLib() async {
+ // Files outside of the lib folder should still get absolute imports to
+ // files inside lib, even with the lint enabled.
+ _enableLints([LintNames.prefer_relative_imports]);
+ final importingFilePath =
+ join(projectFolderPath, 'bin', 'nested1', 'main.dart');
+ final importingFileUri = Uri.file(importingFilePath);
+ final importedFilePath =
+ join(projectFolderPath, 'lib', 'nested2', 'imported.dart');
+
+ // Create a file that will be auto-imported from completion.
+ newFile(importedFilePath, content: 'class MyClass {}');
+
+ final content = '''
+void f() {
+ MyClas^
+}
+ ''';
+
+ final expectedContent = '''
+import 'package:test/nested2/imported.dart';
+
+void f() {
+ MyClass
+}
+ ''';
+
+ final completionLabel = 'MyClass';
+
+ await _checkCompletionEdits(
+ importingFileUri,
+ content,
+ completionLabel,
+ expectedContent,
+ );
+ }
+
Future<void> test_suggestionSets_unavailableIfDisabled() async {
newFile(
join(projectFolderPath, 'other_file.dart'),
@@ -2085,6 +2204,39 @@
expect(updated, contains('a.abcdefghij'));
}
+ /// Sets up the server with a file containing [content] and checks that
+ /// accepting a specific completion produces [expectedContent].
+ ///
+ /// [content] should contain a `^` at the location where completion should be
+ /// invoked/accepted.
+ Future<void> _checkCompletionEdits(
+ Uri fileUri,
+ String content,
+ String completionLabel,
+ String expectedContent,
+ ) async {
+ final initialAnalysis = waitForAnalysisComplete();
+ await initialize(
+ workspaceCapabilities:
+ withApplyEditSupport(emptyWorkspaceClientCapabilities));
+ await openFile(fileUri, withoutMarkers(content));
+ await initialAnalysis;
+ final res = await getCompletion(fileUri, positionFromMarker(content));
+
+ final completion = res.where((c) => c.label == completionLabel).single;
+ final resolvedCompletion = await resolveCompletion(completion);
+
+ // Apply both the main completion edit and the additionalTextEdits atomically.
+ final newContent = applyTextEdits(
+ withoutMarkers(content),
+ [toTextEdit(resolvedCompletion.textEdit!)]
+ .followedBy(resolvedCompletion.additionalTextEdits!)
+ .toList(),
+ );
+
+ expect(newContent, equals(expectedContent));
+ }
+
Future<void> _checkResultsForTriggerCharacters(String content,
List<String> triggerCharacters, Matcher expectedResults) async {
await initialize();
@@ -2099,6 +2251,16 @@
expect(res, expectedResults);
}
}
+
+ void _enableLints(List<String> lintNames) {
+ registerLintRules();
+ final lintsYaml = lintNames.map((name) => ' - $name\n').join();
+ newFile(analysisOptionsPath, content: '''
+linter:
+ rules:
+$lintsYaml
+''');
+ }
}
@reflectiveTest
diff --git a/pkg/analysis_server/test/lsp/diagnostic_test.dart b/pkg/analysis_server/test/lsp/diagnostic_test.dart
index fc6dffe..3b7fc18 100644
--- a/pkg/analysis_server/test/lsp/diagnostic_test.dart
+++ b/pkg/analysis_server/test/lsp/diagnostic_test.dart
@@ -88,7 +88,7 @@
linter:
rules:
- invalid_lint_rule_name
-''').path;
+''');
final firstDiagnosticsUpdate = waitForDiagnostics(analysisOptionsUri);
await initialize();
@@ -102,7 +102,7 @@
Future<void> test_analysisOptionsFile_packageInclude() async {
newFile(analysisOptionsPath, content: '''
include: package:pedantic/analysis_options.yaml
-''').path;
+''');
// Verify there's an error for the import.
final firstDiagnosticsUpdate = waitForDiagnostics(analysisOptionsUri);
diff --git a/pkg/analyzer/lib/src/context/source.dart b/pkg/analyzer/lib/src/context/source.dart
index 554eb1a..f30c15c 100644
--- a/pkg/analyzer/lib/src/context/source.dart
+++ b/pkg/analyzer/lib/src/context/source.dart
@@ -11,6 +11,7 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart' as utils;
import 'package:analyzer/src/source/package_map_resolver.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:analyzer/src/workspace/package_build.dart';
@@ -137,6 +138,9 @@
@override
Uri? restoreUri(Source source) {
+ if (source is InSummarySource) {
+ return source.uri;
+ }
for (UriResolver resolver in resolvers) {
// First see if a resolver can restore the URI.
Uri? uri = resolver.restoreAbsolute(source);
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index e74bf6d..97cac92 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -35,6 +35,7 @@
import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/summary2/informative_data.dart';
import 'package:analyzer/src/util/either.dart';
+import 'package:analyzer/src/util/uri.dart';
import 'package:analyzer/src/workspace/workspace.dart';
import 'package:collection/collection.dart';
import 'package:convert/convert.dart';
@@ -716,11 +717,8 @@
/// Mapping from a path to the flag whether there is a URI for the path.
final Map<String, bool> _hasUriForPath = {};
- /// Mapping from a path to the corresponding [FileState]s, canonical or not.
- final Map<String, List<FileState>> _pathToFiles = {};
-
- /// Mapping from a path to the corresponding canonical [FileState].
- final Map<String, FileState> _pathToCanonicalFile = {};
+ /// Mapping from a path to the corresponding [FileState].
+ final Map<String, FileState> _pathToFile = {};
/// We don't read parts until requested, but if we need to know the
/// library for a file, we need to read parts of every file to know
@@ -775,7 +773,8 @@
}
}
- for (var file in _pathToFiles[path] ?? <FileState>[]) {
+ var file = _pathToFile[path];
+ if (file != null) {
collectAffected(file);
}
}
@@ -808,25 +807,16 @@
return featureSetProvider.getLanguageVersion(path, uri);
}
- /// Return the canonical [FileState] for the given absolute [path]. The
- /// returned file has the last known state since if was last refreshed.
- ///
- /// Here "canonical" means that if the [path] is in a package `lib` then the
- /// returned file will have the `package:` style URI.
+ /// Return the [FileState] for the given absolute [path]. The returned file
+ /// has the last known state since if was last refreshed.
FileState getFileForPath(String path) {
- FileState? file = _pathToCanonicalFile[path];
+ var file = _pathToFile[path];
if (file == null) {
File resource = _resourceProvider.getFile(path);
Source fileSource = resource.createSource();
Uri? uri = _sourceFactory.restoreUri(fileSource);
- // Try to get the existing instance.
- file = _uriToFile[uri];
- // If we have a file, call it the canonical one and return it.
- if (file != null) {
- _pathToCanonicalFile[path] = file;
- return file;
- }
// Create a new file.
+ // TODO(scheglov) this is duplicate
FileSource uriSource = FileSource(resource, uri!);
WorkspacePackage? workspacePackage = _workspace?.findPackageFor(path);
FeatureSet featureSet = contextFeatureSet(path, uri, workspacePackage);
@@ -834,9 +824,9 @@
contextLanguageVersion(path, uri, workspacePackage);
file = FileState._(this, path, uri, uriSource, workspacePackage,
featureSet, packageLanguageVersion);
+ _pathToFile[path] = file;
_uriToFile[uri] = file;
_addFileWithPath(path, file);
- _pathToCanonicalFile[path] = file;
file.refresh();
}
return file;
@@ -874,6 +864,13 @@
String path = uriSource.fullName;
File resource = _resourceProvider.getFile(path);
+
+ var rewrittenUri = rewriteFileToPackageUri(_sourceFactory, uri);
+ if (rewrittenUri == null) {
+ return Either2.t1(null);
+ }
+ uri = rewrittenUri;
+
FileSource source = FileSource(resource, uri);
WorkspacePackage? workspacePackage = _workspace?.findPackageFor(path);
FeatureSet featureSet = contextFeatureSet(path, uri, workspacePackage);
@@ -881,6 +878,7 @@
contextLanguageVersion(path, uri, workspacePackage);
file = FileState._(this, path, uri, source, workspacePackage, featureSet,
packageLanguageVersion);
+ _pathToFile[path] = file;
_uriToFile[uri] = file;
_addFileWithPath(path, file);
file.refresh();
@@ -888,19 +886,6 @@
return Either2.t1(file);
}
- /// Return the list of all [FileState]s corresponding to the given [path]. The
- /// list has at least one item, and the first item is the canonical file.
- List<FileState> getFilesForPath(String path) {
- FileState canonicalFile = getFileForPath(path);
- List<FileState> allFiles = _pathToFiles[path]!.toList();
- if (allFiles.length == 1) {
- return allFiles;
- }
- return allFiles
- ..remove(canonicalFile)
- ..insert(0, canonicalFile);
- }
-
/// Return files where the given [name] is subtyped, i.e. used in `extends`,
/// `with` or `implements` clauses.
Set<FileState>? getFilesSubtypingName(String name) {
@@ -951,15 +936,9 @@
}
void _addFileWithPath(String path, FileState file) {
- var files = _pathToFiles[path];
- if (files == null) {
- knownFilePaths.add(path);
- knownFiles.add(file);
- files = <FileState>[];
- _pathToFiles[path] = files;
- fileStamp++;
- }
- files.add(file);
+ knownFilePaths.add(path);
+ knownFiles.add(file);
+ fileStamp++;
}
/// Clear all [FileState] data - all maps from path or URI, etc.
@@ -968,8 +947,7 @@
knownFilePaths.clear();
knownFiles.clear();
_hasUriForPath.clear();
- _pathToFiles.clear();
- _pathToCanonicalFile.clear();
+ _pathToFile.clear();
_librariesWithoutPartsRead.clear();
_partToLibraries.clear();
_subtypedNameToFiles.clear();
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart b/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart
index d183ecc..887f450 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart
@@ -166,15 +166,9 @@
return _logger.run('Verify API signature of $path', () {
_logger.writeln('Work in ${_fsState.contextName}');
- bool anyApiChanged = false;
- List<FileState> files = _fsState.getFilesForPath(path);
- for (FileState file in files) {
- bool apiChanged = file.refresh();
- if (apiChanged) {
- anyApiChanged = true;
- }
- }
- if (anyApiChanged) {
+ var file = _fsState.getFileForPath(path);
+ var apiChanged = file.refresh();
+ if (apiChanged) {
_logger.writeln('API signatures mismatch found.');
// TODO(scheglov) schedule analysis of only affected files
var pendingChangedFiles = <String>{};
@@ -190,10 +184,8 @@
// Add files that directly import the changed file.
for (String addedPath in addedFiles) {
FileState addedFile = _fsState.getFileForPath(addedPath);
- for (FileState changedFile in files) {
- if (addedFile.importedFiles.contains(changedFile)) {
- pendingImportFiles.add(addedPath);
- }
+ if (addedFile.importedFiles.contains(file)) {
+ pendingImportFiles.add(addedPath);
}
}
@@ -220,7 +212,7 @@
_pendingErrorFiles = pendingErrorFiles;
_pendingFiles = pendingFiles;
}
- return files[0];
+ return file;
});
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 076e54f..1f513c1 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -41,6 +41,7 @@
import 'package:analyzer/src/generated/ffi_verifier.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/hint/sdk_constraint_verifier.dart';
import 'package:analyzer/src/ignore_comments/ignore_info.dart';
import 'package:analyzer/src/lint/linter.dart';
@@ -49,6 +50,7 @@
import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/task/strong/checker.dart';
import 'package:analyzer/src/util/performance/operation_performance.dart';
+import 'package:analyzer/src/util/uri.dart';
import 'package:pub_semver/pub_semver.dart';
var timerLibraryAnalyzer = Stopwatch();
@@ -772,6 +774,18 @@
featureSet: unit.featureSet, flowAnalysisHelper: flowAnalysisHelper));
}
+ Uri? _resolveRelativeUri(String relativeUriStr) {
+ Uri relativeUri;
+ try {
+ relativeUri = Uri.parse(relativeUriStr);
+ } on FormatException {
+ return null;
+ }
+
+ var absoluteUri = resolveRelativeUri(_library.uri, relativeUri);
+ return rewriteFileToPackageUri(_sourceFactory, absoluteUri);
+ }
+
/// Return the result of resolve the given [uriContent], reporting errors
/// against the [uriLiteral].
Source? _resolveUri(FileState file, bool isImport, StringLiteral uriLiteral,
@@ -813,12 +827,12 @@
directive.uriSource = defaultSource;
}
if (directive is NamespaceDirectiveImpl) {
- var relativeUri = _selectRelativeUri(directive);
- directive.selectedUriContent = relativeUri;
- directive.selectedSource = _sourceFactory.resolveUri(
- _library.source,
- relativeUri,
- );
+ var relativeUriStr = _selectRelativeUri(directive);
+ directive.selectedUriContent = relativeUriStr;
+ var absoluteUri = _resolveRelativeUri(relativeUriStr);
+ if (absoluteUri != null) {
+ directive.selectedSource = _sourceFactory.forUri2(absoluteUri);
+ }
for (var configuration in directive.configurations) {
configuration as ConfigurationImpl;
var uriLiteral = configuration.uri;
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 5d1e535..794ef17 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/src/summary2/link.dart';
import 'package:analyzer/src/summary2/reference.dart';
import 'package:analyzer/src/util/comment.dart';
+import 'package:analyzer/src/util/uri.dart';
import 'package:collection/collection.dart';
class ElementBuilder extends ThrowingAstVisitor<void> {
@@ -997,16 +998,24 @@
if (relativeUriStr == null) {
return null;
}
- var relativeUri = Uri.parse(relativeUriStr);
- return resolveRelativeUri(_libraryBuilder.uri, relativeUri);
+
+ Uri relativeUri;
+ try {
+ relativeUri = Uri.parse(relativeUriStr);
+ } on FormatException {
+ return null;
+ }
+
+ var absoluteUri = resolveRelativeUri(_libraryBuilder.uri, relativeUri);
+
+ var sourceFactory = _linker.analysisContext.sourceFactory;
+ return rewriteFileToPackageUri(sourceFactory, absoluteUri);
}
LibraryElement? _selectLibrary(NamespaceDirective node) {
- try {
- var uri = _selectAbsoluteUri(node);
+ var uri = _selectAbsoluteUri(node);
+ if (uri != null) {
return _linker.elementFactory.libraryOfUri('$uri');
- } on FormatException {
- return null;
}
}
diff --git a/pkg/analyzer/lib/src/util/uri.dart b/pkg/analyzer/lib/src/util/uri.dart
index 963dafc..4192e3f 100644
--- a/pkg/analyzer/lib/src/util/uri.dart
+++ b/pkg/analyzer/lib/src/util/uri.dart
@@ -2,6 +2,7 @@
// 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:analyzer/src/generated/source.dart';
import 'package:path/path.dart';
String fileUriToNormalizedPath(Context context, Uri fileUri) {
@@ -10,3 +11,28 @@
path = context.normalize(path);
return path;
}
+
+/// If the [absoluteUri] is a `file` URI that has corresponding `package` URI,
+/// return it. If the URI is not valid, e.g. has empty path segments, so
+/// does not represent a valid file path, return `null`.
+Uri? rewriteFileToPackageUri(SourceFactory sourceFactory, Uri absoluteUri) {
+ // Only file URIs get rewritten into package URIs.
+ if (!absoluteUri.isScheme('file')) {
+ return absoluteUri;
+ }
+
+ // It must be a valid URI, e.g. `file:///home/` is not.
+ var pathSegments = absoluteUri.pathSegments;
+ if (pathSegments.isEmpty || pathSegments.last.isEmpty) {
+ return null;
+ }
+
+ // We ask for Source only because `restoreUri` needs it.
+ // TODO(scheglov) Add more direct way to convert a path to URI.
+ var source = sourceFactory.forUri2(absoluteUri);
+ if (source == null) {
+ return null;
+ }
+
+ return sourceFactory.restoreUri(source);
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index de37c97..35c3ab2 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -1952,16 +1952,13 @@
expect(result.errors, isEmpty);
}
- // Analysis of my_pkg/bin/b.dart produces the error "A value of type
- // 'String' can't be assigned to a variable of type 'int'", because
- // file:///my_pkg/bin/b.dart imports file:///my_pkg/lib/c.dart, which
- // successfully imports file:///my_pkg/test/d.dart, causing y to have an
- // inferred type of String.
+ // Analysis of my_pkg/bin/a.dart produces no error because
+ // the import `../lib/c.dart` is resolved to package:my_pkg/c.dart, and
+ // package:my_pkg/c.dart's import is erroneous, causing y's reference to z
+ // to be unresolved (and therefore have type dynamic).
{
ResolvedUnitResult result = await driver.getResultValid(b);
- List<AnalysisError> errors = result.errors;
- expect(errors, hasLength(1));
- expect(errors[0].errorCode, CompileTimeErrorCode.INVALID_ASSIGNMENT);
+ expect(result.errors, isEmpty);
}
}
@@ -2028,8 +2025,10 @@
{
ResolvedUnitResult result = await driver.getResultValid(b);
- expect(_getImportSource(result.unit, 0).uri.toString(),
- 'package:test/a.dart');
+ expect(
+ _getImportSource(result.unit, 0).uri,
+ Uri.parse('package:test/a.dart'),
+ );
_assertTopLevelVarType(result.unit, 'VB', 'A<int>');
}
@@ -2037,7 +2036,7 @@
ResolvedUnitResult result = await driver.getResultValid(c);
expect(
_getImportSource(result.unit, 0).uri,
- toUri('/test/lib/a.dart'),
+ Uri.parse('package:test/a.dart'),
);
_assertTopLevelVarType(result.unit, 'VC', 'A<double>');
}
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index b298989..6899a94 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -23,7 +23,6 @@
import 'package:analyzer/src/source/package_map_resolver.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
-import 'package:analyzer/src/util/either.dart';
import 'package:analyzer/src/workspace/basic.dart';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
@@ -268,8 +267,6 @@
expect(file.libraryFiles, [file, file.partedFiles[0]]);
expect(_excludeSdk(file.directReferencedFiles), hasLength(5));
-
- expect(fileSystemState.getFilesForPath(a1), [file]);
}
test_getFileForPath_onlyDartFiles() {
@@ -363,27 +360,6 @@
);
}
- test_getFileForUri_packageVsFileUri() {
- String path = convertPath('/aaa/lib/a.dart');
- var packageUri = Uri.parse('package:aaa/a.dart');
- var fileUri = toUri(path);
-
- // The files with `package:` and `file:` URIs are different.
- var filePackageUri = fileSystemState.getFileForUri(packageUri).asFileState;
- var fileFileUri = fileSystemState.getFileForUri(fileUri).asFileState;
- expect(filePackageUri, isNot(same(fileFileUri)));
-
- expect(filePackageUri.path, path);
- expect(filePackageUri.uri, packageUri);
-
- expect(fileFileUri.path, path);
- expect(fileFileUri.uri, fileUri);
-
- // The file with the `package:` style URI is canonical, and is the first.
- var files = fileSystemState.getFilesForPath(path);
- expect(files, [filePackageUri, fileFileUri]);
- }
-
test_getFilesSubtypingName() {
String a = convertPath('/a.dart');
String b = convertPath('/b.dart');
@@ -783,12 +759,3 @@
throw StateError('Unexpected invocation of ${invocation.memberName}');
}
}
-
-extension on Either2<FileState?, ExternalLibrary> {
- FileState get asFileState {
- return map(
- (file) => file!,
- (_) => fail('Expected a file'),
- );
- }
-}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
index 5a09829..e045770 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
@@ -13,11 +13,13 @@
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary2/bundle_reader.dart';
import 'package:analyzer/src/summary2/informative_data.dart';
import 'package:analyzer/src/summary2/link.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/reference.dart';
+import 'package:analyzer/src/util/uri.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'element_text.dart';
@@ -196,11 +198,9 @@
void _addNonDartLibraries(
Set<Source> addedLibraries,
List<LinkInputLibrary> libraries,
- Source? source,
+ Source source,
) {
- if (source == null ||
- source.uri.isScheme('dart') ||
- !addedLibraries.add(source)) {
+ if (source.uri.isScheme('dart') || !addedLibraries.add(source)) {
return;
}
@@ -217,8 +217,29 @@
);
void addRelativeUriStr(StringLiteral uriNode) {
- var uriStr = uriNode.stringValue;
- var uriSource = sourceFactory.resolveUri(source, uriStr);
+ var relativeUriStr = uriNode.stringValue;
+ if (relativeUriStr == null) {
+ return;
+ }
+
+ Uri relativeUri;
+ try {
+ relativeUri = Uri.parse(relativeUriStr);
+ } on FormatException {
+ return;
+ }
+
+ var absoluteUri = resolveRelativeUri(source.uri, relativeUri);
+ var rewrittenUri = rewriteFileToPackageUri(sourceFactory, absoluteUri);
+ if (rewrittenUri == null) {
+ return;
+ }
+
+ var uriSource = sourceFactory.forUri2(rewrittenUri);
+ if (uriSource == null) {
+ return;
+ }
+
_addNonDartLibraries(addedLibraries, libraries, uriSource);
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index bb3c056..450bc47 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -18936,8 +18936,7 @@
test_import_short_absolute() async {
testFile = '/my/project/bin/test.dart';
// Note: "/a.dart" resolves differently on Windows vs. Posix.
- var destinationPath =
- resourceProvider.pathContext.fromUri(Uri.parse('/a.dart'));
+ var destinationPath = convertPath('/a.dart');
addLibrarySource(destinationPath, 'class C {}');
var library = await checkLibrary('import "/a.dart"; C c;');
checkElementText(library, r'''
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index 9b0c895..104fc79 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -17,6 +17,7 @@
hide Element, ElementKind;
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/src/utilities/charcodes.dart';
+import 'package:analyzer_plugin/src/utilities/library.dart';
import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
@@ -1337,11 +1338,6 @@
/// the names used in generated code, to information about these imports.
Map<Uri, _LibraryToImport> librariesToImport = {};
- /// A mapping from libraries that need to be imported relatively in order to
- /// make visible the names used in generated code, to information about these
- /// imports.
- Map<String, _LibraryToImport> librariesToRelativelyImport = {};
-
/// Initialize a newly created builder to build a source file edit within the
/// change being built by the given [changeBuilder]. The file being edited has
/// the given [resolvedUnit] and [timeStamp].
@@ -1350,10 +1346,7 @@
: super(changeBuilder, resolvedUnit.path, timeStamp);
@override
- bool get hasEdits =>
- super.hasEdits ||
- librariesToImport.isNotEmpty ||
- librariesToRelativelyImport.isNotEmpty;
+ bool get hasEdits => super.hasEdits || librariesToImport.isNotEmpty;
@override
void addInsertion(
@@ -1402,9 +1395,6 @@
for (var entry in librariesToImport.entries) {
copy.librariesToImport[entry.key] = entry.value;
}
- for (var entry in librariesToRelativelyImport.entries) {
- copy.librariesToRelativelyImport[entry.key] = entry.value;
- }
return copy;
}
@@ -1418,9 +1408,6 @@
if (librariesToImport.isNotEmpty) {
_addLibraryImports(librariesToImport.values);
}
- if (librariesToRelativelyImport.isNotEmpty) {
- _addLibraryImports(librariesToRelativelyImport.values);
- }
}
@override
@@ -1480,8 +1467,12 @@
return ImportLibraryElementResultImpl(null);
}
- String importLibraryWithRelativeUri(String uriText, [String? prefix]) {
- return _importLibraryWithRelativeUri(uriText, prefix).uriText;
+ String importLibraryWithAbsoluteUri(Uri uri, [String? prefix]) {
+ return _importLibrary(uri, prefix: prefix, forceAbsolute: true).uriText;
+ }
+
+ String importLibraryWithRelativeUri(Uri uri, [String? prefix]) {
+ return _importLibrary(uri, prefix: prefix, forceRelative: true).uriText;
}
@override
@@ -1720,24 +1711,55 @@
}
/// Computes the best URI to import [uri] into the target library.
- String _getLibraryUriText(Uri uri) {
- if (uri.scheme == 'file') {
- var pathContext = resolvedUnit.session.resourceProvider.pathContext;
- var whatPath = pathContext.fromUri(uri);
+ ///
+ /// [uri] may be converted from an absolute URI to a relative URI depending on
+ /// user preferences/lints unless [forceAbsolute] or [forceRelative] are `true`.
+ String _getLibraryUriText(
+ Uri uri, {
+ bool forceAbsolute = false,
+ bool forceRelative = false,
+ }) {
+ var pathContext = resolvedUnit.session.resourceProvider.pathContext;
+
+ /// Returns the relative path to import [whatPath] into [resolvedUnit].
+ String getRelativePath(String whatPath) {
var libraryPath = resolvedUnit.libraryElement.source.fullName;
var libraryFolder = pathContext.dirname(libraryPath);
var relativeFile = pathContext.relative(whatPath, from: libraryFolder);
return pathContext.split(relativeFile).join('/');
}
+
+ if (uri.isScheme('file')) {
+ var whatPath = pathContext.fromUri(uri);
+ return getRelativePath(whatPath);
+ }
+ var preferRelative = _isLintEnabled('prefer_relative_imports');
+ if (forceRelative || (preferRelative && !forceAbsolute)) {
+ if (canBeRelativeImport(uri, resolvedUnit.uri)) {
+ var whatPath = resolvedUnit.session.uriConverter.uriToPath(uri);
+ if (whatPath != null) {
+ return getRelativePath(whatPath);
+ }
+ }
+ }
return uri.toString();
}
/// Arrange to have an import added for the library with the given [uri].
- _LibraryToImport _importLibrary(Uri uri) {
+ ///
+ /// [uri] may be converted from an absolute URI to a relative URI depending on
+ /// user preferences/lints unless [forceAbsolute] or [forceRelative] are `true`.
+ _LibraryToImport _importLibrary(
+ Uri uri, {
+ String? prefix,
+ bool forceAbsolute = false,
+ bool forceRelative = false,
+ }) {
var import = (libraryChangeBuilder ?? this).librariesToImport[uri];
if (import == null) {
- var uriText = _getLibraryUriText(uri);
- var prefix =
+ var uriText = _getLibraryUriText(uri,
+ forceAbsolute: forceAbsolute, forceRelative: forceRelative);
+ prefix ??=
importPrefixGenerator != null ? importPrefixGenerator!(uri) : null;
import = _LibraryToImport(uriText, prefix);
(libraryChangeBuilder ?? this).librariesToImport[uri] = import;
@@ -1745,23 +1767,17 @@
return import;
}
- /// Arrange to have an import added for the library with the given relative
- /// [uriText].
- _LibraryToImport _importLibraryWithRelativeUri(String uriText,
- [String? prefix]) {
- var import = librariesToRelativelyImport[uriText];
- if (import == null) {
- import = _LibraryToImport(uriText, prefix);
- librariesToRelativelyImport[uriText] = import;
- }
- return import;
- }
-
/// Return `true` if the [element] is defined in the target library.
bool _isDefinedLocally(Element element) {
return element.library == resolvedUnit.libraryElement;
}
+ bool _isLintEnabled(String lintName) {
+ final analysisOptions =
+ resolvedUnit.session.analysisContext.analysisOptions;
+ return analysisOptions.isLintEnabled(lintName);
+ }
+
/// Create an edit to replace the return type of the innermost function
/// containing the given [node] with the type `Future`. The [typeProvider] is
/// used to check the current return type, because if it is already `Future`
diff --git a/pkg/analyzer_plugin/lib/src/utilities/library.dart b/pkg/analyzer_plugin/lib/src/utilities/library.dart
new file mode 100644
index 0000000..8fa8383
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/src/utilities/library.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Checks whether importing the library with URI [library2] into the
+/// library with URI [library1] could be a relative import.
+///
+/// Both URIs must be package: URIs and belong to the same package for this to
+/// be true.
+bool canBeRelativeImport(Uri library1, Uri library2) {
+ return library1.isScheme('package') &&
+ library2.isScheme('package') &&
+ library1.pathSegments.isNotEmpty &&
+ library2.pathSegments.isNotEmpty &&
+ library1.pathSegments.first == library2.pathSegments.first;
+}
diff --git a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
index 6bd6c78..4eababe 100644
--- a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
@@ -346,6 +346,9 @@
///
/// Returns the text of the URI that will be used in the import directive.
/// It can be different than the given [Uri].
+ ///
+ /// [uri] may be converted from an absolute URI to a relative URI depending on
+ /// user preferences/lints.
String importLibrary(Uri uri);
/// Ensure that the library with the given [uri] is imported.
diff --git a/pkg/dart2native/lib/dart2native.dart b/pkg/dart2native/lib/dart2native.dart
index f5f0dfe..be47b4c 100644
--- a/pkg/dart2native/lib/dart2native.dart
+++ b/pkg/dart2native/lib/dart2native.dart
@@ -6,8 +6,8 @@
import 'dart:typed_data';
// Maximum page size across all supported architectures (arm64 macOS has 16K
-// pages, the rest are all 4k pages).
-const elfPageSize = 16384;
+// pages, some arm64 Linux distributions have 64K pages).
+const elfPageSize = 65536;
const appjitMagicNumber = <int>[0xdc, 0xdc, 0xf6, 0xf6, 0, 0, 0, 0];
enum Kind { aot, exe }
diff --git a/pkg/dev_compiler/bin/dartdevc.dart b/pkg/dev_compiler/bin/dartdevc.dart
old mode 100755
new mode 100644
index 4d8d197..09d9ca8
--- a/pkg/dev_compiler/bin/dartdevc.dart
+++ b/pkg/dev_compiler/bin/dartdevc.dart
@@ -1,5 +1,5 @@
#!/usr/bin/env dart
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
@@ -8,106 +8,14 @@
/// Command line entry point for Dart Development Compiler (dartdevc), used to
/// compile a collection of dart libraries into a single JS module
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
import 'dart:isolate';
-import 'package:bazel_worker/bazel_worker.dart';
-import 'package:dev_compiler/src/compiler/shared_command.dart';
-import 'package:dev_compiler/src/kernel/expression_compiler_worker.dart';
+
+import 'package:dev_compiler/ddc.dart' as ddc;
/// The entry point for the Dart Dev Compiler.
///
/// [sendPort] may be passed in when started in an isolate. If provided, it is
/// used for bazel worker communication instead of stdin/stdout.
Future main(List<String> args, [SendPort sendPort]) async {
- // Always returns a new modifiable list.
- var parsedArgs = ParsedArguments.from(args);
-
- if (parsedArgs.isWorker) {
- var workerConnection = sendPort == null
- ? StdAsyncWorkerConnection()
- : SendPortAsyncWorkerConnection(sendPort);
- await _CompilerWorker(parsedArgs, workerConnection).run();
- } else if (parsedArgs.isBatch) {
- await runBatch(parsedArgs);
- } else if (parsedArgs.isExpressionCompiler) {
- await ExpressionCompilerWorker.createAndStart(parsedArgs.rest,
- sendPort: sendPort);
- } else {
- var result = await compile(parsedArgs);
- exitCode = result.exitCode;
- }
-}
-
-/// Runs the compiler worker loop.
-class _CompilerWorker extends AsyncWorkerLoop {
- /// The original args supplied to the executable.
- final ParsedArguments _startupArgs;
-
- _CompilerWorker(this._startupArgs, AsyncWorkerConnection workerConnection)
- : super(connection: workerConnection);
-
- /// Keeps track of our last compilation result so it can potentially be
- /// re-used in a worker.
- CompilerResult lastResult;
-
- /// Performs each individual work request.
- @override
- Future<WorkResponse> performRequest(WorkRequest request) async {
- var args = _startupArgs.merge(request.arguments);
- var output = StringBuffer();
- var context = args.reuseResult ? lastResult : null;
-
- /// Build a map of uris to digests.
- final inputDigests = <Uri, List<int>>{};
- for (var input in request.inputs) {
- inputDigests[sourcePathToUri(input.path)] = input.digest;
- }
-
- lastResult = await runZoned(
- () =>
- compile(args, previousResult: context, inputDigests: inputDigests),
- zoneSpecification:
- ZoneSpecification(print: (self, parent, zone, message) {
- output.writeln(message.toString());
- }));
- return WorkResponse()
- ..exitCode = lastResult.success ? 0 : 1
- ..output = output.toString();
- }
-}
-
-/// Runs DDC in Kernel batch mode for test.dart.
-Future runBatch(ParsedArguments batchArgs) async {
- var totalTests = 0;
- var failedTests = 0;
- var watch = Stopwatch()..start();
-
- print('>>> BATCH START');
-
- String line;
- CompilerResult result;
-
- while ((line = stdin.readLineSync(encoding: utf8))?.isNotEmpty == true) {
- totalTests++;
- var args = batchArgs.merge(line.split(RegExp(r'\s+')));
-
- String outcome;
- try {
- result = await compile(args, previousResult: result);
- outcome = result.success ? 'PASS' : (result.crashed ? 'CRASH' : 'FAIL');
- } catch (e, s) {
- outcome = 'CRASH';
- print('Unhandled exception:');
- print(e);
- print(s);
- }
-
- stderr.writeln('>>> EOF STDERR');
- print('>>> TEST $outcome ${watch.elapsedMilliseconds}ms');
- }
-
- var time = watch.elapsedMilliseconds;
- print('>>> BATCH END (${totalTests - failedTests})/$totalTests ${time}ms');
+ return ddc.internalMain(args, sendPort);
}
diff --git a/pkg/dev_compiler/lib/ddc.dart b/pkg/dev_compiler/lib/ddc.dart
new file mode 100755
index 0000000..5911cd9
--- /dev/null
+++ b/pkg/dev_compiler/lib/ddc.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart = 2.9
+
+/// Command line entry point for Dart Development Compiler (dartdevc), used to
+/// compile a collection of dart libraries into a single JS module
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+import 'dart:isolate';
+import 'package:bazel_worker/bazel_worker.dart';
+
+import 'src/compiler/shared_command.dart';
+import 'src/kernel/expression_compiler_worker.dart';
+
+/// The internal entry point for the Dart Dev Compiler.
+///
+/// [sendPort] may be passed in when started in an isolate. If provided, it is
+/// used for bazel worker communication instead of stdin/stdout.
+Future internalMain(List<String> args, [SendPort sendPort]) async {
+ // Always returns a new modifiable list.
+ var parsedArgs = ParsedArguments.from(args);
+
+ if (parsedArgs.isWorker) {
+ var workerConnection = sendPort == null
+ ? StdAsyncWorkerConnection()
+ : SendPortAsyncWorkerConnection(sendPort);
+ await _CompilerWorker(parsedArgs, workerConnection).run();
+ } else if (parsedArgs.isBatch) {
+ await runBatch(parsedArgs);
+ } else if (parsedArgs.isExpressionCompiler) {
+ await ExpressionCompilerWorker.createAndStart(parsedArgs.rest,
+ sendPort: sendPort);
+ } else {
+ var result = await compile(parsedArgs);
+ exitCode = result.exitCode;
+ }
+}
+
+/// Runs the compiler worker loop.
+class _CompilerWorker extends AsyncWorkerLoop {
+ /// The original args supplied to the executable.
+ final ParsedArguments _startupArgs;
+
+ _CompilerWorker(this._startupArgs, AsyncWorkerConnection workerConnection)
+ : super(connection: workerConnection);
+
+ /// Keeps track of our last compilation result so it can potentially be
+ /// re-used in a worker.
+ CompilerResult lastResult;
+
+ /// Performs each individual work request.
+ @override
+ Future<WorkResponse> performRequest(WorkRequest request) async {
+ var args = _startupArgs.merge(request.arguments);
+ var output = StringBuffer();
+ var context = args.reuseResult ? lastResult : null;
+
+ /// Build a map of uris to digests.
+ final inputDigests = <Uri, List<int>>{};
+ for (var input in request.inputs) {
+ inputDigests[sourcePathToUri(input.path)] = input.digest;
+ }
+
+ lastResult = await runZoned(
+ () =>
+ compile(args, previousResult: context, inputDigests: inputDigests),
+ zoneSpecification:
+ ZoneSpecification(print: (self, parent, zone, message) {
+ output.writeln(message.toString());
+ }));
+ return WorkResponse()
+ ..exitCode = lastResult.success ? 0 : 1
+ ..output = output.toString();
+ }
+}
+
+/// Runs DDC in Kernel batch mode for test.dart.
+Future runBatch(ParsedArguments batchArgs) async {
+ var totalTests = 0;
+ var failedTests = 0;
+ var watch = Stopwatch()..start();
+
+ print('>>> BATCH START');
+
+ String line;
+ CompilerResult result;
+
+ while ((line = stdin.readLineSync(encoding: utf8))?.isNotEmpty == true) {
+ totalTests++;
+ var args = batchArgs.merge(line.split(RegExp(r'\s+')));
+
+ String outcome;
+ try {
+ result = await compile(args, previousResult: result);
+ outcome = result.success ? 'PASS' : (result.crashed ? 'CRASH' : 'FAIL');
+ } catch (e, s) {
+ outcome = 'CRASH';
+ print('Unhandled exception:');
+ print(e);
+ print(s);
+ }
+
+ stderr.writeln('>>> EOF STDERR');
+ print('>>> TEST $outcome ${watch.elapsedMilliseconds}ms');
+ }
+
+ var time = watch.elapsedMilliseconds;
+ print('>>> BATCH END (${totalTests - failedTests})/$totalTests ${time}ms');
+}
diff --git a/runtime/include/dart_tools_api.h b/runtime/include/dart_tools_api.h
index 6d02750..1a2d9bb 100644
--- a/runtime/include/dart_tools_api.h
+++ b/runtime/include/dart_tools_api.h
@@ -222,25 +222,6 @@
Dart_ServiceStreamCancelCallback cancel_callback);
/**
- * A callback invoked when the VM service receives an event.
- */
-typedef void (*Dart_NativeStreamConsumer)(const uint8_t* event_json,
- intptr_t event_json_length);
-
-/**
- * Sets the native VM service stream callbacks for a particular stream.
- * Note: The function may be called on multiple threads concurrently.
- *
- * \param consumer A function pointer to an event handler callback function.
- * A NULL value removes the existing listen callback function if any.
- *
- * \param stream_id The ID of the stream on which to set the callback.
- */
-DART_EXPORT void Dart_SetNativeServiceStreamCallback(
- Dart_NativeStreamConsumer consumer,
- const char* stream_id);
-
-/**
* Sends a data event to clients of the VM Service.
*
* A data event is used to pass an array of bytes to subscribed VM
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 00a1877..2dbd8d3 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -15,6 +15,9 @@
#include "vm/dart_api_state.h"
#include "vm/dart_entry.h"
#include "vm/debugger.h"
+#if defined(DART_PRECOMPILED_RUNTIME) && defined(DART_TARGET_OS_LINUX)
+#include "vm/elf.h"
+#endif
#include "vm/flags.h"
#include "vm/handles.h"
#include "vm/heap/become.h"
@@ -298,6 +301,16 @@
}
start_time_micros_ = OS::GetCurrentMonotonicMicros();
VirtualMemory::Init();
+
+#if defined(DART_PRECOMPILED_RUNTIME) && defined(DART_TARGET_OS_LINUX)
+ if (VirtualMemory::PageSize() > kElfPageSize) {
+ return Utils::SCreate(
+ "Incompatible page size for AOT compiled ELF: expected at most %" Pd
+ ", got %" Pd "",
+ kElfPageSize, VirtualMemory::PageSize());
+ }
+#endif
+
OSThread::Init();
Zone::Init();
#if defined(SUPPORT_TIMELINE)
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 437ce6f..082476f 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -6195,14 +6195,6 @@
#endif
}
-DART_EXPORT void Dart_SetNativeServiceStreamCallback(
- Dart_NativeStreamConsumer consumer,
- const char* stream_id) {
-#if !defined(PRODUCT)
- Service::SetNativeServiceStreamCallback(consumer, stream_id);
-#endif
-}
-
DART_EXPORT char* Dart_ServiceSendDataEvent(const char* stream_id,
const char* event_kind,
const uint8_t* bytes,
diff --git a/runtime/vm/elf.h b/runtime/vm/elf.h
index 579c49f..3bf980d 100644
--- a/runtime/vm/elf.h
+++ b/runtime/vm/elf.h
@@ -5,14 +5,30 @@
#ifndef RUNTIME_VM_ELF_H_
#define RUNTIME_VM_ELF_H_
+#include "platform/globals.h"
+
+#if defined(DART_PRECOMPILER)
#include "vm/allocation.h"
#include "vm/compiler/runtime_api.h"
#include "vm/datastream.h"
#include "vm/growable_array.h"
#include "vm/zone.h"
+#endif
namespace dart {
+// The max page size on all supported architectures. Used to determine
+// the alignment of load segments, so that they are guaranteed page-aligned,
+// and no ELF section or segment should have a larger alignment.
+#if defined(DART_TARGET_OS_LINUX) && defined(TARGET_ARCH_ARM64)
+// Some Linux distributions on ARM64 select 64 KB page size.
+// Follow LLVM (https://reviews.llvm.org/D25079) and set maximum page size
+// to 64 KB for ARM64 Linux builds.
+static constexpr intptr_t kElfPageSize = 64 * KB;
+#else
+static constexpr intptr_t kElfPageSize = 16 * KB;
+#endif
+
#if defined(DART_PRECOMPILER)
class Dwarf;
@@ -33,10 +49,7 @@
Elf(Zone* zone, BaseWriteStream* stream, Type type, Dwarf* dwarf = nullptr);
- // The max page size on all supported architectures. Used to determine
- // the alignment of load segments, so that they are guaranteed page-aligned,
- // and no ELF section or segment should have a larger alignment.
- static constexpr intptr_t kPageSize = 16 * KB;
+ static constexpr intptr_t kPageSize = kElfPageSize;
bool IsStripped() const { return dwarf_ == nullptr; }
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index b70dea0..b7576a4 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -1192,14 +1192,6 @@
}
PostEvent(event->isolate(), stream_id, event->KindAsCString(), &js,
enter_safepoint);
-
- // Post event to the native Service Stream handlers if set.
- if (event->stream_info() != nullptr &&
- event->stream_info()->consumer() != nullptr) {
- auto length = js.buffer()->length();
- event->stream_info()->consumer()(
- reinterpret_cast<uint8_t*>(js.buffer()->buffer()), length);
- }
}
void Service::PostEvent(Isolate* isolate,
@@ -1387,17 +1379,6 @@
stream_cancel_callback_ = cancel_callback;
}
-void Service::SetNativeServiceStreamCallback(Dart_NativeStreamConsumer consumer,
- const char* stream_id) {
- for (auto stream : streams_) {
- if (stream->id() == stream_id) {
- stream->set_consumer(consumer);
- }
- }
- // Enable stream.
- ListenStream(stream_id);
-}
-
void Service::SetGetServiceAssetsCallback(
Dart_GetVMServiceAssetsArchive get_service_assets) {
get_service_assets_callback_ = get_service_assets;
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index f51eb10..d519124 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -75,15 +75,9 @@
void set_enabled(bool value) { enabled_ = value; }
bool enabled() const { return enabled_; }
- void set_consumer(Dart_NativeStreamConsumer consumer) {
- callback_ = consumer;
- }
- Dart_NativeStreamConsumer consumer() const { return callback_; }
-
private:
const char* id_;
bool enabled_;
- Dart_NativeStreamConsumer callback_;
};
class Service : public AllStatic {
@@ -116,9 +110,6 @@
Dart_ServiceStreamListenCallback listen_callback,
Dart_ServiceStreamCancelCallback cancel_callback);
- static void SetNativeServiceStreamCallback(Dart_NativeStreamConsumer consumer,
- const char* stream_id);
-
static void SetGetServiceAssetsCallback(
Dart_GetVMServiceAssetsArchive get_service_assets);
diff --git a/tools/VERSION b/tools/VERSION
index 7a5b83a..b08b806 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 18
+PRERELEASE 19
PRERELEASE_PATCH 0
\ No newline at end of file