Version 2.17.0-185.0.dev
Merge commit '81860accbcf8d221b582f3c9e629adcd1fcc182d' into 'dev'
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index b60182d..e2c434e 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -390,13 +390,13 @@
}
/// Return the unresolved unit for the file with the given [path].
- ParsedUnitResult? getParsedUnit(String path) {
+ Future<ParsedUnitResult?> getParsedUnit(String path) async {
if (!file_paths.isDart(resourceProvider.pathContext, path)) {
return null;
}
var session = getAnalysisDriver(path)?.currentSession;
- var result = session?.getParsedUnit(path);
+ var result = await session?.getParsedUnit2(path);
return result is ParsedUnitResult ? result : null;
}
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index eeda336..3949a6f 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -518,7 +518,7 @@
}
// Prepare the file information.
- var result = server.getParsedUnit(file);
+ var result = await server.getParsedUnit(file);
if (result == null) {
server.sendResponse(Response.fileNotAnalyzed(request, file));
return;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
index 36aff2e..3c54395 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
@@ -180,7 +180,7 @@
}
/// Get the location of the code (excluding leading doc comments) for this element.
- protocol.Location? _getCodeLocation(Element element) {
+ Future<protocol.Location?> _getCodeLocation(Element element) async {
var codeElement = element;
// For synthetic getters created for fields, we need to access the associated
// variable to get the codeOffset/codeLength.
@@ -206,7 +206,7 @@
// Read the declaration so we can get the offset after the doc comments.
// TODO(dantup): Skip this for parts (getParsedLibrary will throw), but find
// a better solution.
- final declaration = _parsedDeclaration(codeElement);
+ final declaration = await _parsedDeclaration(codeElement);
var node = declaration?.node;
if (node is VariableDeclaration) {
node = node.parent;
@@ -244,9 +244,11 @@
: null;
}
- void _updateTargetsWithCodeLocations(NavigationCollectorImpl collector) {
+ Future<void> _updateTargetsWithCodeLocations(
+ NavigationCollectorImpl collector,
+ ) async {
for (var targetToUpdate in collector.targetsToUpdate) {
- var codeLocation = _getCodeLocation(targetToUpdate.element);
+ var codeLocation = await _getCodeLocation(targetToUpdate.element);
if (codeLocation != null) {
targetToUpdate.target
..codeOffset = codeLocation.offset
@@ -255,7 +257,9 @@
}
}
- static ElementDeclarationResult? _parsedDeclaration(Element element) {
+ static Future<ElementDeclarationResult?> _parsedDeclaration(
+ Element element,
+ ) async {
var session = element.session;
if (session == null) {
return null;
@@ -266,7 +270,7 @@
return null;
}
- var parsedLibrary = session.getParsedLibrary(libraryPath);
+ var parsedLibrary = await session.getParsedLibrary2(libraryPath);
if (parsedLibrary is! ParsedLibraryResult) {
return null;
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart
index 1149fff..a14bb7d 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart
@@ -30,7 +30,7 @@
final partialResults = <List<FoldingRegion>>[];
LineInfo? lineInfo;
- final unit = server.getParsedUnit(path);
+ final unit = await server.getParsedUnit(path);
if (unit != null) {
lineInfo = unit.lineInfo;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
index 84da8f2..528c52b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
@@ -20,14 +20,14 @@
LspJsonHandler<DocumentOnTypeFormattingParams> get jsonHandler =>
DocumentOnTypeFormattingParams.jsonHandler;
- ErrorOr<List<TextEdit>?> formatFile(String path) {
+ Future<ErrorOr<List<TextEdit>?>> formatFile(String path) async {
final file = server.resourceProvider.getFile(path);
if (!file.exists) {
return error(
ServerErrorCodes.InvalidFilePath, 'File does not exist', path);
}
- final result = server.getParsedUnit(path);
+ final result = await server.getParsedUnit(path);
if (result == null || result.errors.isNotEmpty) {
return success(null);
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart
index f28ef15..44143fc 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart
@@ -20,14 +20,14 @@
LspJsonHandler<DocumentRangeFormattingParams> get jsonHandler =>
DocumentRangeFormattingParams.jsonHandler;
- ErrorOr<List<TextEdit>?> formatRange(String path, Range range) {
+ Future<ErrorOr<List<TextEdit>?>> formatRange(String path, Range range) async {
final file = server.resourceProvider.getFile(path);
if (!file.exists) {
return error(
ServerErrorCodes.InvalidFilePath, 'File does not exist', path);
}
- final result = server.getParsedUnit(path);
+ final result = await server.getParsedUnit(path);
if (result == null || result.errors.isNotEmpty) {
return success(null);
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
index 6ff4313..ea279ad 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
@@ -20,14 +20,14 @@
LspJsonHandler<DocumentFormattingParams> get jsonHandler =>
DocumentFormattingParams.jsonHandler;
- ErrorOr<List<TextEdit>?> formatFile(String path) {
+ Future<ErrorOr<List<TextEdit>?>> formatFile(String path) async {
final file = server.resourceProvider.getFile(path);
if (!file.exists) {
return error(
ServerErrorCodes.InvalidFilePath, 'File does not exist', path);
}
- final result = server.getParsedUnit(path);
+ final result = await server.getParsedUnit(path);
if (result == null || result.errors.isNotEmpty) {
return success(null);
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart
index 193002f..0a97e4d 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart
@@ -39,7 +39,7 @@
return success(null);
}
- final unit = requireUnresolvedUnit(path);
+ final unit = await requireUnresolvedUnit(path);
final positions = params.positions;
final offsets = await unit.mapResult((unit) =>
ErrorOr.all(positions.map((pos) => toOffset(unit.lineInfo, pos))));
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
index ddd82dc..0e1c738 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
@@ -83,8 +83,8 @@
return success(result);
}
- ErrorOr<ParsedUnitResult> requireUnresolvedUnit(String path) {
- final result = server.getParsedUnit(path);
+ Future<ErrorOr<ParsedUnitResult>> requireUnresolvedUnit(String path) async {
+ final result = await server.getParsedUnit(path);
if (result == null) {
if (server.isAnalyzed(path)) {
// If the file was being analyzed and we got a null result, that usually
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
index 4042b04..32d5365 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
@@ -57,7 +57,7 @@
if (prefix == null) {
return;
}
- var node = _findNode();
+ var node = await _findNode();
if (node != null) {
var uriEnd = node.uri.end;
var prefixEnd = prefix.nameOffset + prefix.nameLength;
@@ -66,7 +66,7 @@
}
} else {
if (prefix == null) {
- var node = _findNode();
+ var node = await _findNode();
if (node != null) {
var uriEnd = node.uri.end;
edit = newSourceEdit_range(SourceRange(uriEnd, 0), ' as $newName');
@@ -88,15 +88,13 @@
if (newName.isEmpty) {
reference.addEdit(change, '');
} else {
- var interpolationIdentifier = _getInterpolationIdentifier(reference);
- if (interpolationIdentifier != null) {
+ var identifier = await _getInterpolationIdentifier(reference);
+ if (identifier != null) {
doSourceChange_addElementEdit(
change,
reference.element,
- SourceEdit(
- interpolationIdentifier.offset,
- interpolationIdentifier.length,
- '{$newName.${interpolationIdentifier.name}}'));
+ SourceEdit(identifier.offset, identifier.length,
+ '{$newName.${identifier.name}}'));
} else {
reference.addEdit(change, '$newName.');
}
@@ -105,10 +103,10 @@
}
/// Return the [ImportDirective] node that corresponds to the [element].
- ImportDirective? _findNode() {
+ Future<ImportDirective?> _findNode() async {
var library = element.library;
var path = library.source.fullName;
- var unitResult = session.getParsedUnit(path);
+ var unitResult = await session.getParsedUnit2(path);
if (unitResult is! ParsedUnitResult) {
return null;
}
@@ -120,9 +118,11 @@
/// If the given [reference] is before an interpolated [SimpleIdentifier] in
/// an [InterpolationExpression] without surrounding curly brackets, return
/// it. Otherwise return `null`.
- SimpleIdentifier? _getInterpolationIdentifier(SourceReference reference) {
+ Future<SimpleIdentifier?> _getInterpolationIdentifier(
+ SourceReference reference,
+ ) async {
var source = reference.element.source!;
- var unitResult = session.getParsedUnit(source.fullName);
+ var unitResult = await session.getParsedUnit2(source.fullName);
if (unitResult is! ParsedUnitResult) {
return null;
}
diff --git a/pkg/analysis_server/test/integration/linter/lint_names_test.dart b/pkg/analysis_server/test/integration/linter/lint_names_test.dart
index 58031e7..20eea76 100644
--- a/pkg/analysis_server/test/integration/linter/lint_names_test.dart
+++ b/pkg/analysis_server/test/integration/linter/lint_names_test.dart
@@ -16,17 +16,17 @@
void main() {
/// Ensure server lint name representations correspond w/ actual lint rules.
/// See, e.g., https://dart-review.googlesource.com/c/sdk/+/95743.
- group('lint_names', () {
+ test('lint_names', () async {
var pkgRootPath = path.normalize(packageRoot);
var fixFilePath = path.join(pkgRootPath, 'analysis_server', 'lib', 'src',
'services', 'linter', 'lint_names.dart');
var contextCollection = AnalysisContextCollection(
includedPaths: [fixFilePath],
);
- var parseResult = contextCollection
+ var parseResult = await contextCollection
.contextFor(fixFilePath)
.currentSession
- .getParsedUnit(fixFilePath) as ParsedUnitResult;
+ .getParsedUnit2(fixFilePath) as ParsedUnitResult;
if (parseResult.errors.isNotEmpty) {
throw Exception(parseResult.errors);
@@ -38,9 +38,7 @@
var collector = _FixCollector();
lintNamesClass.accept(collector);
for (var name in collector.lintNames) {
- test(name, () {
- expect(registeredLintNames, contains(name));
- });
+ expect(registeredLintNames, contains(name));
}
});
}
diff --git a/pkg/analysis_server/test/services/correction/sort_members_test.dart b/pkg/analysis_server/test/services/correction/sort_members_test.dart
index 5e7fb27..ab012ef 100644
--- a/pkg/analysis_server/test/services/correction/sort_members_test.dart
+++ b/pkg/analysis_server/test/services/correction/sort_members_test.dart
@@ -1512,7 +1512,7 @@
Future<void> _parseTestUnit(String code) async {
addTestSource(code);
- var result = session.getParsedUnit(testFile) as ParsedUnitResult;
+ var result = await session.getParsedUnit2(testFile) as ParsedUnitResult;
lineInfo = result.lineInfo;
testUnit = result.unit;
}
diff --git a/pkg/analysis_server/test/verify_no_solo_test.dart b/pkg/analysis_server/test/verify_no_solo_test.dart
index 150c731..5fe7b8c 100644
--- a/pkg/analysis_server/test/verify_no_solo_test.dart
+++ b/pkg/analysis_server/test/verify_no_solo_test.dart
@@ -45,9 +45,9 @@
fail('The directory $testsPath contains multiple analysis contexts.');
}
- test('no @soloTest', () {
+ test('no @soloTest', () async {
var failures = <String>[];
- buildTestsIn(contexts[0].currentSession, testsPath,
+ await buildTestsIn(contexts[0].currentSession, testsPath,
provider.getFolder(testsPath), failures);
if (failures.isNotEmpty) {
@@ -56,19 +56,19 @@
});
}
-void buildTestsIn(AnalysisSession session, String testDirPath, Folder directory,
- List<String> failures) {
+Future<void> buildTestsIn(AnalysisSession session, String testDirPath,
+ Folder directory, List<String> failures) async {
var pathContext = session.resourceProvider.pathContext;
var children = directory.getChildren();
children.sort((first, second) => first.shortName.compareTo(second.shortName));
for (var child in children) {
if (child is Folder) {
- buildTestsIn(session, testDirPath, child, failures);
+ await buildTestsIn(session, testDirPath, child, failures);
} else if (child is File && child.shortName.endsWith('_test.dart')) {
var path = child.path;
var relativePath = pathContext.relative(path, from: testDirPath);
- var result = session.getParsedUnit(path);
+ var result = await session.getParsedUnit2(path);
if (result is! ParsedUnitResult) {
fail('Could not parse $path');
}
diff --git a/pkg/analysis_server/test/verify_sorted_test.dart b/pkg/analysis_server/test/verify_sorted_test.dart
index 37de909..b63109c 100644
--- a/pkg/analysis_server/test/verify_sorted_test.dart
+++ b/pkg/analysis_server/test/verify_sorted_test.dart
@@ -142,8 +142,8 @@
continue;
}
var relativePath = pathContext.relative(path, from: testDirPath);
- test(relativePath, () {
- var result = session.getParsedUnit(path);
+ test(relativePath, () async {
+ var result = await session.getParsedUnit2(path);
if (result is! ParsedUnitResult) {
fail('Could not parse $path');
}
diff --git a/pkg/analysis_server_client/test/verify_sorted_test.dart b/pkg/analysis_server_client/test/verify_sorted_test.dart
index 8380e74..a4c2904 100644
--- a/pkg/analysis_server_client/test/verify_sorted_test.dart
+++ b/pkg/analysis_server_client/test/verify_sorted_test.dart
@@ -54,8 +54,8 @@
continue;
}
var relativePath = pathContext.relative(path, from: testDirPath);
- test(relativePath, () {
- var result = session.getParsedUnit(path);
+ test(relativePath, () async {
+ var result = await session.getParsedUnit2(path);
if (result is! ParsedUnitResult) {
fail('Could not parse $path');
}
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 0b6f526..aac32ba 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 3.4.0-dev
+* Deprecated synchronous `getFile`, `getParsedLibrary`, `getParsedLibraryByElement`,
+ `getParsedUnit` from `AnalysisSession`. Use corresponding `getXyz2` asynchronous
+ methods instead. This change is necessary for the future work on macros.
+* Deprecated synchronous `getFileSync` from `AnalysisDriver`, use `getFile` instead.
+
## 3.3.1
* Report HintCode.OVERRIDE_ON_NON_OVERRIDING_xyz on enum.
diff --git a/pkg/analyzer/doc/tutorial/ast.md b/pkg/analyzer/doc/tutorial/ast.md
index ed449d8..7f64a05 100644
--- a/pkg/analyzer/doc/tutorial/ast.md
+++ b/pkg/analyzer/doc/tutorial/ast.md
@@ -54,8 +54,8 @@
the AST:
```dart
-void processFile(AnalysisSession session, String path) {
- var result = session.getParsedUnit(path);
+void processFile(AnalysisSession session, String path) async {
+ var result = await session.getParsedUnit2(path);
if (result is ParsedUnitResult) {
CompilationUnit unit = result.unit;
}
diff --git a/pkg/analyzer/lib/dart/analysis/session.dart b/pkg/analyzer/lib/dart/analysis/session.dart
index dc14b0a..9f7e4ff 100644
--- a/pkg/analyzer/lib/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/dart/analysis/session.dart
@@ -39,24 +39,46 @@
/// Return information about the file at the given absolute, normalized
/// [path].
+ @Deprecated('Use getFile2() instead')
SomeFileResult getFile(String path);
+ /// Return information about the file at the given absolute, normalized
+ /// [path].
+ Future<SomeFileResult> getFile2(String path);
+
/// Return a future that will complete with information about the library
/// element representing the library with the given [uri].
Future<SomeLibraryElementResult> getLibraryByUri(String uri);
/// Return information about the results of parsing units of the library file
/// with the given absolute, normalized [path].
+ @Deprecated('Use getParsedLibrary2() instead')
SomeParsedLibraryResult getParsedLibrary(String path);
/// Return information about the results of parsing units of the library file
+ /// with the given absolute, normalized [path].
+ Future<SomeParsedLibraryResult> getParsedLibrary2(String path);
+
+ /// Return information about the results of parsing units of the library file
/// with the given library [element].
+ @Deprecated('Use getParsedLibraryByElement2() instead')
SomeParsedLibraryResult getParsedLibraryByElement(LibraryElement element);
+ /// Return information about the results of parsing units of the library file
+ /// with the given library [element].
+ Future<SomeParsedLibraryResult> getParsedLibraryByElement2(
+ LibraryElement element,
+ );
+
/// Return information about the results of parsing the file with the given
/// absolute, normalized [path].
+ @Deprecated('Use getParsedUnit2() instead')
SomeParsedUnitResult getParsedUnit(String path);
+ /// Return information about the results of parsing the file with the given
+ /// absolute, normalized [path].
+ Future<SomeParsedUnitResult> getParsedUnit2(String path);
+
/// Return a future that will complete with information about the results of
/// resolving all of the files in the library with the given absolute,
/// normalized [path].
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 84644e4..7a3b593 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -588,6 +588,19 @@
return getErrors(path);
}
+ /// Return the [FileResult] for the Dart file with the given [path].
+ ///
+ /// The [path] must be absolute and normalized.
+ Future<SomeFileResult> getFile(String path) async {
+ if (!_isAbsolutePath(path)) {
+ return InvalidPathResult();
+ }
+
+ FileState file = _fileTracker.getFile(path);
+ return FileResultImpl(
+ currentSession, path, file.uri, file.lineInfo, file.isPart);
+ }
+
/// Return a [Future] that completes with the list of added files that
/// define a class member with the given [name].
Future<List<String>> getFilesDefiningClassMemberName(String name) {
@@ -611,6 +624,7 @@
/// Return the [FileResult] for the Dart file with the given [path].
///
/// The [path] must be absolute and normalized.
+ @Deprecated('Use getFile() instead')
SomeFileResult getFileSync(String path) {
if (!_isAbsolutePath(path)) {
return InvalidPathResult();
@@ -624,7 +638,7 @@
/// Return the [FileResult] for the Dart file with the given [path].
///
/// The [path] must be absolute and normalized.
- @Deprecated('Use getFileSync() instead')
+ @Deprecated('Use getFile() instead')
SomeFileResult getFileSync2(String path) {
return getFileSync(path);
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/session.dart b/pkg/analyzer/lib/src/dart/analysis/session.dart
index 32eeaca..47df470 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session.dart
@@ -60,6 +60,7 @@
return _driver.getErrors(path);
}
+ @Deprecated('Use getFile2() instead')
@override
SomeFileResult getFile(String path) {
_checkConsistency();
@@ -67,11 +68,18 @@
}
@override
+ Future<SomeFileResult> getFile2(String path) async {
+ _checkConsistency();
+ return _driver.getFile(path);
+ }
+
+ @override
Future<SomeLibraryElementResult> getLibraryByUri(String uri) {
_checkConsistency();
return _driver.getLibraryByUri(uri);
}
+ @Deprecated('Use getParsedLibrary2() instead')
@override
SomeParsedLibraryResult getParsedLibrary(String path) {
_checkConsistency();
@@ -79,6 +87,13 @@
}
@override
+ Future<SomeParsedLibraryResult> getParsedLibrary2(String path) async {
+ _checkConsistency();
+ return _driver.getParsedLibrary(path);
+ }
+
+ @Deprecated('Use getParsedLibraryByElement2() instead')
+ @override
SomeParsedLibraryResult getParsedLibraryByElement(LibraryElement element) {
_checkConsistency();
@@ -90,12 +105,32 @@
}
@override
+ Future<SomeParsedLibraryResult> getParsedLibraryByElement2(
+ LibraryElement element,
+ ) async {
+ _checkConsistency();
+
+ if (element.session != this) {
+ return NotElementOfThisSessionResult();
+ }
+
+ return _driver.getParsedLibraryByUri(element.source.uri);
+ }
+
+ @Deprecated('Use getParsedUnit2() instead')
+ @override
SomeParsedUnitResult getParsedUnit(String path) {
_checkConsistency();
return _driver.parseFileSync(path);
}
@override
+ Future<SomeParsedUnitResult> getParsedUnit2(String path) async {
+ _checkConsistency();
+ return _driver.parseFileSync(path);
+ }
+
+ @override
Future<SomeResolvedLibraryResult> getResolvedLibrary(String path) {
_checkConsistency();
return _driver.getResolvedLibrary(path);
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 064de4b..768ae62 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 3.3.1
+version: 3.4.0-dev
description: This package provides a library that performs static analysis of Dart code.
homepage: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index afefd83..67951ae 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -1380,6 +1380,66 @@
expect(result, isA<InvalidPathResult>());
}
+ test_getFile_changedFile() async {
+ var a = convertPath('/test/lib/a.dart');
+ var b = convertPath('/test/lib/b.dart');
+
+ newFile(a, content: '');
+ newFile(b, content: r'''
+import 'a.dart';
+
+void f(A a) {}
+''');
+
+ // Ensure that [a.dart] library cycle is loaded.
+ // So, `a.dart` is in the library context.
+ await driver.getResultValid(a);
+
+ // Update the file, changing its API signature.
+ // Note that we don't call `changeFile`.
+ newFile(a, content: 'class A {}\n');
+
+ // Get the file.
+ // We have not called `changeFile(a)`, so we should not read the file.
+ // Moreover, doing this will create a new library cycle [a.dart].
+ // Library cycles are compared by their identity, so we would try to
+ // reload linked summary for [a.dart], and crash.
+ expect((await driver.getFileValid(a)).lineInfo.lineCount, 1);
+
+ // We have not read `a.dart`, so `A` is still not declared.
+ expect((await driver.getResultValid(b)).errors, isNotEmpty);
+
+ // Notify the driver that the file was changed.
+ driver.changeFile(a);
+
+ // So, `class A {}` is declared now.
+ expect((await driver.getFileValid(a)).lineInfo.lineCount, 2);
+ expect((await driver.getResultValid(b)).errors, isEmpty);
+ }
+
+ test_getFile_library() async {
+ var path = convertPath('/test/lib/a.dart');
+ newFile(path);
+ var file = await driver.getFileValid(path);
+ expect(file.path, path);
+ expect(file.uri.toString(), 'package:test/a.dart');
+ expect(file.isPart, isFalse);
+ }
+
+ test_getFile_notAbsolutePath() async {
+ var result = await driver.getFile('not_absolute.dart');
+ expect(result, isA<InvalidPathResult>());
+ }
+
+ test_getFile_part() async {
+ var path = convertPath('/test/lib/a.dart');
+ newFile(path, content: 'part of lib;');
+ var file = await driver.getFileValid(path);
+ expect(file.path, path);
+ expect(file.uri.toString(), 'package:test/a.dart');
+ expect(file.isPart, isTrue);
+ }
+
test_getFilesDefiningClassMemberName_class() async {
var a = convertPath('/test/bin/a.dart');
var b = convertPath('/test/bin/b.dart');
@@ -1483,6 +1543,7 @@
expect(files, isNot(contains(c)));
}
+ @deprecated
test_getFileSync_changedFile() async {
var a = convertPath('/test/lib/a.dart');
var b = convertPath('/test/lib/b.dart');
@@ -1520,6 +1581,7 @@
expect((await driver.getResultValid(b)).errors, isEmpty);
}
+ @deprecated
test_getFileSync_library() async {
var path = convertPath('/test/lib/a.dart');
newFile(path);
@@ -1529,11 +1591,13 @@
expect(file.isPart, isFalse);
}
+ @deprecated
test_getFileSync_notAbsolutePath() async {
var result = driver.getFileSync('not_absolute.dart');
expect(result, isA<InvalidPathResult>());
}
+ @deprecated
test_getFileSync_part() async {
var path = convertPath('/test/lib/a.dart');
newFile(path, content: 'part of lib;');
@@ -3451,10 +3515,15 @@
}
}
+ @deprecated
FileResult getFileSyncValid(String path) {
return getFileSync(path) as FileResult;
}
+ Future<FileResult> getFileValid(String path) async {
+ return await getFile(path) as FileResult;
+ }
+
Future<LibraryElementResult> getLibraryByUriValid(String uriStr) async {
return await getLibraryByUri(uriStr) as LibraryElementResult;
}
diff --git a/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart b/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart
index d570325..b1a26bd 100644
--- a/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart
@@ -461,7 +461,7 @@
newFile(testFilePath, content: 'class A {}');
// Read the file.
- testDriver.getFileSync(testFilePathPlatform);
+ await testDriver.getFile(testFilePathPlatform);
// Should call `changeFile()`, and the driver must re-read the file.
var result = _resolveTestCode(r'''
diff --git a/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart b/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart
index 983d7bb..f60b34d 100644
--- a/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/results/get_element_declaration_test.dart
@@ -433,13 +433,13 @@
Future<ElementDeclarationResult?> getElementDeclaration(
Element element) async {
var libraryPath = element.library!.source.fullName;
- var library = _getParsedLibrary(libraryPath);
+ var library = await _getParsedLibrary(libraryPath);
return library.getElementDeclaration(element);
}
- ParsedLibraryResult _getParsedLibrary(String path) {
+ Future<ParsedLibraryResult> _getParsedLibrary(String path) async {
var session = contextFor(path).currentSession;
- return session.getParsedLibrary(path) as ParsedLibraryResult;
+ return await session.getParsedLibrary2(path) as ParsedLibraryResult;
}
}
diff --git a/pkg/analyzer/test/src/dart/analysis/session_test.dart b/pkg/analyzer/test/src/dart/analysis/session_test.dart
index 6953e85..db20934 100644
--- a/pkg/analyzer/test/src/dart/analysis/session_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/session_test.dart
@@ -44,6 +44,17 @@
expect(result.uri.toString(), 'package:dart.my/a.dart');
}
+ void test_getParsedLibrary2_notFileOfUri() async {
+ var relPath = 'dart/my/lib/a.dart';
+ newFile('$workspaceRootPath/bazel-bin/$relPath');
+
+ var path = convertPath('$workspaceRootPath/$relPath');
+ var session = contextFor(path).currentSession;
+ var result = await session.getParsedLibrary2(path);
+ expect(result, isA<NotPathOfUriResult>());
+ }
+
+ @deprecated
void test_getParsedLibrary_notFileOfUri() async {
var relPath = 'dart/my/lib/a.dart';
newFile('$workspaceRootPath/bazel-bin/$relPath');
@@ -150,13 +161,44 @@
expect(errorsResult, isA<InvalidPathResult>());
}
- test_getFile_invalidPath_notAbsolute() async {
+ test_getFile2_inconsistent() async {
+ var test = newFile(testFilePath, content: '');
+ var session = contextFor(test.path).currentSession;
+ driverFor(test.path).changeFile(test.path);
+ expect(
+ () async => session.getFile2(test.path),
+ throwsA(isA<InconsistentAnalysisException>()),
+ );
+ }
+
+ test_getFile2_invalidPath_notAbsolute() async {
var session = contextFor(testFilePath).currentSession;
- var errorsResult = session.getFile('not_absolute.dart');
+ var errorsResult = await session.getFile2('not_absolute.dart');
expect(errorsResult, isA<InvalidPathResult>());
}
- test_getFileSync_inconsistent() async {
+ test_getFile2_library() async {
+ var a = newFile('$testPackageLibPath/a.dart', content: '');
+
+ var session = contextFor(testFilePath).currentSession;
+ var file = await session.getFile2Valid(a.path);
+ expect(file.path, a.path);
+ expect(file.uri.toString(), 'package:test/a.dart');
+ expect(file.isPart, isFalse);
+ }
+
+ test_getFile2_part() async {
+ var a = newFile('$testPackageLibPath/a.dart', content: 'part of lib;');
+
+ var session = contextFor(testFilePath).currentSession;
+ var file = await session.getFile2Valid(a.path);
+ expect(file.path, a.path);
+ expect(file.uri.toString(), 'package:test/a.dart');
+ expect(file.isPart, isTrue);
+ }
+
+ @deprecated
+ test_getFile_inconsistent() async {
var test = newFile(testFilePath, content: '');
var session = contextFor(test.path).currentSession;
driverFor(test.path).changeFile(test.path);
@@ -166,7 +208,15 @@
);
}
- test_getFileSync_library() async {
+ @deprecated
+ test_getFile_invalidPath_notAbsolute() async {
+ var session = contextFor(testFilePath).currentSession;
+ var errorsResult = session.getFile('not_absolute.dart');
+ expect(errorsResult, isA<InvalidPathResult>());
+ }
+
+ @deprecated
+ test_getFile_library() async {
var a = newFile('$testPackageLibPath/a.dart', content: '');
var session = contextFor(testFilePath).currentSession;
@@ -176,7 +226,8 @@
expect(file.isPart, isFalse);
}
- test_getFileSync_part() async {
+ @deprecated
+ test_getFile_part() async {
var a = newFile('$testPackageLibPath/a.dart', content: 'part of lib;');
var session = contextFor(testFilePath).currentSession;
@@ -216,6 +267,7 @@
expect(result, isA<CannotResolveUriResult>());
}
+ @deprecated
test_getParsedLibrary() async {
var test = newFile('$testPackageLibPath/a.dart', content: r'''
class A {}
@@ -236,6 +288,189 @@
}
}
+ test_getParsedLibrary2() async {
+ var test = newFile('$testPackageLibPath/a.dart', content: r'''
+class A {}
+class B {}
+''');
+
+ var session = contextFor(testFilePath).currentSession;
+ var parsedLibrary = await session.getParsedLibrary2Valid(test.path);
+ expect(parsedLibrary.session, session);
+
+ expect(parsedLibrary.units, hasLength(1));
+ {
+ var parsedUnit = parsedLibrary.units[0];
+ expect(parsedUnit.session, session);
+ expect(parsedUnit.path, test.path);
+ expect(parsedUnit.uri, Uri.parse('package:test/a.dart'));
+ expect(parsedUnit.unit.declarations, hasLength(2));
+ }
+ }
+
+ test_getParsedLibrary2_getElementDeclaration_class() async {
+ var test = newFile(testFilePath, content: r'''
+class A {}
+class B {}
+''');
+
+ var session = contextFor(testFilePath).currentSession;
+ var libraryResult = await session.getLibraryByUriValid(
+ 'package:test/test.dart',
+ );
+ var parsedLibrary = await session.getParsedLibrary2Valid(test.path);
+
+ var element = libraryResult.element.getType('A')!;
+ var declaration = parsedLibrary.getElementDeclaration(element)!;
+ var node = declaration.node as ClassDeclaration;
+ expect(node.name.name, 'A');
+ expect(node.offset, 0);
+ expect(node.length, 10);
+ }
+
+ test_getParsedLibrary2_getElementDeclaration_notThisLibrary() async {
+ var test = newFile(testFilePath, content: '');
+
+ var session = contextFor(testFilePath).currentSession;
+ var resolvedUnit =
+ await session.getResolvedUnit(test.path) as ResolvedUnitResult;
+ var typeProvider = resolvedUnit.typeProvider;
+ var intClass = typeProvider.intType.element;
+
+ var parsedLibrary = await session.getParsedLibrary2Valid(test.path);
+
+ expect(() {
+ parsedLibrary.getElementDeclaration(intClass);
+ }, throwsArgumentError);
+ }
+
+ test_getParsedLibrary2_getElementDeclaration_synthetic() async {
+ var test = newFile(testFilePath, content: r'''
+int foo = 0;
+''');
+
+ var session = contextFor(testFilePath).currentSession;
+ var parsedLibrary = await session.getParsedLibrary2Valid(test.path);
+
+ var unitResult = await session.getUnitElementValid(test.path);
+ var fooElement = unitResult.element.topLevelVariables[0];
+ expect(fooElement.name, 'foo');
+
+ // We can get the variable element declaration.
+ var fooDeclaration = parsedLibrary.getElementDeclaration(fooElement)!;
+ var fooNode = fooDeclaration.node as VariableDeclaration;
+ expect(fooNode.name.name, 'foo');
+ expect(fooNode.offset, 4);
+ expect(fooNode.length, 7);
+ expect(fooNode.name.staticElement, isNull);
+
+ // Synthetic elements don't have nodes.
+ expect(parsedLibrary.getElementDeclaration(fooElement.getter!), isNull);
+ expect(parsedLibrary.getElementDeclaration(fooElement.setter!), isNull);
+ }
+
+ test_getParsedLibrary2_inconsistent() async {
+ var test = newFile(testFilePath, content: '');
+ var session = contextFor(test.path).currentSession;
+ driverFor(test.path).changeFile(test.path);
+ expect(
+ () => session.getParsedLibrary2(test.path),
+ throwsA(isA<InconsistentAnalysisException>()),
+ );
+ }
+
+ test_getParsedLibrary2_invalidPartUri() async {
+ var test = newFile(testFilePath, content: r'''
+part 'a.dart';
+part ':[invalid uri].dart';
+part 'c.dart';
+''');
+
+ var session = contextFor(testFilePath).currentSession;
+ var parsedLibrary = await session.getParsedLibrary2Valid(test.path);
+
+ expect(parsedLibrary.units, hasLength(3));
+ expect(
+ parsedLibrary.units[0].path,
+ convertPath('/home/test/lib/test.dart'),
+ );
+ expect(
+ parsedLibrary.units[1].path,
+ convertPath('/home/test/lib/a.dart'),
+ );
+ expect(
+ parsedLibrary.units[2].path,
+ convertPath('/home/test/lib/c.dart'),
+ );
+ }
+
+ test_getParsedLibrary2_invalidPath_notAbsolute() async {
+ var session = contextFor(testFilePath).currentSession;
+ var result = await session.getParsedLibrary2('not_absolute.dart');
+ expect(result, isA<InvalidPathResult>());
+ }
+
+ test_getParsedLibrary2_notLibrary() async {
+ var test = newFile(testFilePath, content: 'part of "a.dart";');
+ var session = contextFor(testFilePath).currentSession;
+ var result = await session.getParsedLibrary2(test.path);
+ expect(result, isA<NotLibraryButPartResult>());
+ }
+
+ test_getParsedLibrary2_parts() async {
+ var aContent = r'''
+part 'b.dart';
+part 'c.dart';
+
+class A {}
+''';
+
+ var bContent = r'''
+part of 'a.dart';
+
+class B1 {}
+class B2 {}
+''';
+
+ var cContent = r'''
+part of 'a.dart';
+
+class C1 {}
+class C2 {}
+class C3 {}
+''';
+
+ var a = newFile('$testPackageLibPath/a.dart', content: aContent);
+ var b = newFile('$testPackageLibPath/b.dart', content: bContent);
+ var c = newFile('$testPackageLibPath/c.dart', content: cContent);
+
+ var session = contextFor(testFilePath).currentSession;
+ var parsedLibrary = await session.getParsedLibrary2Valid(a.path);
+ expect(parsedLibrary.units, hasLength(3));
+
+ {
+ var aUnit = parsedLibrary.units[0];
+ expect(aUnit.path, a.path);
+ expect(aUnit.uri, Uri.parse('package:test/a.dart'));
+ expect(aUnit.unit.declarations, hasLength(1));
+ }
+
+ {
+ var bUnit = parsedLibrary.units[1];
+ expect(bUnit.path, b.path);
+ expect(bUnit.uri, Uri.parse('package:test/b.dart'));
+ expect(bUnit.unit.declarations, hasLength(2));
+ }
+
+ {
+ var cUnit = parsedLibrary.units[2];
+ expect(cUnit.path, c.path);
+ expect(cUnit.uri, Uri.parse('package:test/c.dart'));
+ expect(cUnit.unit.declarations, hasLength(3));
+ }
+ }
+
+ @deprecated
test_getParsedLibrary_getElementDeclaration_class() async {
var test = newFile(testFilePath, content: r'''
class A {}
@@ -256,6 +491,7 @@
expect(node.length, 10);
}
+ @deprecated
test_getParsedLibrary_getElementDeclaration_notThisLibrary() async {
var test = newFile(testFilePath, content: '');
@@ -272,6 +508,7 @@
}, throwsArgumentError);
}
+ @deprecated
test_getParsedLibrary_getElementDeclaration_synthetic() async {
var test = newFile(testFilePath, content: r'''
int foo = 0;
@@ -297,6 +534,7 @@
expect(parsedLibrary.getElementDeclaration(fooElement.setter!), isNull);
}
+ @deprecated
test_getParsedLibrary_inconsistent() async {
var test = newFile(testFilePath, content: '');
var session = contextFor(test.path).currentSession;
@@ -307,6 +545,7 @@
);
}
+ @deprecated
test_getParsedLibrary_invalidPartUri() async {
var test = newFile(testFilePath, content: r'''
part 'a.dart';
@@ -332,18 +571,21 @@
);
}
+ @deprecated
test_getParsedLibrary_invalidPath_notAbsolute() async {
var session = contextFor(testFilePath).currentSession;
var result = session.getParsedLibrary('not_absolute.dart');
expect(result, isA<InvalidPathResult>());
}
+ @deprecated
test_getParsedLibrary_notLibrary() async {
var test = newFile(testFilePath, content: 'part of "a.dart";');
var session = contextFor(testFilePath).currentSession;
expect(session.getParsedLibrary(test.path), isA<NotLibraryButPartResult>());
}
+ @deprecated
test_getParsedLibrary_parts() async {
var aContent = r'''
part 'b.dart';
@@ -397,6 +639,7 @@
}
}
+ @deprecated
test_getParsedLibraryByElement() async {
var test = newFile(testFilePath, content: '');
@@ -418,6 +661,43 @@
}
}
+ test_getParsedLibraryByElement2() async {
+ var test = newFile(testFilePath, content: '');
+
+ var session = contextFor(testFilePath).currentSession;
+ var libraryResult = await session.getLibraryByUriValid(
+ 'package:test/test.dart',
+ );
+ var element = libraryResult.element;
+
+ var parsedLibrary = await session.getParsedLibraryByElement2Valid(element);
+ expect(parsedLibrary.session, session);
+ expect(parsedLibrary.units, hasLength(1));
+
+ {
+ var unit = parsedLibrary.units[0];
+ expect(unit.path, test.path);
+ expect(unit.uri, Uri.parse('package:test/test.dart'));
+ expect(unit.unit, isNotNull);
+ }
+ }
+
+ test_getParsedLibraryByElement2_differentSession() async {
+ newFile(testFilePath, content: '');
+
+ var session = contextFor(testFilePath).currentSession;
+ var libraryResult = await session.getLibraryByUriValid(
+ 'package:test/test.dart',
+ );
+ var element = libraryResult.element;
+
+ var aaaSession = contextFor('$workspaceRootPath/aaa').currentSession;
+
+ var result = await aaaSession.getParsedLibraryByElement2(element);
+ expect(result, isA<NotElementOfThisSessionResult>());
+ }
+
+ @deprecated
test_getParsedLibraryByElement_differentSession() async {
newFile(testFilePath, content: '');
@@ -433,6 +713,7 @@
expect(result, isA<NotElementOfThisSessionResult>());
}
+ @deprecated
test_getParsedUnit() async {
var test = newFile(testFilePath, content: r'''
class A {}
@@ -447,6 +728,37 @@
expect(unitResult.unit.declarations, hasLength(2));
}
+ test_getParsedUnit2() async {
+ var test = newFile(testFilePath, content: r'''
+class A {}
+class B {}
+''');
+
+ var session = contextFor(testFilePath).currentSession;
+ var unitResult = await session.getParsedUnit2Valid(test.path);
+ expect(unitResult.session, session);
+ expect(unitResult.path, test.path);
+ expect(unitResult.uri, Uri.parse('package:test/test.dart'));
+ expect(unitResult.unit.declarations, hasLength(2));
+ }
+
+ test_getParsedUnit2_inconsistent() async {
+ var test = newFile(testFilePath, content: '');
+ var session = contextFor(test.path).currentSession;
+ driverFor(test.path).changeFile(test.path);
+ expect(
+ () => session.getParsedUnit2(test.path),
+ throwsA(isA<InconsistentAnalysisException>()),
+ );
+ }
+
+ test_getParsedUnit2_invalidPath_notAbsolute() async {
+ var session = contextFor(testFilePath).currentSession;
+ var result = await session.getParsedUnit2('not_absolute.dart');
+ expect(result, isA<InvalidPathResult>());
+ }
+
+ @deprecated
test_getParsedUnit_inconsistent() async {
var test = newFile(testFilePath, content: '');
var session = contextFor(test.path).currentSession;
@@ -457,6 +769,7 @@
);
}
+ @deprecated
test_getParsedUnit_invalidPath_notAbsolute() async {
var session = contextFor(testFilePath).currentSession;
var result = session.getParsedUnit('not_absolute.dart');
@@ -705,6 +1018,11 @@
return await getErrors(path) as ErrorsResult;
}
+ Future<FileResult> getFile2Valid(String path) async {
+ return await getFile2(path) as FileResult;
+ }
+
+ @deprecated
FileResult getFileValid(String path) {
return getFile(path) as FileResult;
}
@@ -713,14 +1031,31 @@
return await getLibraryByUri(path) as LibraryElementResult;
}
+ Future<ParsedLibraryResult> getParsedLibrary2Valid(String path) async {
+ return await getParsedLibrary2(path) as ParsedLibraryResult;
+ }
+
+ Future<ParsedLibraryResult> getParsedLibraryByElement2Valid(
+ LibraryElement element,
+ ) async {
+ return await getParsedLibraryByElement2(element) as ParsedLibraryResult;
+ }
+
+ @deprecated
ParsedLibraryResult getParsedLibraryByElementValid(LibraryElement element) {
return getParsedLibraryByElement(element) as ParsedLibraryResult;
}
+ @deprecated
ParsedLibraryResult getParsedLibraryValid(String path) {
return getParsedLibrary(path) as ParsedLibraryResult;
}
+ Future<ParsedUnitResult> getParsedUnit2Valid(String path) async {
+ return await getParsedUnit2(path) as ParsedUnitResult;
+ }
+
+ @deprecated
ParsedUnitResult getParsedUnitValid(String path) {
return getParsedUnit(path) as ParsedUnitResult;
}
diff --git a/pkg/analyzer/test/src/services/available_declarations_test.dart b/pkg/analyzer/test/src/services/available_declarations_test.dart
index 357ca89..efd0cc1 100644
--- a/pkg/analyzer/test/src/services/available_declarations_test.dart
+++ b/pkg/analyzer/test/src/services/available_declarations_test.dart
@@ -3625,9 +3625,9 @@
newFile(a, content: 'class A {}');
newFile(b, content: 'class B {}');
newFile(c, content: 'class C {}');
- testAnalysisContext.currentSession.getFile(a);
- testAnalysisContext.currentSession.getFile(b);
- testAnalysisContext.currentSession.getFile(c);
+ await testAnalysisContext.currentSession.getFile2(a);
+ await testAnalysisContext.currentSession.getFile2(b);
+ await testAnalysisContext.currentSession.getFile2(c);
var context = tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
diff --git a/pkg/analyzer_cli/analysis_options.yaml b/pkg/analyzer_cli/analysis_options.yaml
index 8d202f9..2747e0f 100644
--- a/pkg/analyzer_cli/analysis_options.yaml
+++ b/pkg/analyzer_cli/analysis_options.yaml
@@ -9,11 +9,27 @@
linter:
rules:
+ always_declare_return_types: true
+ avoid_empty_else: true
+ avoid_relative_lib_imports: true
+ avoid_shadowing_type_parameters: true
+ avoid_types_as_parameter_names: true
avoid_unused_constructor_parameters: true
+ camel_case_extensions: true
+ curly_braces_in_flow_control_structures: true
depend_on_referenced_packages: true
directives_ordering: true
+ empty_catches: true
# We import heavily from package:analyzer/src.
implementation_imports: false
# This rule does not work well with package:test_reflective_loader.
+ no_duplicate_case_values: true
non_constant_identifier_names: false
+ omit_local_variable_types: true
+ prefer_is_empty: true
+ prefer_is_not_empty: true
+ prefer_iterable_whereType: true
+ prefer_single_quotes: true
+ unawaited_futures: true
+ unrelated_type_equality_checks: true
diff --git a/pkg/analyzer_cli/lib/src/analyzer_impl.dart b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
index fff1252..7e40fff 100644
--- a/pkg/analyzer_cli/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
@@ -148,7 +148,7 @@
// Print errors and performance numbers.
if (printMode == 1) {
- formatter.formatErrors(errorsResults);
+ await formatter.formatErrors(errorsResults);
} else if (printMode == 2) {
_printColdPerf();
}
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index de1d3c0..6c75fd3 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -248,7 +248,7 @@
analysisDriver.sourceFactory,
analysisDriver.currentSession.analysisContext.contextRoot.root.path,
);
- formatter.formatErrors([
+ await formatter.formatErrors([
ErrorsResultImpl(analysisDriver.currentSession, path,
pathContext.toUri(path), lineInfo, false, errors)
]);
@@ -304,7 +304,7 @@
allResult = allResult.max(severity);
}
var lineInfo = LineInfo.fromContent(content);
- formatter.formatErrors([
+ await formatter.formatErrors([
ErrorsResultImpl(analysisDriver.currentSession, path,
pathContext.toUri(path), lineInfo, false, errors)
]);
@@ -320,7 +320,7 @@
var lineInfo = LineInfo.fromContent(content);
var errors = validator.validate(
content, analysisDriver.analysisOptions.chromeOsManifestChecks);
- formatter.formatErrors([
+ await formatter.formatErrors([
ErrorsResultImpl(analysisDriver.currentSession, path,
pathContext.toUri(path), lineInfo, false, errors)
]);
diff --git a/pkg/analyzer_cli/lib/src/error_formatter.dart b/pkg/analyzer_cli/lib/src/error_formatter.dart
index 51c7002..88147da 100644
--- a/pkg/analyzer_cli/lib/src/error_formatter.dart
+++ b/pkg/analyzer_cli/lib/src/error_formatter.dart
@@ -189,10 +189,10 @@
/// Call to write any batched up errors from [formatErrors].
void flush();
- void formatError(
+ Future<void> formatError(
Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error);
- void formatErrors(List<ErrorsResult> results) {
+ Future<void> formatErrors(List<ErrorsResult> results) async {
stats.unfilteredCount += results.length;
var errors = <AnalysisError>[];
@@ -207,7 +207,7 @@
}
for (var error in errors) {
- formatError(errorToLine, error);
+ await formatError(errorToLine, error);
}
}
@@ -276,8 +276,8 @@
}
@override
- void formatError(
- Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) {
+ Future<void> formatError(
+ Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) async {
var source = error.source;
var result = errorToLine[error]!;
var location = result.lineInfo.getLocation(error.offset);
@@ -308,9 +308,10 @@
}
var contextMessages = <ContextMessage>[];
for (var message in error.contextMessages) {
+ // TODO(scheglov) We should add `LineInfo` to `DiagnosticMessage`.
var session = result.session.analysisContext;
if (session is DriverBasedAnalysisContext) {
- var fileResult = session.driver.getFileSync(message.filePath);
+ var fileResult = await session.driver.getFile(message.filePath);
if (fileResult is FileResult) {
var lineInfo = fileResult.lineInfo;
var location = lineInfo.getLocation(message.offset);
@@ -348,13 +349,13 @@
void flush() {}
@override
- void formatError(
- Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) {
+ Future<void> formatError(
+ Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) async {
throw UnsupportedError('Cannot format a single error');
}
@override
- void formatErrors(List<ErrorsResult> results) {
+ Future<void> formatErrors(List<ErrorsResult> results) async {
Map<String, dynamic> range(
Map<String, dynamic> start, Map<String, dynamic> end) =>
{
@@ -435,8 +436,8 @@
void flush() {}
@override
- void formatError(
- Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) {
+ Future<void> formatError(
+ Map<AnalysisError, ErrorsResult> errorToLine, AnalysisError error) async {
// Ensure we don't over-report (#36062).
if (!_seenErrors.add(error)) {
return;
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index de57da2..683562a 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -464,7 +464,7 @@
]);
expect(processorFor(missing_return).severity, ErrorSeverity.ERROR);
expect(bulletToDash(outSink),
- contains("error - The body might complete normally"));
+ contains('error - The body might complete normally'));
expect(outSink.toString(), contains('1 error and 1 warning found.'));
}
diff --git a/pkg/analyzer_cli/test/mocks.dart b/pkg/analyzer_cli/test/mocks.dart
index a8b487a..3de1eb3 100644
--- a/pkg/analyzer_cli/test/mocks.dart
+++ b/pkg/analyzer_cli/test/mocks.dart
@@ -116,7 +116,7 @@
}
@override
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+ dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockLineInfo implements LineInfo {
@@ -163,5 +163,5 @@
MockSource(this.fullName, this.uri);
@override
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+ dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
diff --git a/pkg/analyzer_cli/test/reporter_test.dart b/pkg/analyzer_cli/test/reporter_test.dart
index cffb0ff..54a2964 100644
--- a/pkg/analyzer_cli/test/reporter_test.dart
+++ b/pkg/analyzer_cli/test/reporter_test.dart
@@ -44,27 +44,27 @@
reporter = HumanErrorFormatter(out, options, stats);
});
- test('error', () {
+ test('error', () async {
var error = mockResult(ErrorType.SYNTACTIC_ERROR, ErrorSeverity.ERROR);
- reporter.formatErrors([error]);
+ await reporter.formatErrors([error]);
reporter.flush();
expect(out.toString().trim(),
'error • MSG • /foo/bar/baz.dart:3:3 • mock_code');
});
- test('hint', () {
+ test('hint', () async {
var error = mockResult(ErrorType.HINT, ErrorSeverity.INFO);
- reporter.formatErrors([error]);
+ await reporter.formatErrors([error]);
reporter.flush();
expect(out.toString().trim(),
'hint • MSG • /foo/bar/baz.dart:3:3 • mock_code');
});
- test('stats', () {
+ test('stats', () async {
var error = mockResult(ErrorType.HINT, ErrorSeverity.INFO);
- reporter.formatErrors([error]);
+ await reporter.formatErrors([error]);
reporter.flush();
stats.print(out);
expect(
@@ -79,9 +79,9 @@
reporter = JsonErrorFormatter(out, options, stats);
});
- test('error', () {
+ test('error', () async {
var error = mockResult(ErrorType.SYNTACTIC_ERROR, ErrorSeverity.ERROR);
- reporter.formatErrors([error]);
+ await reporter.formatErrors([error]);
reporter.flush();
expect(
@@ -108,11 +108,11 @@
var source = MockSource(path, package_path.toUri(path));
var error = MockAnalysisError(source, code, 20, 'MSG');
- return ErrorsResultImpl(_MockAnslysisSession(), source.fullName,
+ return ErrorsResultImpl(_MockAnalysisSession(), source.fullName,
Uri.file('/'), lineInfo, false, [error]);
}
-class _MockAnslysisSession implements AnalysisSession {
+class _MockAnalysisSession implements AnalysisSession {
@override
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+ dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
diff --git a/pkg/analyzer_utilities/lib/verify_tests.dart b/pkg/analyzer_utilities/lib/verify_tests.dart
index de1bf43..9bc21e4 100644
--- a/pkg/analyzer_utilities/lib/verify_tests.dart
+++ b/pkg/analyzer_utilities/lib/verify_tests.dart
@@ -87,7 +87,7 @@
}
}
var relativePath = path.relative(directory.path, from: testDirPath);
- test(relativePath, () {
+ test(relativePath, () async {
if (testFileNames.isEmpty) {
return;
}
@@ -103,7 +103,7 @@
if (isOkForTestAllToBeMissing(directory)) {
fail('Found "test_all.dart" in $relativePath but did not expect one');
}
- var result = session.getParsedUnit(testAllFile.path);
+ var result = await session.getParsedUnit2(testAllFile.path);
if (result is! ParsedUnitResult) {
fail('Could not parse ${testAllFile.path}');
}
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 5ae0b2a..96cdc9b 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -47,8 +47,9 @@
final Map<VariableDeclaration, w.Local> locals = {};
w.Local? thisLocal;
w.Local? preciseThisLocal;
+ w.Local? returnValueLocal;
final Map<TypeParameter, w.Local> typeLocals = {};
- final List<Statement> finalizers = [];
+ final List<TryBlockFinalizer> finalizers = [];
final List<w.Label> tryLabels = [];
final Map<LabeledStatement, w.Label> labels = {};
final Map<SwitchCase, w.Label> switchLabels = {};
@@ -622,9 +623,39 @@
@override
void visitTryFinally(TryFinally node) {
- finalizers.add(node.finalizer);
+ // We lower a [TryFinally] to three nested blocks, and we emit the finalizer
+ // up to three times. Once in a catch, to handle the case where the try
+ // throws. Once outside of the catch, to handle the case where the try does
+ // not throw. Finally, if there is a return within the try block, then we
+ // emit the finalizer one more time along with logic to continue walking up
+ // the stack.
+ w.Label tryFinallyBlock = b.block();
+ w.Label finalizerBlock = b.block();
+ finalizers.add(TryBlockFinalizer(finalizerBlock));
+ w.Label tryBlock = b.try_();
node.body.accept(this);
- finalizers.removeLast().accept(this);
+ bool mustHandleReturn = finalizers.removeLast().mustHandleReturn;
+ b.br(tryBlock);
+ b.catch_(translator.exceptionTag);
+ node.finalizer.accept(this);
+ b.rethrow_(tryBlock);
+ b.end(); // end tryBlock.
+ node.finalizer.accept(this);
+ b.br(tryFinallyBlock);
+ b.end(); // end finalizerBlock.
+ if (mustHandleReturn) {
+ node.finalizer.accept(this);
+ if (finalizers.isNotEmpty) {
+ b.br(finalizers.last.label);
+ } else {
+ if (returnValueLocal != null) {
+ b.local_get(returnValueLocal!);
+ translator.convertType(function, returnValueLocal!.type, returnType);
+ }
+ _returnFromFunction();
+ }
+ }
+ b.end(); // end tryFinallyBlock.
}
@override
@@ -768,6 +799,17 @@
throw "ForInStatement should have been desugared: $node";
}
+ /// Handle the return from this function, either by jumping to [returnLabel]
+ /// in the case this function was inlined or just inserting a return
+ /// instruction.
+ void _returnFromFunction() {
+ if (returnLabel != null) {
+ b.br(returnLabel!);
+ } else {
+ b.return_();
+ }
+ }
+
@override
void visitReturnStatement(ReturnStatement node) {
Expression? expression = node.expression;
@@ -776,13 +818,22 @@
} else {
translator.convertType(function, voidMarker, returnType);
}
- for (Statement finalizer in finalizers.reversed) {
- finalizer.accept(this);
- }
- if (returnLabel != null) {
- b.br(returnLabel!);
+
+ // If we are wrapped in a [TryFinally] node then we have to run finalizers
+ // as the stack unwinds. When we get to the top of the finalizer stack, we
+ // will handle the return using [returnValueLocal] if this function returns
+ // a value.
+ if (finalizers.isNotEmpty) {
+ for (TryBlockFinalizer finalizer in finalizers) {
+ finalizer.mustHandleReturn = true;
+ }
+ if (returnType != voidMarker) {
+ returnValueLocal ??= addLocal(returnType);
+ b.local_set(returnValueLocal!);
+ }
+ b.br(finalizers.last.label);
} else {
- b.return_();
+ _returnFromFunction();
}
}
@@ -2022,3 +2073,10 @@
return wrap(node.operand, expectedType);
}
}
+
+class TryBlockFinalizer {
+ final w.Label label;
+ bool mustHandleReturn = false;
+
+ TryBlockFinalizer(this.label);
+}
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index 36a4b0d..1630176 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -352,9 +352,9 @@
/// [stackTraceInfo.nonNullableType] to hold a stack trace. This single
/// exception tag is used to throw and catch all Dart exceptions.
w.Tag createExceptionTag() {
- w.FunctionType functionType = m.addFunctionType(
+ w.FunctionType tagType = functionType(
[topInfo.nonNullableType, stackTraceInfo.nonNullableType], const []);
- w.Tag tag = m.addTag(functionType);
+ w.Tag tag = m.addTag(tagType);
return tag;
}
diff --git a/pkg/test_runner/tool/orphan_files.dart b/pkg/test_runner/tool/orphan_files.dart
index 968458b..4924123 100644
--- a/pkg/test_runner/tool/orphan_files.dart
+++ b/pkg/test_runner/tool/orphan_files.dart
@@ -15,12 +15,9 @@
import 'package:analyzer/dart/analysis/context_locator.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
-
import 'package:test_runner/src/path.dart';
-AnalysisContext _analysisContext;
-
-void main(List<String> arguments) {
+Future<void> main(List<String> arguments) async {
_initAnalysisContext();
var suites = Directory('tests').listSync();
@@ -29,21 +26,14 @@
for (var entry in suites) {
// Skip the co19 tests since they don't use '_test.dart'.
if (entry is Directory && !entry.path.contains('co19')) {
- _checkTestDirectory(entry);
+ await _checkTestDirectory(entry);
}
}
}
-void _initAnalysisContext() {
- var roots = ContextLocator().locateRoots(includedPaths: ['test']);
- if (roots.length != 1) {
- throw StateError('Expected to find exactly one context root, got $roots');
- }
+AnalysisContext _analysisContext;
- _analysisContext = ContextBuilder().createContext(contextRoot: roots[0]);
-}
-
-void _checkTestDirectory(Directory directory) {
+Future<void> _checkTestDirectory(Directory directory) async {
print('-- ${directory.path} --');
var paths = directory
.listSync(recursive: true)
@@ -56,7 +46,7 @@
print('Finding referenced files...');
var importedPaths = <String>{};
for (var path in paths) {
- _parseReferences(importedPaths, path);
+ await _parseReferences(importedPaths, path);
}
// Find the ".dart" files that don't end in "_test.dart" but also aren't used
@@ -72,9 +62,20 @@
if (!hasOrphan) print('No orphans :)');
}
-void _parseReferences(Set<String> importedPaths, String filePath) {
+void _initAnalysisContext() {
+ var roots = ContextLocator().locateRoots(includedPaths: ['test']);
+ if (roots.length != 1) {
+ throw StateError('Expected to find exactly one context root, got $roots');
+ }
+
+ _analysisContext = ContextBuilder().createContext(contextRoot: roots[0]);
+}
+
+Future<void> _parseReferences(
+ Set<String> importedPaths, String filePath) async {
var absolute = Path(filePath).absolute.toNativePath();
- var parseResult = _analysisContext.currentSession.getParsedUnit(absolute);
+ var analysisSession = _analysisContext.currentSession;
+ var parseResult = await analysisSession.getParsedUnit2(absolute);
var unit = (parseResult as ParsedUnitResult).unit;
void add(String importPath) {
diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc
index 0c22675..498df50 100644
--- a/runtime/bin/platform_macos.cc
+++ b/runtime/bin/platform_macos.cc
@@ -11,16 +11,18 @@
#include <CoreFoundation/CoreFoundation.h>
#if !DART_HOST_OS_IOS
-#include <crt_externs.h> // NOLINT
+#include <crt_externs.h>
#endif // !DART_HOST_OS_IOS
-#include <errno.h> // NOLINT
+#include <dlfcn.h>
+#include <errno.h>
#include <mach-o/dyld.h>
-#include <signal.h> // NOLINT
-#include <sys/resource.h> // NOLINT
-#include <sys/sysctl.h> // NOLINT
-#include <sys/types.h> // NOLINT
-#include <sys/utsname.h> // NOLINT
-#include <unistd.h> // NOLINT
+#include <pthread.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
#include <string>
@@ -251,7 +253,98 @@
return path_size;
}
-void Platform::SetProcessName(const char* name) {}
+void Platform::SetProcessName(const char* name) {
+ pthread_setname_np(name);
+
+#if !defined(DART_HOST_OS_IOS)
+ // Attempt to set the name displayed in ActivityMonitor.
+ // https://codereview.chromium.org/659007
+
+ class ScopedDLHandle : public ValueObject {
+ public:
+ explicit ScopedDLHandle(void* handle) : handle_(handle) {}
+ ~ScopedDLHandle() {
+ if (handle_ != NULL) dlclose(handle_);
+ }
+ void* get() { return handle_; }
+
+ private:
+ void* handle_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedDLHandle);
+ };
+
+ class ScopedCFStringRef : public ValueObject {
+ public:
+ explicit ScopedCFStringRef(const char* s)
+ : ref_(CFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)) {}
+ ~ScopedCFStringRef() {
+ if (ref_ != NULL) CFRelease(ref_);
+ }
+ CFStringRef get() { return ref_; }
+
+ private:
+ CFStringRef ref_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedCFStringRef);
+ };
+
+ ScopedDLHandle application_services_handle(
+ dlopen("/System/Library/Frameworks/ApplicationServices.framework/"
+ "Versions/A/ApplicationServices",
+ RTLD_LAZY | RTLD_LOCAL));
+ if (application_services_handle.get() == NULL) return;
+
+ ScopedCFStringRef launch_services_bundle_name("com.apple.LaunchServices");
+ CFBundleRef launch_services_bundle =
+ CFBundleGetBundleWithIdentifier(launch_services_bundle_name.get());
+ if (launch_services_bundle == NULL) return;
+
+#define GET_FUNC(name, cstr) \
+ ScopedCFStringRef name##_id(cstr); \
+ *reinterpret_cast<void**>(&name) = CFBundleGetFunctionPointerForName( \
+ launch_services_bundle, name##_id.get()); \
+ if (name == NULL) return;
+
+#define GET_DATA(name, cstr) \
+ ScopedCFStringRef name##_id(cstr); \
+ *reinterpret_cast<void**>(&name) = \
+ CFBundleGetDataPointerForName(launch_services_bundle, name##_id.get()); \
+ if (name == NULL) return;
+
+ CFTypeRef (*_LSGetCurrentApplicationASN)(void);
+ GET_FUNC(_LSGetCurrentApplicationASN, "_LSGetCurrentApplicationASN");
+
+ OSStatus (*_LSSetApplicationInformationItem)(int, CFTypeRef, CFStringRef,
+ CFStringRef, CFDictionaryRef*);
+ GET_FUNC(_LSSetApplicationInformationItem,
+ "_LSSetApplicationInformationItem");
+
+ CFDictionaryRef (*_LSApplicationCheckIn)(int, CFDictionaryRef);
+ GET_FUNC(_LSApplicationCheckIn, "_LSApplicationCheckIn");
+
+ void (*_LSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
+ void*);
+ GET_FUNC(_LSSetApplicationLaunchServicesServerConnectionStatus,
+ "_LSSetApplicationLaunchServicesServerConnectionStatus");
+
+ CFStringRef* _kLSDisplayNameKey;
+ GET_DATA(_kLSDisplayNameKey, "_kLSDisplayNameKey");
+ if (*_kLSDisplayNameKey == NULL) return;
+
+ _LSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
+
+ _LSApplicationCheckIn(-2, CFBundleGetInfoDictionary(CFBundleGetMainBundle()));
+
+ CFTypeRef asn;
+ asn = _LSGetCurrentApplicationASN();
+ if (asn == NULL) return;
+
+ ScopedCFStringRef cf_name(name);
+ _LSSetApplicationInformationItem(-2, asn, *_kLSDisplayNameKey, cf_name.get(),
+ NULL);
+#undef GET_DATA
+#undef GET_FUNC
+#endif // !defined(DART_HOST_OS_IOS)
+}
void Platform::Exit(int exit_code) {
Console::RestoreConfig();
diff --git a/runtime/vm/compiler/asm_intrinsifier_riscv.cc b/runtime/vm/compiler/asm_intrinsifier_riscv.cc
index db03989..c96447f 100644
--- a/runtime/vm/compiler/asm_intrinsifier_riscv.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_riscv.cc
@@ -537,7 +537,60 @@
intptr_t other_cid,
Label* return_true,
Label* return_false) {
- UNIMPLEMENTED();
+ __ SmiUntag(T0);
+ __ LoadCompressedSmi(
+ T1, FieldAddress(A0, target::String::length_offset())); // this.length
+ __ SmiUntag(T1);
+ __ LoadCompressedSmi(
+ T2, FieldAddress(A1, target::String::length_offset())); // other.length
+ __ SmiUntag(T2);
+
+ // if (other.length == 0) return true;
+ __ beqz(T2, return_true);
+
+ // if (start < 0) return false;
+ __ bltz(T0, return_false);
+
+ // if (start + other.length > this.length) return false;
+ __ add(T3, T0, T2);
+ __ bgt(T3, T1, return_false);
+
+ if (receiver_cid == kOneByteStringCid) {
+ __ add(A0, A0, T0);
+ } else {
+ ASSERT(receiver_cid == kTwoByteStringCid);
+ __ add(A0, A0, T0);
+ __ add(A0, A0, T0);
+ }
+
+ // i = 0
+ __ li(T3, 0);
+
+ // do
+ Label loop;
+ __ Bind(&loop);
+
+ // this.codeUnitAt(i + start)
+ if (receiver_cid == kOneByteStringCid) {
+ __ lbu(TMP, FieldAddress(A0, target::OneByteString::data_offset()));
+ } else {
+ __ lhu(TMP, FieldAddress(A0, target::TwoByteString::data_offset()));
+ }
+ // other.codeUnitAt(i)
+ if (other_cid == kOneByteStringCid) {
+ __ lbu(TMP2, FieldAddress(A1, target::OneByteString::data_offset()));
+ } else {
+ __ lhu(TMP2, FieldAddress(A1, target::TwoByteString::data_offset()));
+ }
+ __ bne(TMP, TMP2, return_false);
+
+ // i++, while (i < len)
+ __ addi(T3, T3, 1);
+ __ addi(A0, A0, receiver_cid == kOneByteStringCid ? 1 : 2);
+ __ addi(A1, A1, other_cid == kOneByteStringCid ? 1 : 2);
+ __ blt(T3, T2, &loop);
+
+ __ j(return_true);
}
// bool _substringMatches(int start, String other)
@@ -545,26 +598,277 @@
// OneByteString other.
void AsmIntrinsifier::StringBaseSubstringMatches(Assembler* assembler,
Label* normal_ir_body) {
- // TODO(riscv)
+ Label return_true, return_false, try_two_byte;
+ __ lx(A0, Address(SP, 2 * target::kWordSize)); // this
+ __ lx(T0, Address(SP, 1 * target::kWordSize)); // start
+ __ lx(A1, Address(SP, 0 * target::kWordSize)); // other
+
+ __ BranchIfNotSmi(T0, normal_ir_body);
+
+ __ CompareClassId(A1, kOneByteStringCid, TMP);
+ __ BranchIf(NE, normal_ir_body);
+
+ __ CompareClassId(A0, kOneByteStringCid, TMP);
+ __ BranchIf(NE, normal_ir_body);
+
+ GenerateSubstringMatchesSpecialization(assembler, kOneByteStringCid,
+ kOneByteStringCid, &return_true,
+ &return_false);
+
+ __ Bind(&try_two_byte);
+ __ CompareClassId(A0, kTwoByteStringCid, TMP);
+ __ BranchIf(NE, normal_ir_body);
+
+ GenerateSubstringMatchesSpecialization(assembler, kTwoByteStringCid,
+ kOneByteStringCid, &return_true,
+ &return_false);
+
+ __ Bind(&return_true);
+ __ LoadObject(A0, CastHandle<Object>(TrueObject()));
+ __ ret();
+
+ __ Bind(&return_false);
+ __ LoadObject(A0, CastHandle<Object>(FalseObject()));
+ __ ret();
+
__ Bind(normal_ir_body);
}
void AsmIntrinsifier::StringBaseCharAt(Assembler* assembler,
Label* normal_ir_body) {
- // TODO(riscv)
+ Label try_two_byte_string;
+
+ __ lx(A1, Address(SP, 0 * target::kWordSize)); // Index.
+ __ lx(A0, Address(SP, 1 * target::kWordSize)); // String.
+ __ BranchIfNotSmi(A1, normal_ir_body); // Index is not a Smi.
+ // Range check.
+ __ lx(TMP, FieldAddress(A0, target::String::length_offset()));
+ __ bgeu(A1, TMP, normal_ir_body); // Runtime throws exception.
+
+ __ CompareClassId(A0, kOneByteStringCid, TMP);
+ __ BranchIf(NE, &try_two_byte_string);
+ __ SmiUntag(A1);
+ __ add(A0, A0, A1);
+ __ lbu(A1, FieldAddress(A0, target::OneByteString::data_offset()));
+ __ CompareImmediate(A1, target::Symbols::kNumberOfOneCharCodeSymbols);
+ __ BranchIf(GE, normal_ir_body);
+ __ lx(A0, Address(THR, target::Thread::predefined_symbols_address_offset()));
+ __ slli(A1, A1, target::kWordSizeLog2);
+ __ add(A0, A0, A1);
+ __ lx(A0, Address(A0, target::Symbols::kNullCharCodeSymbolOffset *
+ target::kWordSize));
+ __ ret();
+
+ __ Bind(&try_two_byte_string);
+ __ CompareClassId(A0, kTwoByteStringCid, TMP);
+ __ BranchIf(NE, normal_ir_body);
+ ASSERT(kSmiTagShift == 1);
+ __ add(A0, A0, A1);
+ __ lhu(A1, FieldAddress(A0, target::TwoByteString::data_offset()));
+ __ CompareImmediate(A1, target::Symbols::kNumberOfOneCharCodeSymbols);
+ __ BranchIf(GE, normal_ir_body);
+ __ lx(A0, Address(THR, target::Thread::predefined_symbols_address_offset()));
+ __ slli(A1, A1, target::kWordSizeLog2);
+ __ add(A0, A0, A1);
+ __ lx(A0, Address(A0, target::Symbols::kNullCharCodeSymbolOffset *
+ target::kWordSize));
+ __ ret();
+
__ Bind(normal_ir_body);
}
void AsmIntrinsifier::StringBaseIsEmpty(Assembler* assembler,
Label* normal_ir_body) {
- // TODO(riscv)
- __ Bind(normal_ir_body);
+ Label is_true;
+ __ lx(A0, Address(SP, 0 * target::kWordSize));
+ __ lx(A0, FieldAddress(A0, target::String::length_offset()));
+ __ beqz(A0, &is_true, Assembler::kNearJump);
+ __ LoadObject(A0, CastHandle<Object>(FalseObject()));
+ __ ret();
+ __ Bind(&is_true);
+ __ LoadObject(A0, CastHandle<Object>(TrueObject()));
+ __ ret();
}
void AsmIntrinsifier::OneByteString_getHashCode(Assembler* assembler,
Label* normal_ir_body) {
- // TODO(riscv)
- __ Bind(normal_ir_body);
+ Label compute_hash;
+ __ lx(A1, Address(SP, 0 * target::kWordSize)); // OneByteString object.
+#if XLEN == 32
+ __ lw(A0, FieldAddress(A1, target::String::hash_offset()));
+#else
+ __ lwu(A0, FieldAddress(A1, target::String::hash_offset()));
+ __ SmiTag(A0);
+#endif
+ __ beqz(A0, &compute_hash);
+ __ ret(); // Return if already computed.
+
+ __ Bind(&compute_hash);
+ __ lx(T0, FieldAddress(A1, target::String::length_offset()));
+ __ SmiUntag(T0);
+
+ Label set_to_one, done;
+ // If the string is empty, set the hash to 1, and return.
+ __ beqz(T0, &set_to_one);
+
+ __ mv(T1, ZR);
+ __ addi(T2, A1, target::OneByteString::data_offset() - kHeapObjectTag);
+ // A1: Instance of OneByteString.
+ // T0: String length, untagged integer.
+ // T1: Loop counter, untagged integer.
+ // T2: String data.
+ // A0: Hash code, untagged integer.
+
+ Label loop;
+ // Add to hash code: (hash_ is uint32)
+ // hash_ += ch;
+ // hash_ += hash_ << 10;
+ // hash_ ^= hash_ >> 6;
+ // Get one characters (ch).
+ __ Bind(&loop);
+ __ lbu(T3, Address(T2, 0));
+ __ addi(T2, T2, 1);
+ // T3: ch.
+ __ addi(T1, T1, 1);
+#if XLEN == 32
+ __ add(A0, A0, T3);
+ __ slli(TMP, A0, 10);
+ __ add(A0, A0, TMP);
+ __ srli(TMP, A0, 6);
+#else
+ __ addw(A0, A0, T3);
+ __ slliw(TMP, A0, 10);
+ __ addw(A0, A0, TMP);
+ __ srliw(TMP, A0, 6);
+#endif
+ __ xor_(A0, A0, TMP);
+ __ bne(T1, T0, &loop);
+
+ // Finalize.
+ // hash_ += hash_ << 3;
+ // hash_ ^= hash_ >> 11;
+ // hash_ += hash_ << 15;
+#if XLEN == 32
+ __ slli(TMP, A0, 3);
+ __ add(A0, A0, TMP);
+ __ srli(TMP, A0, 11);
+ __ xor_(A0, A0, TMP);
+ __ slli(TMP, A0, 15);
+ __ add(A0, A0, TMP);
+#else
+ __ slliw(TMP, A0, 3);
+ __ addw(A0, A0, TMP);
+ __ srliw(TMP, A0, 11);
+ __ xor_(A0, A0, TMP);
+ __ slliw(TMP, A0, 15);
+ __ addw(A0, A0, TMP);
+#endif
+ // hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1);
+ __ AndImmediate(A0, A0,
+ (static_cast<intptr_t>(1) << target::String::kHashBits) - 1);
+ // return hash_ == 0 ? 1 : hash_;
+ __ bnez(A0, &done, Assembler::kNearJump);
+ __ Bind(&set_to_one);
+ __ li(A0, 1);
+ __ Bind(&done);
+
+#if XLEN == 32
+ __ SmiTag(A0);
+ __ sx(A0, FieldAddress(A1, target::String::hash_offset()));
+ __ ret();
+#else
+ // A1: Untagged address of header word (lr/sc do not support offsets).
+ __ subi(A1, A1, kHeapObjectTag);
+ __ slli(A0, A0, target::UntaggedObject::kHashTagPos);
+ Label retry;
+ __ Bind(&retry);
+ __ lr(T0, Address(A1, 0));
+ __ or_(T0, T0, A0);
+ __ sc(TMP, T0, Address(A1, 0));
+ __ bnez(TMP, &retry);
+
+ __ srli(A0, A0, target::UntaggedObject::kHashTagPos);
+ __ SmiTag(A0);
+ __ ret();
+#endif
+}
+
+// Allocates a _OneByteString or _TwoByteString. The content is not initialized.
+// 'length-reg' (A1) contains the desired length as a _Smi or _Mint.
+// Returns new string as tagged pointer in A0.
+static void TryAllocateString(Assembler* assembler,
+ classid_t cid,
+ Label* ok,
+ Label* failure) {
+ ASSERT(cid == kOneByteStringCid || cid == kTwoByteStringCid);
+ const Register length_reg = A1;
+ // _Mint length: call to runtime to produce error.
+ __ BranchIfNotSmi(length_reg, failure);
+ // negative length: call to runtime to produce error.
+ __ bltz(length_reg, failure);
+
+ NOT_IN_PRODUCT(__ MaybeTraceAllocation(cid, TMP, failure));
+ __ mv(T0, length_reg); // Save the length register.
+ if (cid == kOneByteStringCid) {
+ // Untag length.
+ __ SmiUntag(length_reg);
+ } else {
+ // Untag length and multiply by element size -> no-op.
+ ASSERT(kSmiTagSize == 1);
+ }
+ const intptr_t fixed_size_plus_alignment_padding =
+ target::String::InstanceSize() +
+ target::ObjectAlignment::kObjectAlignment - 1;
+ __ addi(length_reg, length_reg, fixed_size_plus_alignment_padding);
+ __ andi(length_reg, length_reg,
+ ~(target::ObjectAlignment::kObjectAlignment - 1));
+
+ __ lx(A0, Address(THR, target::Thread::top_offset()));
+
+ // length_reg: allocation size.
+ __ add(T1, A0, length_reg);
+ __ bltu(T1, A0, failure); // Fail on unsigned overflow.
+
+ // Check if the allocation fits into the remaining space.
+ // A0: potential new object start.
+ // T1: potential next object start.
+ // A1: allocation size.
+ __ lx(TMP, Address(THR, target::Thread::end_offset()));
+ __ bgtu(T1, TMP, failure);
+
+ // Successfully allocated the object(s), now update top to point to
+ // next object start and initialize the object.
+ __ sx(T1, Address(THR, target::Thread::top_offset()));
+ __ AddImmediate(A0, kHeapObjectTag);
+
+ // Initialize the tags.
+ // A0: new object start as a tagged pointer.
+ // T1: new object end address.
+ // A1: allocation size.
+ {
+ const intptr_t shift = target::UntaggedObject::kTagBitsSizeTagPos -
+ target::ObjectAlignment::kObjectAlignmentLog2;
+
+ __ CompareImmediate(A1, target::UntaggedObject::kSizeTagMaxSizeTag);
+ Label dont_zero_tag;
+ __ BranchIf(UNSIGNED_LESS_EQUAL, &dont_zero_tag);
+ __ li(A1, 0);
+ __ Bind(&dont_zero_tag);
+ __ slli(A1, A1, shift);
+
+ // Get the class index and insert it into the tags.
+ // A1: size and bit tags.
+ // This also clears the hash, which is in the high word of the tags.
+ const uword tags =
+ target::MakeTagWordForNewSpaceObject(cid, /*instance_size=*/0);
+ __ OrImmediate(A1, A1, tags);
+ __ sx(A1, FieldAddress(A0, target::Object::tags_offset())); // Store tags.
+ }
+
+ // Set the length field using the saved length (T0).
+ __ StoreIntoObjectNoBarrier(
+ A0, FieldAddress(A0, target::String::length_offset()), T0);
+ __ j(ok);
}
// Arg0: OneByteString (receiver).
@@ -573,7 +877,53 @@
// The indexes must be valid.
void AsmIntrinsifier::OneByteString_substringUnchecked(Assembler* assembler,
Label* normal_ir_body) {
- // TODO(riscv)
+ const intptr_t kStringOffset = 2 * target::kWordSize;
+ const intptr_t kStartIndexOffset = 1 * target::kWordSize;
+ const intptr_t kEndIndexOffset = 0 * target::kWordSize;
+ Label ok;
+
+ __ lx(T0, Address(SP, kEndIndexOffset));
+ __ lx(TMP, Address(SP, kStartIndexOffset));
+ __ or_(T1, T0, TMP);
+ __ BranchIfNotSmi(T1, normal_ir_body); // 'start', 'end' not Smi.
+
+ __ sub(A1, T0, TMP);
+ TryAllocateString(assembler, kOneByteStringCid, &ok, normal_ir_body);
+ __ Bind(&ok);
+ // A0: new string as tagged pointer.
+ // Copy string.
+ __ lx(T1, Address(SP, kStringOffset));
+ __ lx(T2, Address(SP, kStartIndexOffset));
+ __ SmiUntag(T2);
+ // Calculate start address.
+ __ add(T1, T1, T2);
+
+ // T1: Start address to copy from.
+ // T2: Untagged start index.
+ __ lx(T0, Address(SP, kEndIndexOffset));
+ __ SmiUntag(T0);
+ __ sub(T0, T0, T2);
+
+ // T1: Start address to copy from (untagged).
+ // T0: Untagged number of bytes to copy.
+ // A0: Tagged result string.
+ // T3: Pointer into T1.
+ // T4: Pointer into A0.
+ // T2: Scratch register.
+ Label loop, done;
+ __ blez(T0, &done, Assembler::kNearJump);
+ __ mv(T3, T1);
+ __ mv(T4, A0);
+ __ Bind(&loop);
+ __ subi(T0, T0, 1);
+ __ lbu(T2, FieldAddress(T3, target::OneByteString::data_offset()));
+ __ addi(T3, T3, 1);
+ __ sb(T2, FieldAddress(T4, target::OneByteString::data_offset()));
+ __ addi(T4, T4, 1);
+ __ bgtz(T0, &loop);
+
+ __ Bind(&done);
+ __ ret();
__ Bind(normal_ir_body);
}
@@ -603,13 +953,27 @@
void AsmIntrinsifier::AllocateOneByteString(Assembler* assembler,
Label* normal_ir_body) {
- // TODO(riscv)
+ Label ok;
+
+ __ lx(A1, Address(SP, 0 * target::kWordSize)); // Length.
+ TryAllocateString(assembler, kOneByteStringCid, &ok, normal_ir_body);
+
+ __ Bind(&ok);
+ __ ret();
+
__ Bind(normal_ir_body);
}
void AsmIntrinsifier::AllocateTwoByteString(Assembler* assembler,
Label* normal_ir_body) {
- // TODO(riscv)
+ Label ok;
+
+ __ lx(A1, Address(SP, 0 * target::kWordSize)); // Length.
+ TryAllocateString(assembler, kTwoByteStringCid, &ok, normal_ir_body);
+
+ __ Bind(&ok);
+ __ ret();
+
__ Bind(normal_ir_body);
}
@@ -617,7 +981,52 @@
static void StringEquality(Assembler* assembler,
Label* normal_ir_body,
intptr_t string_cid) {
- // TODO(riscv)
+ Label is_true, is_false, loop;
+ __ lx(A0, Address(SP, 1 * target::kWordSize)); // This.
+ __ lx(A1, Address(SP, 0 * target::kWordSize)); // Other.
+
+ // Are identical?
+ __ beq(A0, A1, &is_true, Assembler::kNearJump);
+
+ // Is other OneByteString?
+ __ BranchIfSmi(A1, normal_ir_body, Assembler::kNearJump);
+ __ CompareClassId(A1, string_cid, TMP);
+ __ BranchIf(NE, normal_ir_body, Assembler::kNearJump);
+
+ // Have same length?
+ __ lx(T2, FieldAddress(A0, target::String::length_offset()));
+ __ lx(T3, FieldAddress(A1, target::String::length_offset()));
+ __ bne(T2, T3, &is_false, Assembler::kNearJump);
+
+ // Check contents, no fall-through possible.
+ __ SmiUntag(T2);
+ __ Bind(&loop);
+ __ AddImmediate(T2, -1);
+ __ bltz(T2, &is_true, Assembler::kNearJump);
+ if (string_cid == kOneByteStringCid) {
+ __ lbu(TMP, FieldAddress(A0, target::OneByteString::data_offset()));
+ __ lbu(TMP2, FieldAddress(A1, target::OneByteString::data_offset()));
+ __ addi(A0, A0, 1);
+ __ addi(A1, A1, 1);
+ } else if (string_cid == kTwoByteStringCid) {
+ __ lhu(TMP, FieldAddress(A0, target::TwoByteString::data_offset()));
+ __ lhu(TMP2, FieldAddress(A1, target::TwoByteString::data_offset()));
+ __ addi(A0, A0, 2);
+ __ addi(A1, A1, 2);
+ } else {
+ UNIMPLEMENTED();
+ }
+ __ bne(TMP, TMP2, &is_false, Assembler::kNearJump);
+ __ j(&loop);
+
+ __ Bind(&is_true);
+ __ LoadObject(A0, CastHandle<Object>(TrueObject()));
+ __ ret();
+
+ __ Bind(&is_false);
+ __ LoadObject(A0, CastHandle<Object>(FalseObject()));
+ __ ret();
+
__ Bind(normal_ir_body);
}
@@ -645,7 +1054,7 @@
// S4: Arguments descriptor. (Will be preserved.)
// S5: Unknown. (Must be GC safe on tail call.)
- // Load the specialized function pointer into R0. Leverage the fact the
+ // Load the specialized function pointer into T0. Leverage the fact the
// string CIDs as well as stored function pointers are in sequence.
__ lx(T2, Address(SP, kRegExpParamOffset));
__ lx(T1, Address(SP, kStringParamOffset));
@@ -657,7 +1066,7 @@
sticky)));
// Registers are now set up for the lazy compile stub. It expects the function
- // in R0, the argument descriptor in R4, and IC-Data in R5.
+ // in T0, the argument descriptor in S4, and IC-Data in S5.
__ li(S5, 0);
// Tail-call the function.
diff --git a/tools/VERSION b/tools/VERSION
index 33ae06c..76b2b57 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 17
PATCH 0
-PRERELEASE 184
+PRERELEASE 185
PRERELEASE_PATCH 0
\ No newline at end of file