| // Copyright (c) 2017, 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:async'; |
| import 'dart:convert'; |
| |
| import 'package:analyzer/context/declared_variables.dart'; |
| import 'package:analyzer/dart/element/element.dart' show CompilationUnitElement; |
| import 'package:analyzer/file_system/file_system.dart'; |
| import 'package:analyzer/src/context/context.dart'; |
| import 'package:analyzer/src/dart/analysis/file_state.dart'; |
| import 'package:analyzer/src/dart/element/element.dart'; |
| import 'package:analyzer/src/dart/element/handle.dart'; |
| import 'package:analyzer/src/generated/engine.dart' |
| show AnalysisContext, AnalysisEngine, AnalysisOptions; |
| import 'package:analyzer/src/generated/sdk.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/kernel/resynthesize.dart'; |
| import 'package:front_end/byte_store.dart'; |
| import 'package:front_end/compiler_options.dart'; |
| import 'package:front_end/file_system.dart'; |
| import 'package:front_end/src/base/libraries_specification.dart'; |
| import 'package:front_end/src/base/performace_logger.dart'; |
| import 'package:front_end/src/base/processed_options.dart'; |
| import 'package:front_end/src/fasta/uri_translator_impl.dart'; |
| import 'package:front_end/src/incremental/kernel_driver.dart'; |
| import 'package:kernel/ast.dart' as kernel; |
| import 'package:kernel/target/targets.dart'; |
| import 'package:package_config/packages.dart'; |
| import 'package:package_config/src/packages_impl.dart'; |
| import 'package:path/path.dart' as pathos; |
| |
| /** |
| * Support for resynthesizing element model from Kernel. |
| */ |
| class KernelContext { |
| /** |
| * The [AnalysisContext] which is used to do the analysis. |
| */ |
| final AnalysisContext analysisContext; |
| |
| /** |
| * The resynthesizer that resynthesizes elements in [analysisContext]. |
| */ |
| final ElementResynthesizer resynthesizer; |
| |
| KernelContext._(this.analysisContext, this.resynthesizer); |
| |
| /** |
| * Computes a [CompilationUnitElement] for the given library/unit pair. |
| */ |
| CompilationUnitElement computeUnitElement( |
| Source librarySource, Source unitSource) { |
| String libraryUri = librarySource.uri.toString(); |
| String unitUri = unitSource.uri.toString(); |
| return resynthesizer.getElement( |
| new ElementLocationImpl.con3(<String>[libraryUri, unitUri])); |
| } |
| |
| /** |
| * Cleans up any persistent resources used by this [KernelContext]. |
| * |
| * Should be called once the [KernelContext] is no longer needed. |
| */ |
| void dispose() { |
| analysisContext.dispose(); |
| } |
| |
| /** |
| * Return `true` if the given [uri] is known to be a library. |
| */ |
| bool isLibraryUri(Uri uri) { |
| // TODO(scheglov) implement |
| return true; |
| // String uriStr = uri.toString(); |
| // return store.unlinkedMap[uriStr]?.isPartOf == false; |
| } |
| |
| /** |
| * Create a [KernelContext] which is prepared to analyze [targetLibrary]. |
| */ |
| static Future<KernelContext> forSingleLibrary( |
| FileState targetLibrary, |
| PerformanceLog logger, |
| ByteStore byteStore, |
| AnalysisOptions analysisOptions, |
| DeclaredVariables declaredVariables, |
| SourceFactory sourceFactory, |
| FileSystemState fsState, |
| pathos.Context pathContext) async { |
| return logger.runAsync('Create kernel context', () async { |
| // Prepare SDK libraries. |
| Map<String, LibraryInfo> dartLibraries = {}; |
| { |
| DartSdk dartSdk = sourceFactory.dartSdk; |
| dartSdk.sdkLibraries.forEach((sdkLibrary) { |
| var dartUri = sdkLibrary.shortName; |
| var name = Uri.parse(dartUri).path; |
| var path = dartSdk.mapDartUri(dartUri).fullName; |
| var fileUri = pathContext.toUri(path); |
| dartLibraries[name] = new LibraryInfo(name, fileUri, const []); |
| }); |
| } |
| |
| // Prepare packages. |
| Packages packages = Packages.noPackages; |
| { |
| Map<String, List<Folder>> packageMap = sourceFactory.packageMap; |
| if (packageMap != null) { |
| var map = <String, Uri>{}; |
| for (var name in packageMap.keys) { |
| map[name] = packageMap[name].first.toUri(); |
| } |
| packages = new MapPackages(map); |
| } |
| } |
| |
| var uriTranslator = new UriTranslatorImpl( |
| new TargetLibrariesSpecification('none', dartLibraries), packages); |
| var options = new ProcessedOptions(new CompilerOptions() |
| ..target = new _AnalysisTarget( |
| new TargetFlags(strongMode: analysisOptions.strongMode)) |
| ..reportMessages = false |
| ..logger = logger |
| ..fileSystem = new _FileSystemAdaptor(fsState, pathContext) |
| ..byteStore = byteStore); |
| var driver = new KernelDriver(options, uriTranslator); |
| |
| Uri targetUri = targetLibrary.uri; |
| KernelResult kernelResult = await driver.getKernel(targetUri); |
| |
| // Remember Kernel libraries required to resynthesize the target. |
| var libraryMap = <String, kernel.Library>{}; |
| for (var cycleResult in kernelResult.results) { |
| for (var library in cycleResult.kernelLibraries) { |
| String uriStr = library.importUri.toString(); |
| libraryMap[uriStr] = library; |
| } |
| } |
| |
| // Create and configure a new context. |
| AnalysisContextImpl analysisContext = |
| AnalysisEngine.instance.createAnalysisContext(); |
| analysisContext.useSdkCachePartition = false; |
| analysisContext.analysisOptions = analysisOptions; |
| analysisContext.declaredVariables.addAll(declaredVariables); |
| analysisContext.sourceFactory = sourceFactory.clone(); |
| |
| // Create the resynthesizer bound to the analysis context. |
| var resynthesizer = new KernelResynthesizer( |
| analysisContext, kernelResult.types, libraryMap); |
| |
| return new KernelContext._(analysisContext, resynthesizer); |
| }); |
| } |
| } |
| |
| /** |
| * [Target] for static analysis, with all features enabled. |
| */ |
| class _AnalysisTarget extends NoneTarget { |
| _AnalysisTarget(TargetFlags flags) : super(flags); |
| |
| @override |
| List<String> get extraRequiredLibraries => const <String>['dart:_internal']; |
| |
| @override |
| bool enableNative(Uri uri) => true; |
| } |
| |
| class _FileSystemAdaptor implements FileSystem { |
| final FileSystemState fsState; |
| final pathos.Context pathContext; |
| |
| _FileSystemAdaptor(this.fsState, this.pathContext); |
| |
| @override |
| FileSystemEntity entityForUri(Uri uri) { |
| if (uri.isScheme('file')) { |
| var path = pathContext.fromUri(uri); |
| var file = fsState.getFileForPath(path); |
| return new _FileSystemEntityAdaptor(uri, file); |
| } else { |
| throw new ArgumentError( |
| 'Only file:// URIs are supported, but $uri is given.'); |
| } |
| } |
| } |
| |
| class _FileSystemEntityAdaptor implements FileSystemEntity { |
| final Uri uri; |
| final FileState file; |
| |
| _FileSystemEntityAdaptor(this.uri, this.file); |
| |
| @override |
| Future<bool> exists() async { |
| return file.exists; |
| } |
| |
| @override |
| Future<List<int>> readAsBytes() async { |
| // TODO(scheglov) Optimize. |
| return UTF8.encode(file.content); |
| } |
| |
| @override |
| Future<String> readAsString() async { |
| return file.content; |
| } |
| } |