blob: 5fe2dd40562c975758243b6056a4309fefe7841d [file] [log] [blame]
// Copyright (c) 2019, 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:_fe_analyzer_shared/src/sdk/allowed_experiments.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/context/packages.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/util/uri.dart';
import 'package:meta/meta.dart';
import 'package:pub_semver/pub_semver.dart';
class FeatureSetProvider {
/// This flag will be turned to `true` and inlined when we un-fork SDK,
/// so that the only SDK is the Null Safe SDK.
static const isNullSafetySdk = true;
final AllowedExperiments _allowedExperiments;
final ResourceProvider _resourceProvider;
final Packages _packages;
final FeatureSet _packageDefaultFeatureSet;
final FeatureSet _nonPackageDefaultFeatureSet;
FeatureSetProvider._({
@required AllowedExperiments allowedExperiments,
@required ResourceProvider resourceProvider,
@required Packages packages,
@required FeatureSet packageDefaultFeatureSet,
@required FeatureSet nonPackageDefaultFeatureSet,
}) : _allowedExperiments = allowedExperiments,
_resourceProvider = resourceProvider,
_packages = packages,
_packageDefaultFeatureSet = packageDefaultFeatureSet,
_nonPackageDefaultFeatureSet = nonPackageDefaultFeatureSet;
/// Return the [FeatureSet] for the package that contains the file.
FeatureSet getFeatureSet(String path, 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);
} else {
return FeatureSet.fromEnableFlags([]);
}
}
var package = _findPackage(uri, path);
if (package != null) {
var experiments = _allowedExperiments.forPackage(package.name);
if (experiments != null) {
return FeatureSet.fromEnableFlags(experiments);
}
return _packageDefaultFeatureSet;
}
return _nonPackageDefaultFeatureSet;
}
/// Return the language version for the package that contains the file.
///
/// Each individual file might use `// @dart` to override this version, to
/// be either lower, or higher than the package language version.
Version getLanguageVersion(String path, Uri uri) {
if (uri.isScheme('dart')) {
return ExperimentStatus.currentVersion;
}
var package = _findPackage(uri, path);
if (package != null) {
var languageVersion = package.languageVersion;
if (languageVersion != null) {
return languageVersion;
}
}
return ExperimentStatus.currentVersion;
}
/// Return the package corresponding to the [uri] or [path], `null` if none.
Package _findPackage(Uri uri, String path) {
if (uri.isScheme('package')) {
var pathSegments = uri.pathSegments;
if (pathSegments.isNotEmpty) {
var packageName = pathSegments.first;
var package = _packages[packageName];
if (package != null) {
return package;
}
}
} else if (uri.isScheme('file')) {
var uriPath = fileUriToNormalizedPath(_resourceProvider.pathContext, uri);
var package = _packages.packageForPath(uriPath);
if (package != null) {
return package;
}
}
return _packages.packageForPath(path);
}
static FeatureSetProvider build({
@required SourceFactory sourceFactory,
@required ResourceProvider resourceProvider,
@required Packages packages,
@required FeatureSet packageDefaultFeatureSet,
@required FeatureSet nonPackageDefaultFeatureSet,
}) {
var allowedExperiments = _experimentsForSdk(sourceFactory.dartSdk);
return FeatureSetProvider._(
allowedExperiments: allowedExperiments,
resourceProvider: resourceProvider,
packages: packages,
packageDefaultFeatureSet: packageDefaultFeatureSet,
nonPackageDefaultFeatureSet: nonPackageDefaultFeatureSet,
);
}
static AllowedExperiments _experimentsForSdk(DartSdk sdk) {
var experimentsContent = sdk.allowedExperimentsJson;
if (experimentsContent != null) {
try {
return parseAllowedExperiments(experimentsContent);
} catch (_) {}
}
return AllowedExperiments(
sdkDefaultExperiments: [],
sdkLibraryExperiments: {},
packageExperiments: {},
);
}
}