blob: 2aaccca81d2d6816befd2dd32df58d74d758b036 [file] [log] [blame]
// 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:analyzer/src/summary/summary_sdk.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';
/**
* 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) async {
return logger.runAsync('Create kernel context', () async {
// Prepare SDK libraries.
Map<String, LibraryInfo> dartLibraries = {};
{
DartSdk dartSdk = sourceFactory.dartSdk;
dartSdk.sdkLibraries.forEach((sdkLibrary) {
var name = Uri.parse(sdkLibrary.shortName).path;
var path = dartSdk.mapDartUri(sdkLibrary.shortName).fullName;
dartLibraries[name] =
new LibraryInfo(name, Uri.parse('file://$path'), 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 NoneTarget(
new TargetFlags(strongMode: analysisOptions.strongMode))
..reportMessages = false
..logger = logger
..fileSystem = new _FileSystemAdaptor(fsState)
..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);
analysisContext.typeProvider = _buildTypeProvider(resynthesizer);
return new KernelContext._(analysisContext, resynthesizer);
});
}
static SummaryTypeProvider _buildTypeProvider(
KernelResynthesizer resynthesizer) {
var coreLibrary = resynthesizer.getLibrary('dart:core');
var asyncLibrary = resynthesizer.getLibrary('dart:async');
SummaryTypeProvider summaryTypeProvider = new SummaryTypeProvider();
summaryTypeProvider.initializeCore(coreLibrary);
summaryTypeProvider.initializeAsync(asyncLibrary);
return summaryTypeProvider;
}
}
class _FileSystemAdaptor implements FileSystem {
final FileSystemState fsState;
_FileSystemAdaptor(this.fsState);
@override
FileSystemEntity entityForUri(Uri uri) {
if (uri.isScheme('file')) {
var file = fsState.getFileForPath(uri.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;
}
}