Initial API to build analysis contexts (replaces ContextLocator.locateContexts)

Change-Id: If00ce6321efb6ff4da96e654cfe2a0a8501bed95
Reviewed-on: https://dart-review.googlesource.com/50323
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Brian Wilkerson
2018-04-10 15:48:10 +00:00
committed by commit-bot@chromium.org
parent 5ea271bb01
commit 7764e6962e
4 changed files with 236 additions and 0 deletions
@@ -0,0 +1,42 @@
// Copyright (c) 2018, 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/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/context_root.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/analysis/context_builder.dart';
import 'package:meta/meta.dart';
/**
* A utility class used to build an analysis context based on a context root.
*
* Clients may not extend, implement or mix-in this class.
*/
abstract class ContextBuilder {
/**
* Initialize a newly created context builder. If a [resourceProvider] is
* given, then it will be used to access the file system, otherwise the
* default resource provider will be used.
*/
factory ContextBuilder({ResourceProvider resourceProvider}) =
ContextBuilderImpl;
/**
* Return an analysis context corresponding to the given [contextRoot].
*
* If a set of [declaredVariables] is provided, the values will be used to map
* the the variable names found in `fromEnvironment` invocations to the
* constant value that will be returned. If none is given, then no variables
* will be defined.
*
* If an [sdkPath] is provided, and if it is a valid path to a directory
* containing a valid SDK, then the SDK in the referenced directory will be
* used when analyzing the code in the context.
*/
AnalysisContext createContext(
{@required ContextRoot contextRoot,
DeclaredVariables declaredVariables,
String sdkPath});
}
@@ -0,0 +1,101 @@
// Copyright (c) 2018, 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/context_root.dart' as old;
import 'package:analyzer/context/declared_variables.dart';
import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/context_builder.dart';
import 'package:analyzer/dart/analysis/context_root.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/context/builder.dart' as old
show ContextBuilder, ContextBuilderOptions;
import 'package:analyzer/src/dart/analysis/driver.dart'
show AnalysisDriver, AnalysisDriverScheduler;
import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart'
show FileContentOverlay;
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/sdk.dart' show DartSdkManager;
import 'package:analyzer/src/generated/source.dart' show ContentCache;
import 'package:front_end/src/base/performance_logger.dart' show PerformanceLog;
import 'package:front_end/src/byte_store/byte_store.dart' show MemoryByteStore;
import 'package:meta/meta.dart';
/**
* An implementation of a context builder.
*/
class ContextBuilderImpl implements ContextBuilder {
/**
* The resource provider used to access the file system.
*/
final ResourceProvider resourceProvider;
/**
* Initialize a newly created context builder. If a [resourceProvider] is
* given, then it will be used to access the file system, otherwise the
* default resource provider will be used.
*/
ContextBuilderImpl({ResourceProvider resourceProvider})
: resourceProvider =
resourceProvider ?? PhysicalResourceProvider.INSTANCE;
/**
* Return the path to the default location of the SDK, or `null` if the sdk
* cannot be found.
*/
String get _defaultSdkPath =>
FolderBasedDartSdk.defaultSdkDirectory(resourceProvider)?.path;
@override
AnalysisContext createContext(
{@required ContextRoot contextRoot,
DeclaredVariables declaredVariables,
String sdkPath}) {
PerformanceLog performanceLog = new PerformanceLog(new StringBuffer());
AnalysisDriverScheduler scheduler =
new AnalysisDriverScheduler(performanceLog);
sdkPath ??= _defaultSdkPath;
if (sdkPath == null) {
throw new ArgumentError('Cannot find path to the SDK');
}
DartSdkManager sdkManager = new DartSdkManager(sdkPath, true);
scheduler.start();
// TODO(brianwilkerson) Move the required implementation from the old
// ContextBuilder to this class and remove the old class.
old.ContextBuilderOptions options = new old.ContextBuilderOptions();
if (declaredVariables != null) {
options.declaredVariables = _toMap(declaredVariables);
}
options.defaultPackageFilePath = contextRoot.packagesFile?.path;
old.ContextBuilder builder = new old.ContextBuilder(
resourceProvider, sdkManager, new ContentCache(),
options: options);
builder.analysisDriverScheduler = scheduler;
builder.byteStore = new MemoryByteStore();
builder.fileContentOverlay = new FileContentOverlay();
builder.performanceLog = performanceLog;
old.ContextRoot oldContextRoot = new old.ContextRoot(
contextRoot.root.path, contextRoot.excludedPaths.toList());
AnalysisDriver driver = builder.buildDriver(oldContextRoot);
DriverBasedAnalysisContext context =
new DriverBasedAnalysisContext(resourceProvider, contextRoot, driver);
return context;
}
/**
* Convert the [declaredVariables] into a map for use with the old context
* builder.
*/
Map<String, String> _toMap(DeclaredVariables declaredVariables) {
Map<String, String> map = <String, String>{};
for (String name in declaredVariables.variableNames) {
map[name] = declaredVariables.get(name);
}
return map;
}
}
@@ -0,0 +1,91 @@
// Copyright (c) 2018, 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:io' as io;
import 'package:analyzer/context/declared_variables.dart';
import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/context_root.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/analysis/context_builder.dart';
import 'package:analyzer/src/dart/analysis/context_root.dart';
import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../context/mock_sdk.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ContextBuilderImplTest);
});
}
@reflectiveTest
class ContextBuilderImplTest extends Object with ResourceProviderMixin {
ContextBuilderImpl contextBuilder;
ContextRoot contextRoot;
void assertEquals(DeclaredVariables actual, DeclaredVariables expected) {
Iterable<String> actualNames = actual.variableNames;
Iterable<String> expectedNames = expected.variableNames;
expect(actualNames, expectedNames);
for (String name in expectedNames) {
expect(actual.get(name), expected.get(name));
}
}
void setUp() {
resourceProvider.newFolder(resourceProvider.pathContext.dirname(
resourceProvider.pathContext.dirname(io.Platform.resolvedExecutable)));
contextBuilder = new ContextBuilderImpl(resourceProvider: resourceProvider);
String path = resourceProvider.convertPath('/temp/root');
Folder folder = resourceProvider.newFolder(path);
contextRoot = new ContextRootImpl(resourceProvider, folder);
}
test_createContext_declaredVariables() {
DeclaredVariables declaredVariables = new DeclaredVariables();
declaredVariables.define('foo', 'true');
DriverBasedAnalysisContext context = contextBuilder.createContext(
contextRoot: contextRoot, declaredVariables: declaredVariables);
expect(context.analysisOptions, isNotNull);
expect(context.contextRoot, contextRoot);
assertEquals(context.driver.declaredVariables, declaredVariables);
}
test_createContext_declaredVariables_sdkPath() {
DeclaredVariables declaredVariables = new DeclaredVariables();
declaredVariables.define('bar', 'true');
MockSdk sdk = new MockSdk(resourceProvider: resourceProvider);
DriverBasedAnalysisContext context = contextBuilder.createContext(
contextRoot: contextRoot,
declaredVariables: declaredVariables,
sdkPath: sdkRoot);
expect(context.analysisOptions, isNotNull);
expect(context.contextRoot, contextRoot);
assertEquals(context.driver.declaredVariables, declaredVariables);
expect(context.driver.sourceFactory.dartSdk.mapDartUri('dart:core'),
sdk.mapDartUri('dart:core'));
}
test_createContext_defaults() {
AnalysisContext context =
contextBuilder.createContext(contextRoot: contextRoot);
expect(context.analysisOptions, isNotNull);
expect(context.contextRoot, contextRoot);
}
test_createContext_sdkPath() {
String sdkPath = resourceProvider.convertPath('/path/to/sdk');
resourceProvider.newFolder(sdkPath);
AnalysisContext context = contextBuilder.createContext(
contextRoot: contextRoot, sdkPath: sdkPath);
expect(context.analysisOptions, isNotNull);
expect(context.contextRoot, contextRoot);
// TODO(brianwilkerson) We don't currently have a way to test whether the
// sdkPath is being handled correctly.
}
}
@@ -4,6 +4,7 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'context_builder_test.dart' as context_builder_test;
import 'context_locator_test.dart' as context_locator_test;
import 'context_root_test.dart' as context_root_test;
import 'defined_names_test.dart' as defined_names_test;
@@ -21,6 +22,7 @@ import 'session_test.dart' as session_test;
main() {
defineReflectiveSuite(() {
context_builder_test.main();
context_locator_test.main();
context_root_test.main();
defined_names_test.main();