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:
Konstantin Shcheglov
2015-12-21 10:27:24 -08:00
parent 811bcd11bf
commit f5963da1d5
3 changed files with 134 additions and 28 deletions
+2 -2
View File
@@ -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) =>
+47 -13
View File
@@ -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);
+85 -13
View File
@@ -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.
*/