Add parseString() to replace the deprecated parseCompilationUnit().
Change-Id: Ib272f6a281b09a02ba037049e76bf08dd78dbbab
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105540
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/dart/analysis/results.dart b/pkg/analyzer/lib/dart/analysis/results.dart
index 7f82c94..db9f9f8 100644
--- a/pkg/analyzer/lib/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/dart/analysis/results.dart
@@ -105,6 +105,27 @@
CompilationUnit get unit;
}
+/// The result of parsing of a single file. The errors returned include only
+/// those discovered during scanning and parsing.
+///
+/// Similar to [ParsedUnitResult], but does not allow access to an analysis
+/// session.
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class ParseStringResult {
+ /// The content of the file that was scanned and parsed.
+ String get content;
+
+ /// The analysis errors that were computed during analysis.
+ List<AnalysisError> get errors;
+
+ /// Information about lines in the content.
+ LineInfo get lineInfo;
+
+ /// The parsed, unresolved compilation unit for the [content].
+ CompilationUnit get unit;
+}
+
/// The result of building resolved AST(s) for the whole library.
///
/// Clients may not extend, implement or mix-in this class.
diff --git a/pkg/analyzer/lib/dart/analysis/utilities.dart b/pkg/analyzer/lib/dart/analysis/utilities.dart
index 75ef87b..cd3210e 100644
--- a/pkg/analyzer/lib/dart/analysis/utilities.dart
+++ b/pkg/analyzer/lib/dart/analysis/utilities.dart
@@ -6,9 +6,17 @@
import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/source/line_info.dart';
+import 'package:analyzer/src/dart/analysis/results.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/string_source.dart';
import 'package:meta/meta.dart';
/// Return the result of parsing the file at the given [path].
@@ -25,6 +33,36 @@
return context.currentSession.getParsedUnit(path);
}
+/// Returns the result of parsing the given [content] as a compilation unit.
+///
+/// If a [featureSet] is provided, it will be the default set of features that
+/// will be assumed by the parser.
+///
+/// If [throwIfDiagnostics] is `true` (the default), then if any diagnostics are
+/// produced because of syntactic errors in the [content] an `ArgumentError`
+/// will be thrown. If the parameter is `false`, then the caller can check the
+/// result to see whether there are any `errors`.
+ParseStringResult parseString(
+ {@required String content,
+ FeatureSet featureSet,
+ bool throwIfDiagnostics: true}) {
+ featureSet ??= FeatureSet.fromEnableFlags([]);
+ var source = StringSource(content, null);
+ var reader = CharSequenceReader(content);
+ var errorCollector = RecordingErrorListener();
+ var scanner = Scanner(source, reader, errorCollector)
+ ..configureFeatures(featureSet);
+ var token = scanner.tokenize();
+ var parser = Parser(source, errorCollector, featureSet: scanner.featureSet);
+ var unit = parser.parseCompilationUnit(token);
+ ParseStringResult result = ParseStringResultImpl(
+ content, LineInfo(scanner.lineStarts), unit, errorCollector.errors);
+ if (throwIfDiagnostics && result.errors.isNotEmpty) {
+ throw new ArgumentError('Content produced diagnostics when parsed');
+ }
+ return result;
+}
+
/// Return the result of resolving the file at the given [path].
///
/// If a [resourceProvider] is given, it will be used to access the file system.
diff --git a/pkg/analyzer/lib/src/dart/analysis/results.dart b/pkg/analyzer/lib/src/dart/analysis/results.dart
index b38336b..adfe2ea 100644
--- a/pkg/analyzer/lib/src/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/results.dart
@@ -163,6 +163,22 @@
ResultState get state => ResultState.VALID;
}
+class ParseStringResultImpl implements ParseStringResult {
+ @override
+ final String content;
+
+ @override
+ final List<AnalysisError> errors;
+
+ @override
+ final LineInfo lineInfo;
+
+ @override
+ final CompilationUnit unit;
+
+ ParseStringResultImpl(this.content, this.lineInfo, this.unit, this.errors);
+}
+
class ResolvedLibraryResultImpl extends AnalysisResultImpl
implements ResolvedLibraryResult {
@override
diff --git a/pkg/analyzer/test/dart/analysis/test_all.dart b/pkg/analyzer/test/dart/analysis/test_all.dart
index fe1f2ee..44f950b 100644
--- a/pkg/analyzer/test/dart/analysis/test_all.dart
+++ b/pkg/analyzer/test/dart/analysis/test_all.dart
@@ -5,9 +5,11 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'declared_variables_test.dart' as declared_variables;
+import 'utilities_test.dart' as utilities;
main() {
defineReflectiveSuite(() {
declared_variables.main();
+ utilities.main();
}, name: 'analysis');
}
diff --git a/pkg/analyzer/test/dart/analysis/utilities_test.dart b/pkg/analyzer/test/dart/analysis/utilities_test.dart
new file mode 100644
index 0000000..8240940
--- /dev/null
+++ b/pkg/analyzer/test/dart/analysis/utilities_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/analysis/utilities.dart';
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(UtilitiesTest);
+ });
+}
+
+@reflectiveTest
+class UtilitiesTest with ResourceProviderMixin {
+ test_parseString_errors_noThrow() {
+ String content = '''
+void main() => print('Hello, world!')
+''';
+ ParseStringResult result =
+ parseString(content: content, throwIfDiagnostics: false);
+ expect(result.content, content);
+ expect(result.errors, hasLength(1));
+ expect(result.lineInfo, isNotNull);
+ expect(result.unit.toString(),
+ equals("void main() => print('Hello, world!');"));
+ }
+
+ test_parseString_errors_throw() {
+ String content = '''
+void main() => print('Hello, world!')
+''';
+ expect(() => parseString(content: content),
+ throwsA(const TypeMatcher<ArgumentError>()));
+ }
+
+ test_parseString_featureSet_nnbd_off() {
+ String content = '''
+int? f() => 1;
+''';
+ var featureSet = FeatureSet.forTesting(sdkVersion: '2.3.0');
+ expect(featureSet.isEnabled(Feature.non_nullable), isFalse);
+ ParseStringResult result = parseString(
+ content: content, throwIfDiagnostics: false, featureSet: featureSet);
+ expect(result.content, content);
+ expect(result.errors, hasLength(1));
+ expect(result.lineInfo, isNotNull);
+ expect(result.unit.toString(), equals('int? f() => 1;'));
+ }
+
+ test_parseString_featureSet_nnbd_on() {
+ String content = '''
+int? f() => 1;
+''';
+ var featureSet =
+ FeatureSet.forTesting(additionalFeatures: [Feature.non_nullable]);
+ ParseStringResult result = parseString(
+ content: content, throwIfDiagnostics: false, featureSet: featureSet);
+ expect(result.content, content);
+ expect(result.errors, isEmpty);
+ expect(result.lineInfo, isNotNull);
+ expect(result.unit.toString(), equals('int? f() => 1;'));
+ }
+
+ test_parseString_noErrors() {
+ String content = '''
+void main() => print('Hello, world!');
+''';
+ ParseStringResult result = parseString(content: content);
+ expect(result.content, content);
+ expect(result.errors, isEmpty);
+ expect(result.lineInfo, isNotNull);
+ expect(result.unit.toString(),
+ equals("void main() => print('Hello, world!');"));
+ }
+}