|  | // Copyright (c) 2015, 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 'dart:collection'; | 
|  |  | 
|  | import 'package:analyzer/exception/exception.dart'; | 
|  | import 'package:analyzer/file_system/file_system.dart'; | 
|  | import 'package:analyzer/source/source.dart'; | 
|  | import 'package:analyzer/src/generated/engine.dart'; | 
|  | import 'package:analyzer/src/generated/sdk.dart'; | 
|  | import 'package:analyzer/src/generated/source.dart' | 
|  | show DartUriResolver, SourceFactory, UriResolver; | 
|  | import 'package:analyzer/src/source/package_map_resolver.dart'; | 
|  | import 'package:analyzer/src/util/file_paths.dart' as file_paths; | 
|  | import 'package:analyzer/src/utilities/uri_cache.dart'; | 
|  | import 'package:analyzer/src/workspace/pub.dart'; | 
|  |  | 
|  | /// Return `true` if the given [source] refers to a file that is assumed to be | 
|  | /// generated. | 
|  | bool isGeneratedSource(Source? source) { | 
|  | if (source == null) { | 
|  | return false; | 
|  | } | 
|  | return file_paths.isGenerated(source.fullName); | 
|  | } | 
|  |  | 
|  | /// Instances of the class `SourceFactory` resolve possibly relative URI's | 
|  | /// against an existing [Source]. | 
|  | class SourceFactoryImpl implements SourceFactory { | 
|  | /// The resolvers used to resolve absolute URI's. | 
|  | final List<UriResolver> resolvers; | 
|  |  | 
|  | /// Cache of mapping of absolute [Uri]s to [Source]s. | 
|  | final HashMap<Uri, Source> _absoluteUriToSourceCache = HashMap<Uri, Source>(); | 
|  |  | 
|  | /// Initialize a newly created source factory with the given absolute URI | 
|  | /// [resolvers]. | 
|  | SourceFactoryImpl(this.resolvers); | 
|  |  | 
|  | @override | 
|  | DartSdk? get dartSdk { | 
|  | final resolvers = this.resolvers; | 
|  | int length = resolvers.length; | 
|  | for (int i = 0; i < length; i++) { | 
|  | var resolver = resolvers[i]; | 
|  | if (resolver is DartUriResolver) { | 
|  | return resolver.dartSdk; | 
|  | } | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | @override | 
|  | Map<String, List<Folder>>? get packageMap { | 
|  | for (var resolver in resolvers) { | 
|  | if (resolver is PackageMapUriResolver) { | 
|  | return resolver.packageMap; | 
|  | } | 
|  | if (resolver is PackageBuildPackageUriResolver) { | 
|  | return resolver.packageMap; | 
|  | } | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | @override | 
|  | Source? forUri(String absoluteUri) { | 
|  | try { | 
|  | Uri uri; | 
|  | try { | 
|  | uri = uriCache.parse(absoluteUri); | 
|  | } catch (exception, stackTrace) { | 
|  | AnalysisEngine.instance.instrumentationService | 
|  | .logInfo('Could not resolve URI: $absoluteUri $stackTrace'); | 
|  | return null; | 
|  | } | 
|  | if (uri.isAbsolute) { | 
|  | return _internalResolveUri(null, uri); | 
|  | } | 
|  | } catch (exception, stackTrace) { | 
|  | // TODO(39284): should this exception be silent? | 
|  | AnalysisEngine.instance.instrumentationService.logException( | 
|  | SilentException( | 
|  | "Could not resolve URI: $absoluteUri", exception, stackTrace)); | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | @override | 
|  | Source? forUri2(Uri absoluteUri) { | 
|  | if (absoluteUri.isAbsolute) { | 
|  | try { | 
|  | return _internalResolveUri(null, absoluteUri); | 
|  | } on AnalysisException catch (exception, stackTrace) { | 
|  | // TODO(39284): should this exception be silent? | 
|  | AnalysisEngine.instance.instrumentationService.logException( | 
|  | SilentException( | 
|  | "Could not resolve URI: $absoluteUri", exception, stackTrace)); | 
|  | } | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | @override | 
|  | Uri? pathToUri(String path) { | 
|  | for (var resolver in resolvers) { | 
|  | var uri = resolver.pathToUri(path); | 
|  | if (uri != null) { | 
|  | return uri; | 
|  | } | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | @override | 
|  | Source? resolveUri(Source? containingSource, String? containedUri) { | 
|  | if (containedUri == null) { | 
|  | return null; | 
|  | } | 
|  | if (containedUri.isEmpty) { | 
|  | return containingSource; | 
|  | } | 
|  | try { | 
|  | // Force the creation of an escaped URI to deal with spaces, etc. | 
|  | return _internalResolveUri( | 
|  | containingSource, uriCache.parse(containedUri)); | 
|  | } on FormatException { | 
|  | return null; | 
|  | } catch (exception, stackTrace) { | 
|  | String containingFullName = | 
|  | containingSource != null ? containingSource.fullName : '<null>'; | 
|  | // TODO(39284): should this exception be silent? | 
|  | AnalysisEngine.instance.instrumentationService | 
|  | .logException(SilentException( | 
|  | "Could not resolve URI ($containedUri) " | 
|  | "relative to source ($containingFullName)", | 
|  | exception, | 
|  | stackTrace)); | 
|  | return null; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Return a source object representing the URI that results from resolving | 
|  | /// the given (possibly relative) contained URI against the URI associated | 
|  | /// with an existing source object, or `null` if the URI could not be | 
|  | /// resolved. | 
|  | /// | 
|  | /// @param containingSource the source containing the given URI | 
|  | /// @param containedUri the (possibly relative) URI to be resolved against the | 
|  | ///        containing source | 
|  | /// @return the source representing the contained URI | 
|  | /// @throws AnalysisException if either the contained URI is invalid or if it | 
|  | ///         cannot be resolved against the source object's URI | 
|  | Source? _internalResolveUri(Source? containingSource, Uri containedUri) { | 
|  | if (!containedUri.isAbsolute) { | 
|  | if (containingSource == null) { | 
|  | throw AnalysisException( | 
|  | "Cannot resolve a relative URI without a containing source: " | 
|  | "$containedUri"); | 
|  | } | 
|  | containedUri = | 
|  | uriCache.resolveRelative(containingSource.uri, containedUri); | 
|  | } | 
|  |  | 
|  | var result = _absoluteUriToSourceCache[containedUri]; | 
|  | if (result == null) { | 
|  | for (UriResolver resolver in resolvers) { | 
|  | result = resolver.resolveAbsolute(containedUri); | 
|  | if (result != null) { | 
|  | _absoluteUriToSourceCache[containedUri] = result; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  | } |