Index: pkg/analyzer/lib/src/task/dart.dart |
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart |
index 1d9850e0ebab908e248cdb9fa0551867cc06dfbd..2a0815c95129c49f673bd02319741249d6c2a5ee 100644 |
--- a/pkg/analyzer/lib/src/task/dart.dart |
+++ b/pkg/analyzer/lib/src/task/dart.dart |
@@ -14,6 +14,7 @@ import 'package:analyzer/src/generated/engine.dart' |
hide AnalysisCache, AnalysisTask; |
import 'package:analyzer/src/generated/error.dart'; |
import 'package:analyzer/src/generated/error_verifier.dart'; |
+import 'package:analyzer/src/generated/incremental_resolver.dart'; |
import 'package:analyzer/src/generated/java_engine.dart'; |
import 'package:analyzer/src/generated/parser.dart'; |
import 'package:analyzer/src/generated/resolver.dart'; |
@@ -185,6 +186,14 @@ final ListResultDescriptor<VariableElement> INFERABLE_STATIC_VARIABLES_IN_UNIT = |
'INFERABLE_STATIC_VARIABLES_IN_UNIT', null); |
/** |
+ * An inferrable static variable ([VariableElement]) whose type has been |
+ * inferred. |
+ */ |
+final ResultDescriptor<VariableElement> INFERRED_STATIC_VARIABLE = |
+ new ResultDescriptor<VariableElement>('INFERRED_STATIC_VARIABLE', null, |
+ cachingPolicy: ELEMENT_CACHING_POLICY); |
+ |
+/** |
* The partial [LibraryElement] associated with a library. |
* |
* The [LibraryElement] and its [CompilationUnitElement]s are attached to each |
@@ -1673,7 +1682,7 @@ class ComputeInferableStaticVariableDependenciesTask |
// |
// Record outputs. |
// |
- outputs[INFERABLE_STATIC_VARIABLE_DEPENDENCIES] = gatherer.results; |
+ outputs[INFERABLE_STATIC_VARIABLE_DEPENDENCIES] = gatherer.results.toList(); |
} |
/** |
@@ -2401,6 +2410,227 @@ class GenerateHintsTask extends SourceBasedAnalysisTask { |
} |
/** |
+ * An abstract class that defines utility methods that are useful for tasks |
+ * operating on static variables. |
+ */ |
+abstract class InferStaticVariableTask extends ConstantEvaluationAnalysisTask { |
+ InferStaticVariableTask( |
+ InternalAnalysisContext context, VariableElement variable) |
+ : super(context, variable); |
+ |
+ /** |
+ * Return the declaration of the target within the given compilation [unit]. |
+ * Throw an exception if the declaration cannot be found. |
+ */ |
+ VariableDeclaration getDeclaration(CompilationUnit unit) { |
+ VariableElement variable = target; |
+ NodeLocator locator = new NodeLocator(variable.nameOffset); |
+ AstNode node = locator.searchWithin(unit); |
+ VariableDeclaration declaration = |
+ node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration); |
+ if (declaration == null || declaration.name != node) { |
+ throw new AnalysisException( |
+ "Failed to find the declaration of the variable ${variable.displayName} in ${variable.source}"); |
+ } |
+ return declaration; |
+ } |
+} |
+ |
+/** |
+ * A task that ensures that all of the inferrable static variables in a |
+ * compilation unit have had their type inferred. |
+ */ |
+class InferStaticVariableTypesInUnitTask extends SourceBasedAnalysisTask { |
Paul Berry
2015/08/29 01:14:55
Since this task has dependencies which are other s
Brian Wilkerson
2015/08/31 15:08:52
Sorry, I should have included this in a comment, b
Paul Berry
2015/08/31 15:50:59
Acknowledged.
|
+ /** |
+ * The name of the input whose value is the [RESOLVED_UNIT5] for the |
+ * compilation unit. |
+ */ |
+ static const String UNIT_INPUT = 'UNIT_INPUT'; |
+ |
+ /** |
+ * The name of the input whose value is a list of the inferrable static |
+ * variables whose types have been computed. |
+ */ |
+ static const String INFERRED_VARIABLES_INPUT = 'INFERRED_VARIABLES_INPUT'; |
+ |
+ /** |
+ * The task descriptor describing this kind of task. |
+ */ |
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
+ 'InferStaticVariableTypesInUnitTask', |
+ createTask, |
+ buildInputs, |
+ <ResultDescriptor>[RESOLVED_UNIT6]); |
+ |
+ /** |
+ * Initialize a newly created task to build a library element for the given |
+ * [unit] in the given [context]. |
+ */ |
+ InferStaticVariableTypesInUnitTask( |
+ InternalAnalysisContext context, LibrarySpecificUnit unit) |
+ : super(context, unit); |
+ |
+ @override |
+ TaskDescriptor get descriptor => DESCRIPTOR; |
+ |
+ @override |
+ void internalPerform() { |
+ // |
+ // Prepare inputs. |
+ // |
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
+ // |
+ // Record outputs. There is no additional work to be done at this time |
+ // because the work has implicitly been done by virtue of the task model |
+ // preparing all of the inputs. |
+ // |
+ outputs[RESOLVED_UNIT6] = unit; |
+ } |
+ |
+ /** |
+ * Return a map from the names of the inputs of this kind of task to the task |
+ * input descriptors describing those inputs for a task with the given |
+ * [libSource]. |
+ */ |
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
+ LibrarySpecificUnit unit = target; |
+ return <String, TaskInput>{ |
+ INFERRED_VARIABLES_INPUT: INFERABLE_STATIC_VARIABLES_IN_UNIT |
+ .of(unit) |
+ .toListOf(INFERRED_STATIC_VARIABLE), |
+ UNIT_INPUT: RESOLVED_UNIT5.of(unit) |
+ }; |
+ } |
+ |
+ /** |
+ * Create a [InferStaticVariableTypesInUnitTask] based on the given [target] in the |
+ * given [context]. |
+ */ |
+ static InferStaticVariableTypesInUnitTask createTask( |
+ AnalysisContext context, AnalysisTarget target) { |
+ return new InferStaticVariableTypesInUnitTask(context, target); |
+ } |
+} |
+ |
+/** |
+ * A task that computes the type of an inferrable static variable and |
+ * stores it in the element model. |
+ */ |
+class InferStaticVariableTypeTask extends InferStaticVariableTask { |
+ /** |
+ * The name of the input which ensures that dependent values have their type |
+ * inferred before the target. |
+ */ |
+ static const String DEPENDENCIES_INPUT = 'DEPENDENCIES_INPUT'; |
+ |
+ /** |
+ * The name of the [TYPE_PROVIDER] input. |
+ */ |
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
+ |
+ /** |
+ * The name of the [RESOLVED_UNIT5] input. |
+ */ |
+ static const String UNIT_INPUT = 'UNIT_INPUT'; |
+ |
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
+ 'InferStaticVariableTypeTask', |
+ createTask, |
+ buildInputs, |
+ <ResultDescriptor>[INFERRED_STATIC_VARIABLE]); |
+ |
+ InferStaticVariableTypeTask( |
+ InternalAnalysisContext context, VariableElement variable) |
+ : super(context, variable); |
+ |
+ @override |
+ TaskDescriptor get descriptor => DESCRIPTOR; |
+ |
+ @override |
+ bool get handlesDependencyCycles => true; |
+ |
+ @override |
+ void internalPerform() { |
+ // |
+ // Prepare inputs. |
+ // |
+ // Note: DEPENDENCIES_INPUT is not needed. It is merely a bookkeeping |
+ // dependency to ensure that the variables that this variable references |
+ // have types inferred before inferring the type of this variable. |
+ // |
+ VariableElementImpl variable = target; |
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
+ TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
+ // |
+ // Re-resolve the variable's initializer so that the inferred types of other |
+ // variables will be propagated. |
+ // |
+ NodeLocator locator = new NodeLocator(variable.nameOffset); |
+ AstNode node = locator.searchWithin(unit); |
+ VariableDeclaration declaration = |
+ node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration); |
+ if (declaration == null || declaration.name != node) { |
+ throw new AnalysisException( |
+ "NodeLocator failed to find a variable's declaration"); |
+ } |
+ RecordingErrorListener errorListener = new RecordingErrorListener(); |
+ Expression initializer = declaration.initializer; |
+ ResolutionContext resolutionContext = |
+ ResolutionContextBuilder.contextFor(initializer, errorListener); |
+ ResolverVisitor visitor = new ResolverVisitor( |
+ variable.library, variable.source, typeProvider, errorListener, |
+ nameScope: resolutionContext.scope); |
+ if (resolutionContext.enclosingClassDeclaration != null) { |
+ visitor.prepareToResolveMembersInClass( |
+ resolutionContext.enclosingClassDeclaration); |
+ } |
+ visitor.initForIncrementalResolution(); |
Paul Berry
2015/08/29 01:14:55
It seems weird that we both manually initialize th
Brian Wilkerson
2015/08/31 15:08:52
The method initForIncrementalResolution() is also
|
+ initializer.accept(visitor); |
+ // |
+ // Record the type of the variable. |
+ // |
+ DartType newType = initializer.staticType; |
+ variable.type = newType; |
+ (variable.initializer as ExecutableElementImpl).returnType = newType; |
+ if (variable is PropertyInducingElementImpl) { |
+ setReturnType(variable.getter, newType); |
+ setParameterType(variable.setter, newType); |
+ } |
+ // |
+ // Record outputs. |
+ // |
+ outputs[INFERRED_STATIC_VARIABLE] = variable; |
+ } |
+ |
+ /** |
+ * Return a map from the names of the inputs of this kind of task to the task |
+ * input descriptors describing those inputs for a task with the given |
+ * [target]. |
+ */ |
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
+ VariableElement variable = target; |
+ LibrarySpecificUnit unit = |
+ new LibrarySpecificUnit(variable.library.source, variable.source); |
+ return <String, TaskInput>{ |
+ DEPENDENCIES_INPUT: INFERABLE_STATIC_VARIABLE_DEPENDENCIES |
+ .of(variable) |
+ .toListOf(INFERRED_STATIC_VARIABLE), |
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request), |
+ UNIT_INPUT: RESOLVED_UNIT5.of(unit) |
+ }; |
+ } |
+ |
+ /** |
+ * Create a [InferStaticVariableTypeTask] based on the given [target] in the |
+ * given [context]. |
+ */ |
+ static InferStaticVariableTypeTask createTask( |
+ AnalysisContext context, AnalysisTarget target) { |
+ return new InferStaticVariableTypeTask(context, target); |
+ } |
+} |
+ |
+/** |
* A task computes all of the errors of all of the units for a single |
* library source and sets the [LIBRARY_ERRORS_READY] flag. |
*/ |