Skip to content

Commit

Permalink
Add buildSdkSummary() to analyzer API.
Browse files Browse the repository at this point in the history
R=brianwilkerson@google.com

Bug: dart-lang/build#2745 (comment)
Change-Id: I144dd99be5e5a210e27f3b5b5b54951659479511
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/153384
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
  • Loading branch information
scheglov authored and commit-bot@chromium.org committed Jul 6, 2020
1 parent 431b57c commit 11632ff
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 244 deletions.
3 changes: 3 additions & 0 deletions pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,6 @@
## 0.39.13-dev
* Added 'dart/sdk/build_sdk_summary.dart' with `buildSdkSummary`.

## 0.39.12
* Deprecated `canUseSummaries` in `DartSdkManager` constructor.
Summaries are not supported this way for SDK.
Expand Down
192 changes: 192 additions & 0 deletions pkg/analyzer/lib/dart/sdk/build_sdk_summary.dart
@@ -0,0 +1,192 @@
// Copyright (c) 2020, 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:typed_data';

import 'package:_fe_analyzer_shared/src/sdk/allowed_experiments.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/utilities.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/summarize_elements.dart';
import 'package:analyzer/src/summary2/link.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/reference.dart';
import 'package:meta/meta.dart';
import 'package:yaml/yaml.dart';

/// Build summary for SDK at the given [sdkPath].
///
/// If [embedderYamlPath] is provided, then libraries from this file are
/// appended to the libraries of the specified SDK.
Uint8List buildSdkSummary({
@required ResourceProvider resourceProvider,
@required String sdkPath,
String embedderYamlPath,
}) {
var sdk = FolderBasedDartSdk(
resourceProvider,
resourceProvider.getFolder(sdkPath),
);
sdk.analysisOptions = AnalysisOptionsImpl();

// Append libraries from the embedder.
if (embedderYamlPath != null) {
var file = resourceProvider.getFile(embedderYamlPath);
var content = file.readAsStringSync();
var map = loadYaml(content) as YamlMap;
var embedderSdk = EmbedderSdk(resourceProvider, {file.parent: map});
for (var library in embedderSdk.sdkLibraries) {
var uriStr = library.shortName;
if (sdk.libraryMap.getLibrary(uriStr) == null) {
sdk.libraryMap.setLibrary(uriStr, library);
}
}
}

var librarySources = sdk.sdkLibraries.map((e) {
return sdk.mapDartUri(e.shortName);
}).toList();

return _Builder(
sdk.context,
sdk.allowedExperimentsJson,
librarySources,
).build();
}

class _Builder {
final AnalysisContext context;
final String allowedExperimentsJson;
final Iterable<Source> librarySources;

final Set<String> libraryUris = <String>{};
final List<LinkInputLibrary> inputLibraries = [];

AllowedExperiments allowedExperiments;
final PackageBundleAssembler bundleAssembler = PackageBundleAssembler();

_Builder(
this.context,
this.allowedExperimentsJson,
this.librarySources,
) {
allowedExperiments = _parseAllowedExperiments(allowedExperimentsJson);
}

/// Build the linked bundle and return its bytes.
Uint8List build() {
librarySources.forEach(_addLibrary);

var elementFactory = LinkedElementFactory(
context,
AnalysisSessionImpl(null),
Reference.root(),
);

var linkResult = link(elementFactory, inputLibraries);
bundleAssembler.setBundle2(linkResult.bundle);

var buffer = PackageBundleBuilder(
bundle2: linkResult.bundle,
sdk: PackageBundleSdkBuilder(
allowedExperimentsJson: allowedExperimentsJson,
),
).toBuffer();

return buffer is Uint8List ? buffer : Uint8List.fromList(buffer);
}

void _addLibrary(Source source) {
String uriStr = source.uri.toString();
if (!libraryUris.add(uriStr)) {
return;
}

var inputUnits = <LinkInputUnit>[];

CompilationUnit definingUnit = _parse(source);
inputUnits.add(
LinkInputUnit(null, source, false, definingUnit),
);

for (Directive directive in definingUnit.directives) {
if (directive is NamespaceDirective) {
String libUri = directive.uri.stringValue;
Source libSource = context.sourceFactory.resolveUri(source, libUri);
_addLibrary(libSource);
} else if (directive is PartDirective) {
String partUri = directive.uri.stringValue;
Source partSource = context.sourceFactory.resolveUri(source, partUri);
CompilationUnit partUnit = _parse(partSource);
inputUnits.add(
LinkInputUnit(partUri, partSource, false, partUnit),
);
}
}

inputLibraries.add(
LinkInputLibrary(source, inputUnits),
);
}

/// Return the [FeatureSet] for the given [uri], must be a `dart:` URI.
FeatureSet _featureSet(Uri uri) {
if (uri.isScheme('dart')) {
var pathSegments = uri.pathSegments;
if (pathSegments.isNotEmpty) {
var libraryName = pathSegments.first;
var experiments = allowedExperiments.forSdkLibrary(libraryName);
return FeatureSet.fromEnableFlags(experiments);
}
}
throw StateError('Expected a valid dart: URI: $uri');
}

CompilationUnit _parse(Source source) {
var result = parseString(
content: source.contents.data,
featureSet: _featureSet(source.uri),
throwIfDiagnostics: false,
);

if (result.errors.isNotEmpty) {
var errorsStr = result.errors.map((e) {
var location = result.lineInfo.getLocation(e.offset);
return '${source.fullName}:$location - ${e.message}';
}).join('\n');
throw StateError(
'Unexpected diagnostics:\n$errorsStr',
);
}

var unit = result.unit as CompilationUnitImpl;
unit.languageVersion = LibraryLanguageVersion(
package: ExperimentStatus.currentVersion,
override: null,
);

return result.unit;
}

static AllowedExperiments _parseAllowedExperiments(String content) {
if (content == null) {
return AllowedExperiments(
sdkDefaultExperiments: [],
sdkLibraryExperiments: {},
packageExperiments: {},
);
}

return parseAllowedExperiments(content);
}
}

0 comments on commit 11632ff

Please sign in to comment.