| 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 839024650b1c6a60c16dafa26abba80aec9b1c60..a24e8d85ee021dc67e401ab090275d7ebd41b7b8 100644 | 
| --- a/pkg/analyzer/lib/src/task/dart.dart | 
| +++ b/pkg/analyzer/lib/src/task/dart.dart | 
| @@ -282,6 +282,14 @@ final ListResultDescriptor<AnalysisError> PARSE_ERRORS = | 
| 'PARSE_ERRORS', AnalysisError.NO_ERRORS); | 
|  | 
| /** | 
| + * The names (resolved and not) referenced by a unit. | 
| + * | 
| + * The result is only available for [Source]s representing a compilation unit. | 
| + */ | 
| +final ResultDescriptor<ReferencedNames> REFERENCED_NAMES = | 
| +    new ResultDescriptor<ReferencedNames>('REFERENCED_NAMES', null); | 
| + | 
| +/** | 
| * The errors produced while resolving references. | 
| * | 
| * The list will be empty if there were no errors, but will not be `null`. | 
| @@ -1915,6 +1923,84 @@ class ContainingLibrariesTask extends SourceBasedAnalysisTask { | 
| } | 
|  | 
| /** | 
| + * The description for a change in a Dart source. | 
| + */ | 
| +class DartDelta extends Delta { | 
| +  bool hasDirectiveChange = false; | 
| + | 
| +  final Set<String> addedNames = new Set<String>(); | 
| +  final Set<String> changedNames = new Set<String>(); | 
| +  final Set<String> removedNames = new Set<String>(); | 
| + | 
| +  final Set<Source> invalidatedSources = new Set<Source>(); | 
| + | 
| +  DartDelta(Source source) : super(source) { | 
| +    invalidatedSources.add(source); | 
| +  } | 
| + | 
| +  @override | 
| +  bool affects(InternalAnalysisContext context, AnalysisTarget target, | 
| +      ResultDescriptor descriptor) { | 
| +    if (hasDirectiveChange) { | 
| +      return true; | 
| +    } | 
| +    Source targetSource = null; | 
| +    if (target is Source) { | 
| +      targetSource = target; | 
| +    } | 
| +    if (target is LibrarySpecificUnit) { | 
| +      targetSource = target.library; | 
| +    } | 
| +    if (target is Element) { | 
| +      targetSource = target.source; | 
| +    } | 
| +    if (targetSource == source) { | 
| +      return true; | 
| +    } | 
| +    if (targetSource != null) { | 
| +      List<Source> librarySources = | 
| +          context.getLibrariesContaining(targetSource); | 
| +      for (Source librarySource in librarySources) { | 
| +        AnalysisCache cache = context.analysisCache; | 
| +        ReferencedNames referencedNames = | 
| +            cache.getValue(librarySource, REFERENCED_NAMES); | 
| +        if (referencedNames == null) { | 
| +          return true; | 
| +        } | 
| +        referencedNames.addChangedElements(this); | 
| +        if (referencedNames.isAffectedBy(this)) { | 
| +          return true; | 
| +        } | 
| +      } | 
| +      return false; | 
| +    } | 
| +    return true; | 
| +  } | 
| + | 
| +  void elementAdded(Element element) { | 
| +    addedNames.add(element.name); | 
| +  } | 
| + | 
| +  void elementChanged(Element element) { | 
| +    changedNames.add(element.name); | 
| +  } | 
| + | 
| +  void elementRemoved(Element element) { | 
| +    removedNames.add(element.name); | 
| +  } | 
| + | 
| +  bool isNameAffected(String name) { | 
| +    return addedNames.contains(name) || | 
| +        changedNames.contains(name) || | 
| +        removedNames.contains(name); | 
| +  } | 
| + | 
| +  bool nameChanged(String name) { | 
| +    return changedNames.add(name); | 
| +  } | 
| +} | 
| + | 
| +/** | 
| * A task that merges all of the errors for a single source into a single list | 
| * of errors. | 
| */ | 
| @@ -2791,6 +2877,104 @@ class PublicNamespaceBuilder { | 
| } | 
|  | 
| /** | 
| + * Information about a library - which names it uses, which names it defines | 
| + * with their externally visible dependencies. | 
| + */ | 
| +class ReferencedNames { | 
| +  final Set<String> names = new Set<String>(); | 
| +  final Map<String, Set<String>> userToDependsOn = <String, Set<String>>{}; | 
| + | 
| +  /** | 
| +   * Updates [delta] by adding names that are changed in this library. | 
| +   */ | 
| +  void addChangedElements(DartDelta delta) { | 
| +    bool hasProgress = true; | 
| +    while (hasProgress) { | 
| +      hasProgress = false; | 
| +      userToDependsOn.forEach((user, dependencies) { | 
| +        for (String dependency in dependencies) { | 
| +          if (delta.isNameAffected(dependency)) { | 
| +            if (delta.nameChanged(user)) { | 
| +              hasProgress = true; | 
| +            } | 
| +          } | 
| +        } | 
| +      }); | 
| +    } | 
| +  } | 
| + | 
| +  /** | 
| +   * Returns `true` if the library described by this object is affected by | 
| +   * the given [delta]. | 
| +   */ | 
| +  bool isAffectedBy(DartDelta delta) { | 
| +    for (String name in names) { | 
| +      if (delta.isNameAffected(name)) { | 
| +        return true; | 
| +      } | 
| +    } | 
| +    return false; | 
| +  } | 
| +} | 
| + | 
| +/** | 
| + * A builder for creating [ReferencedNames]. | 
| + * | 
| + * TODO(scheglov) Record dependencies for all other top-level declarations. | 
| + */ | 
| +class ReferencedNamesBuilder extends RecursiveAstVisitor { | 
| +  final ReferencedNames names; | 
| +  int bodyLevel = 0; | 
| +  Set<String> dependsOn; | 
| + | 
| +  ReferencedNamesBuilder(this.names); | 
| + | 
| +  ReferencedNames build(CompilationUnit unit) { | 
| +    unit.accept(this); | 
| +    return names; | 
| +  } | 
| + | 
| +  @override | 
| +  visitBlockFunctionBody(BlockFunctionBody node) { | 
| +    try { | 
| +      bodyLevel++; | 
| +      super.visitBlockFunctionBody(node); | 
| +    } finally { | 
| +      bodyLevel--; | 
| +    } | 
| +  } | 
| + | 
| +  @override | 
| +  visitClassDeclaration(ClassDeclaration node) { | 
| +    dependsOn = new Set<String>(); | 
| +    super.visitClassDeclaration(node); | 
| +    names.userToDependsOn[node.name.name] = dependsOn; | 
| +    dependsOn = null; | 
| +  } | 
| + | 
| +  @override | 
| +  visitExpressionFunctionBody(ExpressionFunctionBody node) { | 
| +    try { | 
| +      bodyLevel++; | 
| +      super.visitExpressionFunctionBody(node); | 
| +    } finally { | 
| +      bodyLevel--; | 
| +    } | 
| +  } | 
| + | 
| +  @override | 
| +  visitSimpleIdentifier(SimpleIdentifier node) { | 
| +    if (!node.inDeclarationContext()) { | 
| +      String name = node.name; | 
| +      names.names.add(name); | 
| +      if (dependsOn != null && bodyLevel == 0) { | 
| +        dependsOn.add(name); | 
| +      } | 
| +    } | 
| +  } | 
| +} | 
| + | 
| +/** | 
| * A task that finishes resolution by requesting [RESOLVED_UNIT_NO_CONSTANTS] for every | 
| * unit in the libraries closure and produces [LIBRARY_ELEMENT]. | 
| */ | 
| @@ -2801,11 +2985,16 @@ class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask { | 
| static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; | 
|  | 
| /** | 
| +   * The name of the [RESOLVED_UNIT6] input. | 
| +   */ | 
| +  static const String UNITS_INPUT = 'UNITS_INPUT'; | 
| + | 
| +  /** | 
| * The task descriptor describing this kind of task. | 
| */ | 
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( | 
| 'ResolveLibraryReferencesTask', createTask, buildInputs, | 
| -      <ResultDescriptor>[LIBRARY_ELEMENT]); | 
| +      <ResultDescriptor>[LIBRARY_ELEMENT, REFERENCED_NAMES]); | 
|  | 
| ResolveLibraryReferencesTask( | 
| InternalAnalysisContext context, AnalysisTarget target) | 
| @@ -2816,8 +3005,21 @@ class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask { | 
|  | 
| @override | 
| void internalPerform() { | 
| +    // | 
| +    // Prepare inputs. | 
| +    // | 
| LibraryElement library = getRequiredInput(LIBRARY_INPUT); | 
| +    List<CompilationUnit> units = getRequiredInput(UNITS_INPUT); | 
| +    // Compute referenced names. | 
| +    ReferencedNames referencedNames = new ReferencedNames(); | 
| +    for (CompilationUnit unit in units) { | 
| +      new ReferencedNamesBuilder(referencedNames).build(unit); | 
| +    } | 
| +    // | 
| +    // Record outputs. | 
| +    // | 
| outputs[LIBRARY_ELEMENT] = library; | 
| +    outputs[REFERENCED_NAMES] = referencedNames; | 
| } | 
|  | 
| /** | 
| @@ -2829,6 +3031,8 @@ class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask { | 
| Source source = target; | 
| return <String, TaskInput>{ | 
| LIBRARY_INPUT: LIBRARY_ELEMENT6.of(source), | 
| +      UNITS_INPUT: UNITS.of(source).toList((Source unit) => | 
| +          RESOLVED_UNIT6.of(new LibrarySpecificUnit(source, unit))), | 
| 'resolvedUnits': IMPORT_EXPORT_SOURCE_CLOSURE | 
| .of(source) | 
| .toMapOf(UNITS) | 
| @@ -3057,7 +3261,7 @@ class ResolveUnitTypeNamesTask extends SourceBasedAnalysisTask { | 
| LibrarySpecificUnit unit = target; | 
| return <String, TaskInput>{ | 
| 'importsExportNamespace': | 
| -                IMPORTED_LIBRARIES.of(unit.library).toMapOf(LIBRARY_ELEMENT4), | 
| +          IMPORTED_LIBRARIES.of(unit.library).toMapOf(LIBRARY_ELEMENT4), | 
| LIBRARY_INPUT: LIBRARY_ELEMENT4.of(unit.library), | 
| UNIT_INPUT: RESOLVED_UNIT2.of(unit), | 
| TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request) | 
|  |