blob: a81b50f0fbbe2d064f95427ea6bb56f508fbc36e [file] [log] [blame]
// Copyright (c) 2014, 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.
library analyzer.src.generated.sdk;
import 'dart:collection';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisOptions;
import 'package:analyzer/src/generated/source.dart' show Source;
import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
/**
* A Dart SDK installed in a specified location.
*/
abstract class DartSdk {
/**
* The short name of the dart SDK 'async' library.
*/
static const String DART_ASYNC = "dart:async";
/**
* The short name of the dart SDK 'core' library.
*/
static const String DART_CORE = "dart:core";
/**
* The short name of the dart SDK 'html' library.
*/
static const String DART_HTML = "dart:html";
/**
* The prefix shared by all dart library URIs.
*/
static const String DART_LIBRARY_PREFIX = "dart:";
/**
* The version number that is returned when the real version number could not
* be determined.
*/
static const String DEFAULT_VERSION = "0";
/**
* Return the analysis context used for all of the sources in this [DartSdk].
*/
AnalysisContext get context;
/**
* Return a list containing all of the libraries defined in this SDK.
*/
List<SdkLibrary> get sdkLibraries;
/**
* Return the revision number of this SDK, or `"0"` if the revision number
* cannot be discovered.
*/
String get sdkVersion;
/**
* Return a list containing the library URI's for the libraries defined in
* this SDK.
*/
List<String> get uris;
/**
* Return a source representing the given 'file:' [uri] if the file is in this
* SDK, or `null` if the file is not in this SDK.
*/
Source fromFileUri(Uri uri);
/**
* Return the linked [PackageBundle] for this SDK, if it can be provided, or
* `null` otherwise.
*
* This is a temporary API, don't use it.
*/
PackageBundle getLinkedBundle();
/**
* Return the library representing the library with the given 'dart:' [uri],
* or `null` if the given URI does not denote a library in this SDK.
*/
SdkLibrary getSdkLibrary(String uri);
/**
* Return the source representing the library with the given 'dart:' [uri], or
* `null` if the given URI does not denote a library in this SDK.
*/
Source mapDartUri(String uri);
}
/**
* Manages the DartSdk's that have been created. Clients need to create multiple
* SDKs when the analysis options associated with those SDK's contexts will
* produce different analysis results.
*/
class DartSdkManager {
/**
* The absolute path to the directory containing the default SDK.
*/
final String defaultSdkDirectory;
/**
* A flag indicating whether it is acceptable to use summaries when they are
* available.
*/
final bool canUseSummaries;
/**
* A table mapping (an encoding of) analysis options and SDK locations to the
* DartSdk from that location that has been configured with those options.
*/
Map<SdkDescription, DartSdk> sdkMap = new HashMap<SdkDescription, DartSdk>();
/**
* Initialize a newly created manager.
*/
DartSdkManager(this.defaultSdkDirectory, this.canUseSummaries,
[dynamic ignored]);
/**
* Return any SDK that has been created, or `null` if no SDKs have been
* created.
*/
DartSdk get anySdk {
if (sdkMap.isEmpty) {
return null;
}
return sdkMap.values.first;
}
/**
* Return a list of the descriptors of the SDKs that are currently being
* managed.
*/
List<SdkDescription> get sdkDescriptors => sdkMap.keys.toList();
/**
* Return the Dart SDK that is appropriate for the given SDK [description].
* If such an SDK has not yet been created, then the [ifAbsent] function will
* be invoked to create it.
*/
DartSdk getSdk(SdkDescription description, DartSdk ifAbsent()) {
return sdkMap.putIfAbsent(description, ifAbsent);
}
}
/**
* A map from Dart library URI's to the [SdkLibraryImpl] representing that
* library.
*/
class LibraryMap {
/**
* A table mapping Dart library URI's to the library.
*/
LinkedHashMap<String, SdkLibraryImpl> _libraryMap =
new LinkedHashMap<String, SdkLibraryImpl>();
/**
* Return a list containing all of the sdk libraries in this mapping.
*/
List<SdkLibrary> get sdkLibraries => new List.from(_libraryMap.values);
/**
* Return a list containing the library URI's for which a mapping is available.
*/
List<String> get uris => _libraryMap.keys.toList();
/**
* Return the library with the given 'dart:' [uri], or `null` if the URI does
* not map to a library.
*/
SdkLibrary getLibrary(String uri) => _libraryMap[uri];
/**
* Set the library with the given 'dart:' [uri] to the given [library].
*/
void setLibrary(String dartUri, SdkLibraryImpl library) {
_libraryMap[dartUri] = library;
}
/**
* Return the number of library URI's for which a mapping is available.
*/
int size() => _libraryMap.length;
}
/**
* A description of a [DartSdk].
*/
class SdkDescription {
/**
* The paths to the files or directories that define the SDK.
*/
final List<String> paths;
/**
* The analysis options that will be used by the SDK's context.
*/
final AnalysisOptions options;
/**
* Initialize a newly created SDK description to describe an SDK based on the
* files or directories at the given [paths] that is analyzed using the given
* [options].
*/
SdkDescription(this.paths, this.options);
@override
int get hashCode {
int hashCode = 0;
for (int value in options.signature) {
hashCode = JenkinsSmiHash.combine(hashCode, value);
}
for (String path in paths) {
hashCode = JenkinsSmiHash.combine(hashCode, path.hashCode);
}
return JenkinsSmiHash.finish(hashCode);
}
@override
bool operator ==(Object other) {
if (other is SdkDescription) {
if (!AnalysisOptions.signaturesEqual(
options.signature, other.options.signature)) {
return false;
}
int length = paths.length;
if (other.paths.length != length) {
return false;
}
for (int i = 0; i < length; i++) {
if (other.paths[i] != paths[i]) {
return false;
}
}
return true;
}
return false;
}
@override
String toString() {
StringBuffer buffer = new StringBuffer();
bool needsSeparator = false;
void add(String optionName) {
if (needsSeparator) {
buffer.write(', ');
}
buffer.write(optionName);
needsSeparator = true;
}
for (String path in paths) {
add(path);
}
if (needsSeparator) {
buffer.write(' ');
}
buffer.write('(');
buffer.write(options.signature);
buffer.write(')');
return buffer.toString();
}
}
class SdkLibrariesReader_LibraryBuilder extends RecursiveAstVisitor<Object> {
/**
* The prefix added to the name of a library to form the URI used in code to
* reference the library.
*/
static String _LIBRARY_PREFIX = "dart:";
/**
* The name of the optional parameter used to indicate whether the library is
* an implementation library.
*/
static String _IMPLEMENTATION = "implementation";
/**
* The name of the optional parameter used to specify the path used when
* compiling for dart2js.
*/
static String _DART2JS_PATH = "dart2jsPath";
/**
* The name of the optional parameter used to indicate whether the library is
* documented.
*/
static String _DOCUMENTED = "documented";
/**
* The name of the optional parameter used to specify the category of the
* library.
*/
static String _CATEGORIES = "categories";
/**
* The name of the optional parameter used to specify the platforms on which
* the library can be used.
*/
static String _PLATFORMS = "platforms";
/**
* The value of the [PLATFORMS] parameter used to specify that the library can
* be used on the VM.
*/
static String _VM_PLATFORM = "VM_PLATFORM";
/**
* A flag indicating whether the dart2js path should be used when it is
* available.
*/
final bool _useDart2jsPaths;
/**
* The library map that is populated by visiting the AST structure parsed from
* the contents of the libraries file.
*/
LibraryMap _librariesMap = new LibraryMap();
/**
* Initialize a newly created library builder to use the dart2js path if
* [_useDart2jsPaths] is `true`.
*/
SdkLibrariesReader_LibraryBuilder(this._useDart2jsPaths);
/**
* Return the library map that was populated by visiting the AST structure
* parsed from the contents of the libraries file.
*/
LibraryMap get librariesMap => _librariesMap;
// To be backwards-compatible the new categories field is translated to
// an old approximation.
String convertCategories(String categories) {
switch (categories) {
case "":
return "Internal";
case "Client":
return "Client";
case "Server":
return "Server";
case "Client,Server":
return "Shared";
case "Client,Server,Embedded":
return "Shared";
}
return "Shared";
}
@override
Object visitMapLiteralEntry(MapLiteralEntry node) {
String libraryName = null;
Expression key = node.key;
if (key is SimpleStringLiteral) {
libraryName = "$_LIBRARY_PREFIX${key.value}";
}
Expression value = node.value;
if (value is InstanceCreationExpression) {
SdkLibraryImpl library = new SdkLibraryImpl(libraryName);
List<Expression> arguments = value.argumentList.arguments;
for (Expression argument in arguments) {
if (argument is SimpleStringLiteral) {
library.path = argument.value;
} else if (argument is NamedExpression) {
String name = argument.name.label.name;
Expression expression = argument.expression;
if (name == _CATEGORIES) {
library.category =
convertCategories((expression as StringLiteral).stringValue);
} else if (name == _IMPLEMENTATION) {
library._implementation = (expression as BooleanLiteral).value;
} else if (name == _DOCUMENTED) {
library.documented = (expression as BooleanLiteral).value;
} else if (name == _PLATFORMS) {
if (expression is SimpleIdentifier) {
String identifier = expression.name;
if (identifier == _VM_PLATFORM) {
library.setVmLibrary();
} else {
library.setDart2JsLibrary();
}
}
} else if (_useDart2jsPaths && name == _DART2JS_PATH) {
if (expression is SimpleStringLiteral) {
library.path = expression.value;
}
}
}
}
_librariesMap.setLibrary(libraryName, library);
}
return null;
}
}
/**
* Represents a single library in the SDK
*/
abstract class SdkLibrary {
/**
* Return the name of the category containing the library.
*/
String get category;
/**
* Return `true` if this library can be compiled to JavaScript by dart2js.
*/
bool get isDart2JsLibrary;
/**
* Return `true` if the library is documented.
*/
bool get isDocumented;
/**
* Return `true` if the library is an implementation library.
*/
bool get isImplementation;
/**
* Return `true` if library is internal can be used only by other SDK libraries.
*/
bool get isInternal;
/**
* Return `true` if this library can be used for both client and server.
*/
bool get isShared;
/**
* Return `true` if this library can be run on the VM.
*/
bool get isVmLibrary;
/**
* Return the path to the file defining the library. The path is relative to
* the `lib` directory within the SDK.
*/
String get path;
/**
* Return the short name of the library. This is the URI of the library,
* including `dart:`.
*/
String get shortName;
}
/**
* The information known about a single library within the SDK.
*/
class SdkLibraryImpl implements SdkLibrary {
/**
* The bit mask used to access the bit representing the flag indicating
* whether a library is intended to work on the dart2js platform.
*/
static int DART2JS_PLATFORM = 1;
/**
* The bit mask used to access the bit representing the flag indicating
* whether a library is intended to work on the VM platform.
*/
static int VM_PLATFORM = 2;
@override
final String shortName;
/**
* The path to the file defining the library. The path is relative to the
* 'lib' directory within the SDK.
*/
@override
String path = null;
/**
* The name of the category containing the library. Unless otherwise specified
* in the libraries file all libraries are assumed to be shared between server
* and client.
*/
@override
String category = "Shared";
/**
* A flag indicating whether the library is documented.
*/
bool _documented = true;
/**
* A flag indicating whether the library is an implementation library.
*/
bool _implementation = false;
/**
* An encoding of which platforms this library is intended to work on.
*/
int _platforms = 0;
/**
* Initialize a newly created library to represent the library with the given
* [name].
*/
SdkLibraryImpl(this.shortName);
/**
* Set whether the library is documented.
*/
void set documented(bool documented) {
this._documented = documented;
}
@override
bool get isDart2JsLibrary => (_platforms & DART2JS_PLATFORM) != 0;
@override
bool get isDocumented => _documented;
@override
bool get isImplementation => _implementation;
@override
bool get isInternal => category == "Internal";
@override
bool get isShared => category == "Shared";
@override
bool get isVmLibrary => (_platforms & VM_PLATFORM) != 0;
/**
* Record that this library can be compiled to JavaScript by dart2js.
*/
void setDart2JsLibrary() {
_platforms |= DART2JS_PLATFORM;
}
/**
* Record that this library can be run on the VM.
*/
void setVmLibrary() {
_platforms |= VM_PLATFORM;
}
}