blob: f14cde27a64211301cc16399f1e389b667f86208 [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 'package:analyzer/context/declared_variables.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart' show CompilationUnitElement;
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
import 'package:analyzer/src/dart/analysis/file_tracker.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisEngine, AnalysisOptions;
import 'package:analyzer/src/generated/source.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/task/dart.dart' show COMPILATION_UNIT_ELEMENT;
import 'package:analyzer/task/dart.dart' show LibrarySpecificUnit;
/**
* Context information necessary to analyze one or more libraries within an
* [AnalysisDriver].
*
* Currently this is implemented as a wrapper around [AnalysisContext].
* TODO(paulberry): make a front end API that this can make use of instead.
*/
class LibraryContext {
final SummaryDataStore store;
/**
* The [AnalysisContext] which is used to do the analysis.
*/
final AnalysisContext _analysisContext;
/**
* Create a [LibraryContext] which is prepared to analyze [targetLibrary].
*/
factory LibraryContext.forSingleLibrary(
FileState targetLibrary,
PerformanceLog logger,
PackageBundle sdkBundle,
ByteStore byteStore,
AnalysisOptions options,
DeclaredVariables declaredVariables,
SourceFactory sourceFactory,
FileTracker fileTracker) {
return logger.run('Create library context', () {
Map<String, FileState> libraries = <String, FileState>{};
SummaryDataStore store = new SummaryDataStore(const <String>[]);
if (sdkBundle != null) {
store.addBundle(null, sdkBundle);
}
void appendLibraryFiles(FileState library) {
if (!libraries.containsKey(library.uriStr)) {
// Serve 'dart:' URIs from the SDK bundle.
if (sdkBundle != null && library.uri.scheme == 'dart') {
return;
}
libraries[library.uriStr] = library;
// Append the defining unit.
store.addUnlinkedUnit(library.uriStr, library.unlinked);
// Append parts.
for (FileState part in library.partedFiles) {
store.addUnlinkedUnit(part.uriStr, part.unlinked);
}
// Append referenced libraries.
library.importedFiles.forEach(appendLibraryFiles);
library.exportedFiles.forEach(appendLibraryFiles);
}
}
logger.run('Append library files', () {
return appendLibraryFiles(targetLibrary);
});
Set<String> libraryUrisToLink = new Set<String>();
logger.run('Load linked bundles', () {
for (FileState library in libraries.values) {
if (library.exists || library == targetLibrary) {
String key = '${library.transitiveSignature}.linked';
List<int> bytes = byteStore.get(key);
if (bytes != null) {
LinkedLibrary linked = new LinkedLibrary.fromBuffer(bytes);
store.addLinkedLibrary(library.uriStr, linked);
} else {
libraryUrisToLink.add(library.uriStr);
}
}
}
int numOfLoaded = libraries.length - libraryUrisToLink.length;
logger.writeln('Loaded $numOfLoaded linked bundles.');
});
Map<String, LinkedLibraryBuilder> linkedLibraries = {};
logger.run('Link bundles', () {
linkedLibraries = link(libraryUrisToLink, (String uri) {
LinkedLibrary linkedLibrary = store.linkedMap[uri];
return linkedLibrary;
}, (String uri) {
UnlinkedUnit unlinkedUnit = store.unlinkedMap[uri];
return unlinkedUnit;
}, (_) => null, options.strongMode);
logger.writeln('Linked ${linkedLibraries.length} bundles.');
});
linkedLibraries.forEach((uri, linkedBuilder) {
FileState library = libraries[uri];
String key = '${library.transitiveSignature}.linked';
List<int> bytes = linkedBuilder.toBuffer();
LinkedLibrary linked = new LinkedLibrary.fromBuffer(bytes);
store.addLinkedLibrary(uri, linked);
byteStore.put(key, bytes);
});
var analysisContext = _createAnalysisContext(
options, declaredVariables, sourceFactory, fileTracker, store);
return new LibraryContext._(store, analysisContext);
});
}
LibraryContext._(this.store, this._analysisContext);
/**
* Computes a [CompilationUnitElement] for the given library/unit pair.
*/
CompilationUnitElement computeUnitElement(
Source librarySource, Source unitSource) {
return _analysisContext.computeResult(
new LibrarySpecificUnit(librarySource, unitSource),
COMPILATION_UNIT_ELEMENT);
}
/**
* Cleans up any persistent resources used by this [LibraryContext].
*
* Should be called once the [LibraryContext] is no longer needed.
*/
void dispose() {
_analysisContext.dispose();
}
/**
* Computes a resolved [CompilationUnit] and a list of [AnalysisError]s for
* the given library/unit pair.
*/
ResolutionResult resolveUnit(Source librarySource, Source unitSource) {
CompilationUnit resolvedUnit =
_analysisContext.resolveCompilationUnit2(unitSource, librarySource);
List<AnalysisError> errors = _analysisContext.computeErrors(unitSource);
return new ResolutionResult(resolvedUnit, errors);
}
static AnalysisContext _createAnalysisContext(
AnalysisOptions _analysisOptions,
DeclaredVariables declaredVariables,
SourceFactory _sourceFactory,
FileTracker fileTracker,
SummaryDataStore store) {
AnalysisContextImpl analysisContext =
AnalysisEngine.instance.createAnalysisContext();
analysisContext.useSdkCachePartition = false;
analysisContext.analysisOptions = _analysisOptions;
analysisContext.declaredVariables.addAll(declaredVariables);
analysisContext.sourceFactory = _sourceFactory.clone();
analysisContext.contentCache = new _ContentCacheWrapper(fileTracker);
analysisContext.resultProvider =
new InputPackagesResultProvider(analysisContext, store);
return analysisContext;
}
}
/**
* Container object holding the result of a call to
* [LibraryContext.resolveUnit].
*/
class ResolutionResult {
final CompilationUnit resolvedUnit;
final List<AnalysisError> errors;
ResolutionResult(this.resolvedUnit, this.errors);
}
/**
* [ContentCache] wrapper around [FileContentOverlay].
*/
class _ContentCacheWrapper implements ContentCache {
final FileTracker fileTracker;
_ContentCacheWrapper(this.fileTracker);
@override
void accept(ContentCacheVisitor visitor) {
throw new UnimplementedError();
}
@override
String getContents(Source source) {
return _getFileForSource(source).content;
}
@override
bool getExists(Source source) {
if (source.isInSystemLibrary) {
return true;
}
return _getFileForSource(source).exists;
}
@override
int getModificationStamp(Source source) {
if (source.isInSystemLibrary) {
return 0;
}
return _getFileForSource(source).exists ? 0 : -1;
}
@override
String setContents(Source source, String contents) {
throw new UnimplementedError();
}
FileState _getFileForSource(Source source) {
String path = source.fullName;
return fileTracker.fsState.getFileForPath(path);
}
}