ResultProvider - an alternative source of analysis results.
I don't like the name, so I'm open to any ideas. R=brianwilkerson@google.com, paulberry@google.com BUG= Review URL: https://codereview.chromium.org/1539093002 .
This commit is contained in:
@@ -1299,8 +1299,8 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
|
||||
PropertyAccessorMember.from(element.getGetter(getterName), this);
|
||||
|
||||
@override
|
||||
MethodElement getMethod(String methodName) =>
|
||||
MethodMember.from(element.getMethod(methodName), this);
|
||||
MethodElement getMethod(String methodName) => MethodMember.from(
|
||||
(element as ClassElementImpl).getMethod(methodName), this);
|
||||
|
||||
@override
|
||||
PropertyAccessorElement getSetter(String setterName) =>
|
||||
|
||||
@@ -43,6 +43,11 @@ class AnalysisDriver {
|
||||
*/
|
||||
final InternalAnalysisContext context;
|
||||
|
||||
/**
|
||||
* The alternative source of analysis results.
|
||||
*/
|
||||
ResultProvider resultProvider;
|
||||
|
||||
/**
|
||||
* The map of [ComputedResult] controllers.
|
||||
*/
|
||||
@@ -167,8 +172,8 @@ class AnalysisDriver {
|
||||
}
|
||||
TaskDescriptor taskDescriptor = taskManager.findTask(target, result);
|
||||
try {
|
||||
WorkItem workItem =
|
||||
new WorkItem(context, target, taskDescriptor, result, 0, null);
|
||||
WorkItem workItem = new WorkItem(
|
||||
context, resultProvider, target, taskDescriptor, result, 0, null);
|
||||
return new WorkOrder(taskManager, workItem);
|
||||
} catch (exception, stackTrace) {
|
||||
throw new AnalysisException(
|
||||
@@ -504,7 +509,25 @@ class InfiniteTaskLoopException extends AnalysisException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Object used by CycleAwareDependencyWalker to report a single strongly
|
||||
* The object used by [WorkItem] to get values without using tasks.
|
||||
*/
|
||||
abstract class ResultProvider {
|
||||
/**
|
||||
* [WorkItem] calls this method when the [result] of the [entry] is
|
||||
* [CacheState.INVALID], so it is about to schedule its computation.
|
||||
*
|
||||
* If the provider knows how to provide the value, it sets the value into
|
||||
* the [entry] with all required dependencies, and returns `true`.
|
||||
*
|
||||
* Otherwise, it returns `false` to indicate that the [WorkItem] should
|
||||
* compute the value.
|
||||
*/
|
||||
bool provideResult(InternalAnalysisContext context, CacheEntry entry,
|
||||
ResultDescriptor result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Object used by [CycleAwareDependencyWalker] to report a single strongly
|
||||
* connected component of nodes.
|
||||
*/
|
||||
class StronglyConnectedComponent<Node> {
|
||||
@@ -534,6 +557,11 @@ class WorkItem {
|
||||
*/
|
||||
final InternalAnalysisContext context;
|
||||
|
||||
/**
|
||||
* The alternative source of analysis results.
|
||||
*/
|
||||
final ResultProvider resultProvider;
|
||||
|
||||
/**
|
||||
* The target for which a task is to be performed.
|
||||
*/
|
||||
@@ -597,8 +625,8 @@ class WorkItem {
|
||||
* Initialize a newly created work item to compute the inputs for the task
|
||||
* described by the given descriptor.
|
||||
*/
|
||||
WorkItem(this.context, this.target, this.descriptor, this.spawningResult,
|
||||
this.level, this.workOrder) {
|
||||
WorkItem(this.context, this.resultProvider, this.target, this.descriptor,
|
||||
this.spawningResult, this.level, this.workOrder) {
|
||||
AnalysisTarget actualTarget =
|
||||
identical(target, AnalysisContextTarget.request)
|
||||
? new AnalysisContextTarget(context)
|
||||
@@ -702,14 +730,20 @@ class WorkItem {
|
||||
//
|
||||
throw new UnimplementedError();
|
||||
} else if (inputState != CacheState.VALID) {
|
||||
try {
|
||||
TaskDescriptor descriptor =
|
||||
taskManager.findTask(inputTarget, inputResult);
|
||||
return new WorkItem(context, inputTarget, descriptor, inputResult,
|
||||
level + 1, workOrder);
|
||||
} on AnalysisException catch (exception, stackTrace) {
|
||||
this.exception = new CaughtException(exception, stackTrace);
|
||||
return null;
|
||||
if (resultProvider != null &&
|
||||
resultProvider.provideResult(context, inputEntry, inputResult)) {
|
||||
inputState = CacheState.VALID;
|
||||
builder.currentValue = inputEntry.getValue(inputResult);
|
||||
} else {
|
||||
try {
|
||||
TaskDescriptor descriptor =
|
||||
taskManager.findTask(inputTarget, inputResult);
|
||||
return new WorkItem(context, resultProvider, inputTarget,
|
||||
descriptor, inputResult, level + 1, workOrder);
|
||||
} on AnalysisException catch (exception, stackTrace) {
|
||||
this.exception = new CaughtException(exception, stackTrace);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
builder.currentValue = inputEntry.getValue(inputResult);
|
||||
|
||||
@@ -344,7 +344,8 @@ class AnalysisDriverTest extends AbstractDriverTest {
|
||||
'task', (context, target) => task, (target) => {}, [result]);
|
||||
task = new TestAnalysisTask(context, target,
|
||||
descriptor: descriptor, value: 42);
|
||||
WorkItem item = new WorkItem(context, target, descriptor, null, 0, null);
|
||||
WorkItem item =
|
||||
new WorkItem(context, null, target, descriptor, null, 0, null);
|
||||
|
||||
bool streamNotified = false;
|
||||
analysisDriver.onResultComputed(result).listen((event) {
|
||||
@@ -368,7 +369,8 @@ class AnalysisDriverTest extends AbstractDriverTest {
|
||||
'task', (context, target) => task, (target) => {}, [result]);
|
||||
task = new TestAnalysisTask(context, target,
|
||||
descriptor: descriptor, exception: exception);
|
||||
WorkItem item = new WorkItem(context, target, descriptor, null, 0, null);
|
||||
WorkItem item =
|
||||
new WorkItem(context, null, target, descriptor, null, 0, null);
|
||||
|
||||
analysisDriver.performWorkItem(item);
|
||||
CacheEntry targetEntry = context.getCacheEntry(item.target);
|
||||
@@ -383,7 +385,8 @@ class AnalysisDriverTest extends AbstractDriverTest {
|
||||
TaskDescriptor descriptor = new TaskDescriptor(
|
||||
'task', (context, target) => task, (target) => {}, [result]);
|
||||
task = new TestAnalysisTask(context, target, descriptor: descriptor);
|
||||
WorkItem item = new WorkItem(context, target, descriptor, null, 0, null);
|
||||
WorkItem item =
|
||||
new WorkItem(context, null, target, descriptor, null, 0, null);
|
||||
|
||||
analysisDriver.performWorkItem(item);
|
||||
CacheEntry targetEntry = context.getCacheEntry(item.target);
|
||||
@@ -401,7 +404,8 @@ class AnalysisDriverTest extends AbstractDriverTest {
|
||||
[result]);
|
||||
CaughtException exception =
|
||||
new CaughtException(new AnalysisException(), null);
|
||||
WorkItem item = new WorkItem(context, target, descriptor, null, 0, null);
|
||||
WorkItem item =
|
||||
new WorkItem(context, null, target, descriptor, null, 0, null);
|
||||
item.exception = exception;
|
||||
|
||||
analysisDriver.performWorkItem(item);
|
||||
@@ -418,7 +422,7 @@ class AnalysisDriverTest extends AbstractDriverTest {
|
||||
(target) => {'one': inputResult.of(target)},
|
||||
[new ResultDescriptor('output', null)]);
|
||||
analysisDriver.currentWorkOrder = new WorkOrder(
|
||||
taskManager, new WorkItem(null, null, descriptor, null, 0, null));
|
||||
taskManager, new WorkItem(null, null, null, descriptor, null, 0, null));
|
||||
|
||||
analysisDriver.reset();
|
||||
expect(analysisDriver.currentWorkOrder, isNull);
|
||||
@@ -616,7 +620,8 @@ class WorkItemTest extends AbstractDriverTest {
|
||||
(context, target) => new TestAnalysisTask(context, target),
|
||||
(target) => {},
|
||||
[new ResultDescriptor('output', null)]);
|
||||
WorkItem item = new WorkItem(context, target, descriptor, null, 0, null);
|
||||
WorkItem item =
|
||||
new WorkItem(context, null, target, descriptor, null, 0, null);
|
||||
AnalysisTask task = item.buildTask();
|
||||
expect(task, isNotNull);
|
||||
}
|
||||
@@ -633,7 +638,8 @@ class WorkItemTest extends AbstractDriverTest {
|
||||
new TestAnalysisTask(context, target, results: outputResults),
|
||||
(target) => {'one': inputResult.of(target)},
|
||||
outputResults);
|
||||
WorkItem item = new WorkItem(context, target, descriptor, null, 0, null);
|
||||
WorkItem item =
|
||||
new WorkItem(context, null, target, descriptor, null, 0, null);
|
||||
expect(() => item.buildTask(), throwsStateError);
|
||||
}
|
||||
|
||||
@@ -641,7 +647,8 @@ class WorkItemTest extends AbstractDriverTest {
|
||||
AnalysisTarget target = new TestSource();
|
||||
TaskDescriptor descriptor = new TaskDescriptor(
|
||||
'task', null, (target) => {}, [new ResultDescriptor('result', null)]);
|
||||
WorkItem item = new WorkItem(context, target, descriptor, null, 0, null);
|
||||
WorkItem item =
|
||||
new WorkItem(context, null, target, descriptor, null, 0, null);
|
||||
expect(item, isNotNull);
|
||||
expect(item.context, context);
|
||||
expect(item.descriptor, descriptor);
|
||||
@@ -655,7 +662,8 @@ class WorkItemTest extends AbstractDriverTest {
|
||||
(context, target) => new TestAnalysisTask(context, target),
|
||||
(target) => {},
|
||||
[new ResultDescriptor('output', null)]);
|
||||
WorkItem item = new WorkItem(context, target, descriptor, null, 0, null);
|
||||
WorkItem item =
|
||||
new WorkItem(context, null, target, descriptor, null, 0, null);
|
||||
WorkItem result = item.gatherInputs(taskManager, []);
|
||||
expect(result, isNull);
|
||||
expect(item.exception, isNull);
|
||||
@@ -680,7 +688,7 @@ class WorkItemTest extends AbstractDriverTest {
|
||||
taskManager.addTaskDescriptor(task1);
|
||||
taskManager.addTaskDescriptor(task2);
|
||||
// gather inputs
|
||||
WorkItem item = new WorkItem(context, target, task2, null, 0, null);
|
||||
WorkItem item = new WorkItem(context, null, target, task2, null, 0, null);
|
||||
WorkItem inputItem = item.gatherInputs(taskManager, []);
|
||||
expect(inputItem, isNotNull);
|
||||
}
|
||||
@@ -693,11 +701,72 @@ class WorkItemTest extends AbstractDriverTest {
|
||||
(context, target) => new TestAnalysisTask(context, target),
|
||||
(target) => {'one': inputResult.of(target)},
|
||||
[new ResultDescriptor('output', null)]);
|
||||
WorkItem item = new WorkItem(context, target, descriptor, null, 0, null);
|
||||
WorkItem item =
|
||||
new WorkItem(context, null, target, descriptor, null, 0, null);
|
||||
WorkItem result = item.gatherInputs(taskManager, []);
|
||||
expect(result, isNull);
|
||||
expect(item.exception, isNotNull);
|
||||
}
|
||||
|
||||
test_gatherInputs_useResultProvider_hasResult() {
|
||||
AnalysisTarget target = new TestSource();
|
||||
ResultDescriptor resultA = new ResultDescriptor('resultA', null);
|
||||
ResultDescriptor resultB = new ResultDescriptor('resultB', null);
|
||||
// prepare tasks
|
||||
TaskDescriptor task1 = new TaskDescriptor(
|
||||
'task',
|
||||
(context, target) =>
|
||||
new TestAnalysisTask(context, target, results: [resultA]),
|
||||
(target) => {},
|
||||
[resultA]);
|
||||
TaskDescriptor task2 = new TaskDescriptor(
|
||||
'task',
|
||||
(context, target) => new TestAnalysisTask(context, target),
|
||||
(target) => {'one': resultA.of(target)},
|
||||
[resultB]);
|
||||
taskManager.addTaskDescriptor(task1);
|
||||
taskManager.addTaskDescriptor(task2);
|
||||
// configure ResultProvider
|
||||
ResultProvider resultProvider = new _ResultProviderMock();
|
||||
when(resultProvider.provideResult(context, anyObject, resultA))
|
||||
.thenReturn(true);
|
||||
// gather inputs
|
||||
WorkItem item =
|
||||
new WorkItem(context, resultProvider, target, task2, null, 0, null);
|
||||
WorkItem inputItem = item.gatherInputs(taskManager, []);
|
||||
expect(inputItem, isNull);
|
||||
}
|
||||
|
||||
test_gatherInputs_useResultProvider_noResult() {
|
||||
AnalysisTarget target = new TestSource();
|
||||
ResultDescriptor resultA = new ResultDescriptor('resultA', null);
|
||||
ResultDescriptor resultB = new ResultDescriptor('resultB', null);
|
||||
// prepare tasks
|
||||
TaskDescriptor task1 = new TaskDescriptor(
|
||||
'task',
|
||||
(context, target) =>
|
||||
new TestAnalysisTask(context, target, results: [resultA]),
|
||||
(target) => {},
|
||||
[resultA]);
|
||||
TaskDescriptor task2 = new TaskDescriptor(
|
||||
'task',
|
||||
(context, target) => new TestAnalysisTask(context, target),
|
||||
(target) => {'one': resultA.of(target)},
|
||||
[resultB]);
|
||||
taskManager.addTaskDescriptor(task1);
|
||||
taskManager.addTaskDescriptor(task2);
|
||||
// configure ResultProvider
|
||||
ResultProvider resultProvider = new _ResultProviderMock();
|
||||
when(resultProvider.provideResult(anyObject, anyObject, anyObject))
|
||||
.thenReturn(false);
|
||||
// gather inputs
|
||||
WorkItem item =
|
||||
new WorkItem(context, resultProvider, target, task2, null, 0, null);
|
||||
WorkItem inputItem = item.gatherInputs(taskManager, []);
|
||||
expect(inputItem, isNotNull);
|
||||
expect(inputItem.target, target);
|
||||
expect(inputItem.descriptor, task1);
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
@@ -707,7 +776,7 @@ class WorkOrderTest extends EngineTestCase {
|
||||
TaskDescriptor descriptor = new TaskDescriptor(
|
||||
'task', null, (_) => {}, [new ResultDescriptor('result', null)]);
|
||||
WorkOrder order = new WorkOrder(
|
||||
manager, new WorkItem(null, null, descriptor, null, 0, null));
|
||||
manager, new WorkItem(null, null, null, descriptor, null, 0, null));
|
||||
expect(order, isNotNull);
|
||||
expect(order.currentItems, isNull);
|
||||
expect(order.current, isNull);
|
||||
@@ -717,7 +786,8 @@ class WorkOrderTest extends EngineTestCase {
|
||||
TaskManager manager = new TaskManager();
|
||||
TaskDescriptor descriptor = new TaskDescriptor(
|
||||
'task', null, (_) => {}, [new ResultDescriptor('result', null)]);
|
||||
WorkItem workItem = new WorkItem(null, null, descriptor, null, 0, null);
|
||||
WorkItem workItem =
|
||||
new WorkItem(null, null, null, descriptor, null, 0, null);
|
||||
WorkOrder order = new WorkOrder(manager, workItem);
|
||||
// "item" has no child items
|
||||
expect(order.moveNext(), isTrue);
|
||||
@@ -757,6 +827,8 @@ class _InternalAnalysisContextMock extends TypedMock
|
||||
}
|
||||
}
|
||||
|
||||
class _ResultProviderMock extends TypedMock implements ResultProvider {}
|
||||
|
||||
/**
|
||||
* Concrete class for testing [CycleAwareDependencyWalker] behavior.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user