| // Copyright (c) 2018, 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/declared_variables.dart'; |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/ast/token.dart'; |
| import 'package:analyzer/error/listener.dart'; |
| import 'package:analyzer/file_system/memory_file_system.dart'; |
| import 'package:analyzer/src/dart/analysis/experiments.dart'; |
| import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart'; |
| import 'package:analyzer/src/dart/scanner/reader.dart'; |
| import 'package:analyzer/src/dart/scanner/scanner.dart'; |
| import 'package:analyzer/src/generated/engine.dart'; |
| import 'package:analyzer/src/generated/parser.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/generated/utilities_dart.dart'; |
| import 'package:analyzer/src/summary/format.dart'; |
| import 'package:analyzer/src/summary/idl.dart'; |
| import 'package:analyzer/src/summary/link.dart'; |
| import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
| import 'package:analyzer/src/summary/prelink.dart'; |
| import 'package:analyzer/src/summary/summarize_ast.dart'; |
| import 'package:analyzer/src/summary/summarize_elements.dart'; |
| import 'package:analyzer/src/test_utilities/mock_sdk.dart'; |
| import 'package:path/path.dart' show posix; |
| import 'package:test/test.dart'; |
| |
| import 'resynthesize_common.dart'; |
| |
| /// Convert the given Posix style file [path] to the corresponding absolute URI. |
| String absUri(String path) { |
| String absolutePath = posix.absolute(path); |
| return posix.toUri(absolutePath).toString(); |
| } |
| |
| CompilationUnit parseText( |
| String text, { |
| ExperimentStatus experimentStatus, |
| }) { |
| experimentStatus ??= ExperimentStatus(); |
| CharSequenceReader reader = new CharSequenceReader(text); |
| Scanner scanner = |
| new Scanner(null, reader, AnalysisErrorListener.NULL_LISTENER) |
| ..configureFeatures(experimentStatus); |
| Token token = scanner.tokenize(); |
| Parser parser = new Parser( |
| NonExistingSource.unknown, AnalysisErrorListener.NULL_LISTENER, |
| featureSet: experimentStatus); |
| CompilationUnit unit = parser.parseCompilationUnit(token); |
| unit.lineInfo = new LineInfo(scanner.lineStarts); |
| return unit; |
| } |
| |
| /// Verify invariants of the given [linkedLibrary]. |
| void _validateLinkedLibrary(LinkedLibrary linkedLibrary) { |
| for (LinkedUnit unit in linkedLibrary.units) { |
| for (LinkedReference reference in unit.references) { |
| switch (reference.kind) { |
| case ReferenceKind.classOrEnum: |
| case ReferenceKind.topLevelPropertyAccessor: |
| case ReferenceKind.topLevelFunction: |
| case ReferenceKind.typedef: |
| // This reference can have either a zero or a nonzero dependency, |
| // since it refers to top level element which might or might not be |
| // imported from another library. |
| break; |
| case ReferenceKind.prefix: |
| // Prefixes should have a dependency of 0, since they come from the |
| // current library. |
| expect(reference.dependency, 0, |
| reason: 'Nonzero dependency for prefix'); |
| break; |
| case ReferenceKind.unresolved: |
| // Unresolved references always have a dependency of 0. |
| expect(reference.dependency, 0, |
| reason: 'Nonzero dependency for undefined'); |
| break; |
| default: |
| // This reference should have a dependency of 0, since it refers to |
| // an element that is contained within some other element. |
| expect(reference.dependency, 0, |
| reason: 'Nonzero dependency for ${reference.kind}'); |
| } |
| } |
| } |
| } |
| |
| /// Abstract base class for tests of summary resynthesis. |
| /// |
| /// Test classes should not extend this class directly; they should extend a |
| /// class that implements this class with methods that drive summary generation. |
| /// The tests themselves can then be provided via mixin, allowing summaries to |
| /// be tested in a variety of ways. |
| abstract class ResynthesizeTestStrategy { |
| /// The set of [ExperimentStatus] enabled in this test. |
| ExperimentStatus experimentStatus; |
| |
| void set allowMissingFiles(bool value); |
| |
| set declaredVariables(DeclaredVariables declaredVariables); |
| |
| bool get isAstBasedSummary => false; |
| |
| MemoryResourceProvider get resourceProvider; |
| |
| void set testFile(String value); |
| |
| Source get testSource; |
| |
| void addLibrary(String uri); |
| |
| Source addLibrarySource(String filePath, String contents); |
| |
| Source addSource(String path, String contents); |
| |
| Source addTestSource(String code, [Uri uri]); |
| |
| void checkMinimalResynthesisWork(TestSummaryResynthesizer resynthesizer, |
| Uri expectedLibraryUri, List<Uri> expectedUnitUriList); |
| |
| TestSummaryResynthesizer encodeLibrary(Source source); |
| } |
| |
| /// Implementation of [SummaryBlackBoxTestStrategy] that drives summary |
| /// generation using the old two-phase API. |
| class ResynthesizeTestStrategyTwoPhase extends AbstractResynthesizeTest |
| implements ResynthesizeTestStrategy { |
| @override |
| ExperimentStatus experimentStatus = ExperimentStatus(); |
| |
| final Set<Source> serializedSources = new Set<Source>(); |
| |
| final Map<String, UnlinkedUnitBuilder> uriToUnit = |
| <String, UnlinkedUnitBuilder>{}; |
| |
| PackageBundleAssembler bundleAssembler = new PackageBundleAssembler(); |
| |
| @override |
| bool get isAstBasedSummary => false; |
| |
| TestSummaryResynthesizer encodeLibrary(Source source) { |
| _serializeLibrary(source); |
| |
| PackageBundle bundle = |
| new PackageBundle.fromBuffer(bundleAssembler.assemble().toBuffer()); |
| |
| Map<String, UnlinkedUnit> unlinkedSummaries = <String, UnlinkedUnit>{}; |
| for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) { |
| String uri = bundle.unlinkedUnitUris[i]; |
| unlinkedSummaries[uri] = bundle.unlinkedUnits[i]; |
| } |
| |
| LinkedLibrary getDependency(String absoluteUri) { |
| Map<String, LinkedLibrary> sdkLibraries = |
| SerializedMockSdk.instance.uriToLinkedLibrary; |
| LinkedLibrary linkedLibrary = sdkLibraries[absoluteUri]; |
| if (linkedLibrary == null && !allowMissingFiles) { |
| fail('Linker unexpectedly requested LinkedLibrary for "$absoluteUri".' |
| ' Libraries available: ${sdkLibraries.keys}'); |
| } |
| return linkedLibrary; |
| } |
| |
| UnlinkedUnit getUnit(String absoluteUri) { |
| UnlinkedUnit unit = uriToUnit[absoluteUri] ?? |
| SerializedMockSdk.instance.uriToUnlinkedUnit[absoluteUri]; |
| if (unit == null && !allowMissingFiles) { |
| fail('Linker unexpectedly requested unit for "$absoluteUri".'); |
| } |
| return unit; |
| } |
| |
| Set<String> nonSdkLibraryUris = serializedSources |
| .where((Source source) => !source.isInSystemLibrary) |
| .map((Source source) => source.uri.toString()) |
| .toSet(); |
| |
| var analysisOptions = AnalysisOptionsImpl() |
| ..enabledExperiments = experimentStatus.toStringList(); |
| |
| Map<String, LinkedLibrary> linkedSummaries = link(nonSdkLibraryUris, |
| getDependency, getUnit, declaredVariables, analysisOptions); |
| |
| var analysisContext = RestrictedAnalysisContext( |
| analysisOptions, |
| declaredVariables, |
| sourceFactory, |
| ); |
| |
| return new TestSummaryResynthesizer( |
| analysisContext, |
| new Map<String, UnlinkedUnit>() |
| ..addAll(SerializedMockSdk.instance.uriToUnlinkedUnit) |
| ..addAll(unlinkedSummaries), |
| new Map<String, LinkedLibrary>() |
| ..addAll(SerializedMockSdk.instance.uriToLinkedLibrary) |
| ..addAll(linkedSummaries), |
| allowMissingFiles); |
| } |
| |
| UnlinkedUnit _getUnlinkedUnit(Source source) { |
| if (source == null) { |
| return new UnlinkedUnitBuilder(); |
| } |
| |
| String uriStr = source.uri.toString(); |
| { |
| UnlinkedUnit unlinkedUnitInSdk = |
| SerializedMockSdk.instance.uriToUnlinkedUnit[uriStr]; |
| if (unlinkedUnitInSdk != null) { |
| return unlinkedUnitInSdk; |
| } |
| } |
| return uriToUnit.putIfAbsent(uriStr, () { |
| var file = getFile(source.fullName); |
| |
| String contents; |
| if (file.exists) { |
| contents = file.readAsStringSync(); |
| } else { |
| // Source does not exist. |
| if (!allowMissingFiles) { |
| fail('Unexpectedly tried to get unlinked summary for $source'); |
| } |
| contents = ''; |
| } |
| |
| CompilationUnit unit = |
| parseText(contents, experimentStatus: experimentStatus); |
| |
| UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit); |
| bundleAssembler.addUnlinkedUnit(source, unlinkedUnit); |
| return unlinkedUnit; |
| }); |
| } |
| |
| void _serializeLibrary(Source librarySource) { |
| if (librarySource == null || librarySource.isInSystemLibrary) { |
| return; |
| } |
| if (!serializedSources.add(librarySource)) { |
| return; |
| } |
| |
| UnlinkedUnit getPart(String absoluteUri) { |
| Source source = sourceFactory.forUri(absoluteUri); |
| return _getUnlinkedUnit(source); |
| } |
| |
| UnlinkedPublicNamespace getImport(String relativeUri) { |
| return getPart(relativeUri)?.publicNamespace; |
| } |
| |
| UnlinkedUnit definingUnit = _getUnlinkedUnit(librarySource); |
| if (definingUnit != null) { |
| LinkedLibraryBuilder linkedLibrary = prelink(librarySource.uri.toString(), |
| definingUnit, getPart, getImport, declaredVariables); |
| linkedLibrary.dependencies.skip(1).forEach((LinkedDependency d) { |
| Source source = sourceFactory.forUri(d.uri); |
| _serializeLibrary(source); |
| }); |
| } |
| } |
| } |
| |
| /// [SerializedMockSdk] is a singleton class representing the result of |
| /// serializing the mock SDK to summaries. It is computed once and then shared |
| /// among test invocations so that we don't bog down the tests. |
| /// |
| /// Note: should an exception occur during computation of [instance], it will |
| /// silently be set to null to allow other tests to complete quickly. |
| class SerializedMockSdk { |
| static final SerializedMockSdk instance = _serializeMockSdk(); |
| |
| final Map<String, UnlinkedUnit> uriToUnlinkedUnit; |
| |
| final Map<String, LinkedLibrary> uriToLinkedLibrary; |
| |
| SerializedMockSdk._(this.uriToUnlinkedUnit, this.uriToLinkedLibrary); |
| |
| static SerializedMockSdk _serializeMockSdk() { |
| try { |
| Map<String, UnlinkedUnit> uriToUnlinkedUnit = <String, UnlinkedUnit>{}; |
| Map<String, LinkedLibrary> uriToLinkedLibrary = <String, LinkedLibrary>{}; |
| var resourceProvider = new MemoryResourceProvider(); |
| PackageBundle bundle = |
| new MockSdk(resourceProvider: resourceProvider).getLinkedBundle(); |
| for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) { |
| String uri = bundle.unlinkedUnitUris[i]; |
| uriToUnlinkedUnit[uri] = bundle.unlinkedUnits[i]; |
| } |
| for (int i = 0; i < bundle.linkedLibraryUris.length; i++) { |
| String uri = bundle.linkedLibraryUris[i]; |
| uriToLinkedLibrary[uri] = bundle.linkedLibraries[i]; |
| } |
| return new SerializedMockSdk._(uriToUnlinkedUnit, uriToLinkedLibrary); |
| } catch (_) { |
| return null; |
| } |
| } |
| } |
| |
| /// Abstract base class for tests involving summaries. |
| /// |
| /// Test classes should not extend this class directly; they should extend a |
| /// class that implements this class with methods that drive summary generation. |
| /// The tests themselves can then be provided via mixin, allowing summaries to |
| /// be tested in a variety of ways. |
| abstract class SummaryBaseTestStrategy { |
| /// The set of [ExperimentStatus] enabled in this test. |
| ExperimentStatus experimentStatus; |
| |
| /// Add the given package bundle as a dependency so that it may be referenced |
| /// by the files under test. |
| void addBundle(String path, PackageBundle bundle); |
| |
| /// Add the given source file so that it may be referenced by the file under |
| /// test. |
| void addNamedSource(String filePath, String contents); |
| |
| /// Link together the given file, along with any other files passed to |
| /// [addNamedSource], to form a package bundle. Reset the state of the |
| /// buffers accumulated by [addNamedSource] and [addBundle] so that further |
| /// bundles can be created. |
| PackageBundleBuilder createPackageBundle(String text, |
| {String path: '/test.dart', String uri}); |
| } |
| |
| /// Abstract base class for black-box tests of summaries. |
| /// |
| /// Test classes should not extend this class directly; they should extend a |
| /// class that implements this class with methods that drive summary generation. |
| /// The tests themselves can then be provided via mixin, allowing summaries to |
| /// be tested in a variety of ways. |
| abstract class SummaryBlackBoxTestStrategy extends SummaryBaseTestStrategy { |
| /// A test will set this to `true` if it contains `import`, `export`, or |
| /// `part` declarations that deliberately refer to non-existent files. |
| void set allowMissingFiles(bool value); |
| |
| /// Indicates whether the summary contains expressions for non-const fields. |
| /// |
| /// When one-phase summarization is in use, only const field initializer |
| /// expressions are stored in the summary. |
| bool get containsNonConstExprs; |
| |
| /// Get access to the linked summary that results from serializing and |
| /// then deserializing the library under test. |
| LinkedLibrary get linked; |
| |
| /// `true` if the linked portion of the summary only contains prelinked data. |
| /// This happens because we don't yet have a full linker; only a prelinker. |
| bool get skipFullyLinkedData; |
| |
| /// Get access to the unlinked compilation unit summaries that result from |
| /// serializing and deserializing the library under test. |
| List<UnlinkedUnit> get unlinkedUnits; |
| |
| /// Serialize the given library [text], then deserialize it and store its |
| /// summary in [lib]. |
| void serializeLibraryText(String text, |
| {bool allowErrors: false, bool nnbd: false}); |
| } |
| |
| /// Implementation of [SummaryBlackBoxTestStrategy] that drives summary |
| /// generation using the old two-phase API, and exercises the pre-linker only. |
| class SummaryBlackBoxTestStrategyPrelink |
| extends _SummaryBlackBoxTestStrategyTwoPhase |
| implements SummaryBlackBoxTestStrategy { |
| @override |
| bool get skipFullyLinkedData => true; |
| |
| @override |
| void serializeLibraryText(String text, |
| {bool allowErrors: false, bool nnbd: false}) { |
| super.serializeLibraryText(text, allowErrors: allowErrors, nnbd: nnbd); |
| |
| UnlinkedUnit getPart(String absoluteUri) { |
| return _linkerInputs.getUnit(absoluteUri); |
| } |
| |
| UnlinkedPublicNamespace getImport(String absoluteUri) { |
| return getPart(absoluteUri)?.publicNamespace; |
| } |
| |
| linked = new LinkedLibrary.fromBuffer(prelink( |
| _linkerInputs._testDartUri.toString(), |
| _linkerInputs._unlinkedDefiningUnit, |
| getPart, |
| getImport, |
| DeclaredVariables()) |
| .toBuffer()); |
| _validateLinkedLibrary(linked); |
| } |
| } |
| |
| /// Implementation of [SummaryBlackBoxTestStrategy] that drives summary |
| /// generation using the old two-phase API, and exercises full summary |
| /// generation. |
| class SummaryBlackBoxTestStrategyTwoPhase |
| extends _SummaryBlackBoxTestStrategyTwoPhase |
| implements SummaryBlackBoxTestStrategy { |
| @override |
| bool get skipFullyLinkedData => false; |
| } |
| |
| /// Abstract base class for unit tests of the summary linker. |
| /// |
| /// Test classes should not extend this class directly; they should extend a |
| /// class that implements this class with methods that drive summary generation. |
| /// The tests themselves can then be provided via mixin, allowing summaries to |
| /// be tested in a variety of ways. |
| abstract class SummaryLinkerTestStrategy extends SummaryBaseTestStrategy { |
| Linker get linker; |
| |
| /// Gets the URI of the main library under test. |
| /// |
| /// May only be called after [createLinker]. |
| Uri get testDartUri; |
| |
| LibraryElementInBuildUnit get testLibrary; |
| |
| void createLinker(String text, {String path: '/test.dart'}); |
| } |
| |
| /// Implementation of [SummaryLinkerTestStrategy] that drives summary generation |
| /// using the old two-phase API. |
| class SummaryLinkerTestStrategyTwoPhase extends _SummaryBaseTestStrategyTwoPhase |
| implements SummaryLinkerTestStrategy { |
| LibraryElementInBuildUnit _testLibrary; |
| |
| @override |
| Linker linker; |
| |
| @override |
| Uri get testDartUri => _linkerInputs._testDartUri; |
| |
| @override |
| LibraryElementInBuildUnit get testLibrary => |
| _testLibrary ??= linker.getLibrary(_linkerInputs._testDartUri) |
| as LibraryElementInBuildUnit; |
| |
| @override |
| bool get _allowMissingFiles => false; |
| |
| @override |
| void createLinker(String text, {String path: '/test.dart'}) { |
| _linkerInputs = _createLinkerInputs(text, path: path); |
| Map<String, LinkedLibraryBuilder> linkedLibraries = setupForLink( |
| _linkerInputs.linkedLibraries, |
| _linkerInputs.getUnit, |
| _linkerInputs.declaredVariables); |
| linker = new Linker(linkedLibraries, _linkerInputs.getDependency, |
| _linkerInputs.getUnit, null, analysisOptions); |
| } |
| } |
| |
| /// [_FilesToLink] stores information about a set of files to be linked |
| /// together. This information is grouped into a class to allow it to be reset |
| /// easily when [_SummaryBaseTestStrategyTwoPhase._createLinkerInputs] is |
| /// called. |
| /// |
| /// The generic parameter [U] is the type of information stored for each |
| /// compilation unit. |
| class _FilesToLink<U> { |
| /// Map from absolute URI to the [U] for each compilation unit passed to |
| /// [addNamedSource]. |
| Map<String, U> uriToUnit = <String, U>{}; |
| |
| /// Information about summaries to be included in the link process. |
| SummaryDataStore summaryDataStore = new SummaryDataStore([]); |
| } |
| |
| /// Instances of the class [_LinkerInputs] encapsulate the necessary information |
| /// to pass to the summary linker. |
| class _LinkerInputs { |
| final bool _allowMissingFiles; |
| final Map<String, UnlinkedUnit> _uriToUnit; |
| final Uri _testDartUri; |
| final UnlinkedUnit _unlinkedDefiningUnit; |
| final Map<String, LinkedLibrary> _dependentLinkedLibraries; |
| final Map<String, UnlinkedUnit> _dependentUnlinkedUnits; |
| |
| _LinkerInputs( |
| this._allowMissingFiles, |
| this._uriToUnit, |
| this._testDartUri, |
| this._unlinkedDefiningUnit, |
| this._dependentLinkedLibraries, |
| this._dependentUnlinkedUnits); |
| |
| DeclaredVariables get declaredVariables => DeclaredVariables(); |
| |
| Set<String> get linkedLibraries => _uriToUnit.keys.toSet(); |
| |
| LinkedLibrary getDependency(String absoluteUri) { |
| Map<String, LinkedLibrary> sdkLibraries = |
| SerializedMockSdk.instance.uriToLinkedLibrary; |
| LinkedLibrary linkedLibrary = |
| sdkLibraries[absoluteUri] ?? _dependentLinkedLibraries[absoluteUri]; |
| if (linkedLibrary == null && !_allowMissingFiles) { |
| Set<String> librariesAvailable = sdkLibraries.keys.toSet(); |
| librariesAvailable.addAll(_dependentLinkedLibraries.keys); |
| fail('Linker unexpectedly requested LinkedLibrary for "$absoluteUri".' |
| ' Libraries available: ${librariesAvailable.toList()}'); |
| } |
| return linkedLibrary; |
| } |
| |
| UnlinkedUnit getUnit(String absoluteUri) { |
| if (absoluteUri == null) { |
| return null; |
| } |
| UnlinkedUnit unit = _uriToUnit[absoluteUri] ?? |
| SerializedMockSdk.instance.uriToUnlinkedUnit[absoluteUri] ?? |
| _dependentUnlinkedUnits[absoluteUri]; |
| if (unit == null && !_allowMissingFiles) { |
| fail('Linker unexpectedly requested unit for "$absoluteUri".'); |
| } |
| return unit; |
| } |
| } |
| |
| /// Implementation of [SummaryBaseTestStrategy] that drives summary generation |
| /// using the old two-phase API. |
| abstract class _SummaryBaseTestStrategyTwoPhase |
| implements SummaryBaseTestStrategy { |
| /// Information about the files to be linked. |
| _FilesToLink<UnlinkedUnitBuilder> _filesToLink = |
| new _FilesToLink<UnlinkedUnitBuilder>(); |
| |
| @override |
| ExperimentStatus experimentStatus = ExperimentStatus(); |
| |
| _LinkerInputs _linkerInputs; |
| |
| AnalysisOptions get analysisOptions => AnalysisOptionsImpl() |
| ..enabledExperiments = experimentStatus.toStringList(); |
| |
| bool get _allowMissingFiles; |
| |
| @override |
| void addBundle(String path, PackageBundle bundle) { |
| _filesToLink.summaryDataStore.addBundle(path, bundle); |
| } |
| |
| @override |
| void addNamedSource(String filePath, String contents) { |
| CompilationUnit unit = parseText(contents); |
| UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit); |
| _filesToLink.uriToUnit[absUri(filePath)] = unlinkedUnit; |
| } |
| |
| @override |
| PackageBundleBuilder createPackageBundle(String text, |
| {String path: '/test.dart', String uri}) { |
| PackageBundleAssembler assembler = new PackageBundleAssembler(); |
| _LinkerInputs linkerInputs = |
| _createLinkerInputs(text, path: path, uri: uri); |
| Map<String, LinkedLibraryBuilder> linkedLibraries = link( |
| linkerInputs.linkedLibraries, |
| linkerInputs.getDependency, |
| linkerInputs.getUnit, |
| linkerInputs.declaredVariables, |
| analysisOptions); |
| linkedLibraries.forEach(assembler.addLinkedLibrary); |
| linkerInputs._uriToUnit.forEach((String uri, UnlinkedUnit unit) { |
| assembler.addUnlinkedUnitViaUri(uri, unit); |
| }); |
| return assembler.assemble(); |
| } |
| |
| UnlinkedUnitBuilder createUnlinkedSummary(Uri uri, String text, |
| {bool nnbd: false}) => |
| serializeAstUnlinked(parseText(text, experimentStatus: experimentStatus), |
| nnbd: nnbd); |
| |
| _LinkerInputs _createLinkerInputs(String text, |
| {String path: '/test.dart', String uri, bool nnbd: false}) { |
| uri ??= absUri(path); |
| Uri testDartUri = Uri.parse(uri); |
| UnlinkedUnitBuilder unlinkedDefiningUnit = |
| createUnlinkedSummary(testDartUri, text, nnbd: nnbd); |
| _filesToLink.uriToUnit[testDartUri.toString()] = unlinkedDefiningUnit; |
| _LinkerInputs linkerInputs = new _LinkerInputs( |
| _allowMissingFiles, |
| _filesToLink.uriToUnit, |
| testDartUri, |
| unlinkedDefiningUnit, |
| _filesToLink.summaryDataStore.linkedMap, |
| _filesToLink.summaryDataStore.unlinkedMap); |
| // Reset _filesToLink in case the test needs to start a new package bundle. |
| _filesToLink = new _FilesToLink<UnlinkedUnitBuilder>(); |
| return linkerInputs; |
| } |
| } |
| |
| /// Implementation of [SummaryBlackBoxTestStrategy] that drives summary |
| /// generation using the old two-phase API. |
| /// |
| /// Not intended to be used directly; instead use a derived class that either |
| /// exercises the full summary algorithm or just pre-linking. |
| abstract class _SummaryBlackBoxTestStrategyTwoPhase |
| extends _SummaryBaseTestStrategyTwoPhase |
| implements SummaryBlackBoxTestStrategy { |
| @override |
| List<UnlinkedUnit> unlinkedUnits; |
| |
| @override |
| LinkedLibrary linked; |
| |
| @override |
| bool _allowMissingFiles = false; |
| |
| @override |
| void set allowMissingFiles(bool value) { |
| _allowMissingFiles = value; |
| } |
| |
| @override |
| bool get containsNonConstExprs => true; |
| |
| @override |
| void serializeLibraryText(String text, |
| {bool allowErrors: false, bool nnbd: false}) { |
| Map<String, UnlinkedUnitBuilder> uriToUnit = this._filesToLink.uriToUnit; |
| _linkerInputs = _createLinkerInputs(text, nnbd: nnbd); |
| linked = link( |
| _linkerInputs.linkedLibraries, |
| _linkerInputs.getDependency, |
| _linkerInputs.getUnit, |
| DeclaredVariables(), |
| analysisOptions)[_linkerInputs._testDartUri.toString()]; |
| expect(linked, isNotNull); |
| _validateLinkedLibrary(linked); |
| unlinkedUnits = <UnlinkedUnit>[_linkerInputs._unlinkedDefiningUnit]; |
| for (String relativeUriStr |
| in _linkerInputs._unlinkedDefiningUnit.publicNamespace.parts) { |
| Uri relativeUri; |
| try { |
| relativeUri = Uri.parse(relativeUriStr); |
| } on FormatException { |
| unlinkedUnits.add(new UnlinkedUnitBuilder()); |
| continue; |
| } |
| |
| UnlinkedUnit unit = uriToUnit[ |
| resolveRelativeUri(_linkerInputs._testDartUri, relativeUri) |
| .toString()]; |
| if (unit == null) { |
| if (!_allowMissingFiles) { |
| fail('Test referred to unknown unit $relativeUriStr'); |
| } |
| } else { |
| unlinkedUnits.add(unit); |
| } |
| } |
| } |
| } |