Ignore analysis_options.yaml everywhere (#3666)

diff --git a/lib/src/command/deps.dart b/lib/src/command/deps.dart
index a4203ab..d34c868 100644
--- a/lib/src/command/deps.dart
+++ b/lib/src/command/deps.dart
@@ -8,7 +8,6 @@
 import '../ascii_tree.dart' as tree;
 import '../command.dart';
 import '../command_runner.dart';
-import '../dart.dart';
 import '../log.dart' as log;
 import '../package.dart';
 import '../sdk.dart';
@@ -31,9 +30,6 @@
   @override
   bool get takesArguments => false;
 
-  final AnalysisContextManager analysisContextManager =
-      AnalysisContextManager();
-
   /// The [StringBuffer] used to accumulate the output.
   // TODO(sigurdm): use a local variable for this.
   final _buffer = StringBuffer();
diff --git a/lib/src/dart.dart b/lib/src/dart.dart
index d922de0..ac13549 100644
--- a/lib/src/dart.dart
+++ b/lib/src/dart.dart
@@ -6,15 +6,12 @@
 import 'dart:async';
 import 'dart:io';
 
-import 'package:analyzer/dart/analysis/analysis_context.dart';
-import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/dart/analysis/context_builder.dart';
+import 'package:analyzer/dart/analysis/context_locator.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/file_system/overlay_file_system.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:cli_util/cli_util.dart';
 import 'package:frontend_server_client/frontend_server_client.dart';
 import 'package:path/path.dart' as p;
 
@@ -23,53 +20,26 @@
 import 'log.dart' as log;
 
 class AnalysisContextManager {
-  /// The map from a context root directory to to the context.
-  final Map<String, AnalysisContext> _contexts = {};
+  static final sessions = <String, AnalysisContextManager>{};
 
-  /// Ensure that there are analysis contexts for the directory with the
-  /// given [path]. If any previously added root covers the [path], keep
-  /// the previously created analysis context.
-  ///
-  /// This method does not discover analysis roots "up", it only looks down
-  /// the given [path]. It is expected that the client knows analysis roots
-  /// in advance. Pub does know, it is the packages it works with.
-  void createContextsForDirectory(String path) {
-    path = p.normalize(p.absolute(path));
+  final String packagePath;
+  final AnalysisSession _session;
 
-    // We add all contexts below the given directory.
-    // So, children contexts must also have been added.
-    if (_contexts.containsKey(path)) {
-      return;
-    }
+  factory AnalysisContextManager(String packagePath) => sessions.putIfAbsent(
+      packagePath, () => AnalysisContextManager._(packagePath));
 
-    // Overwrite the analysis_options.yaml to avoid loading the file included
-    // in the package, as this may result in some files not being analyzed.
-    final resourceProvider =
-        OverlayResourceProvider(PhysicalResourceProvider.INSTANCE);
-    resourceProvider.setOverlay(
-      p.join(path, 'analysis_options.yaml'),
-      content: '',
-      modificationStamp: 0,
-    );
-
-    var contextCollection = AnalysisContextCollection(
-      includedPaths: [path],
-      resourceProvider: resourceProvider,
-      sdkPath: getSdkPath(),
-    );
-
-    // Add new contexts for the given path.
-    for (var analysisContext in contextCollection.contexts) {
-      var contextRootPath = analysisContext.contextRoot.root.path;
-
-      // If there is already a context for this context root path, keep it.
-      if (_contexts.containsKey(contextRootPath)) {
-        continue;
-      }
-
-      _contexts[contextRootPath] = analysisContext;
-    }
-  }
+  AnalysisContextManager._(this.packagePath)
+      : _session = ContextBuilder()
+            .createContext(
+              contextRoot: ContextLocator().locateRoots(
+                includedPaths: [p.absolute(p.normalize(packagePath))],
+                optionsFile:
+                    // We don't want to take 'analysis_options.yaml' files into
+                    // account. So we replace it with an empty file.
+                    Platform.isWindows ? r'C:\NUL' : '/dev/null',
+              ).first,
+            )
+            .currentSession;
 
   /// Parse the file with the given [path] into AST.
   ///
@@ -80,7 +50,7 @@
   /// Throws [AnalyzerErrorGroup] is the file has parsing errors.
   CompilationUnit parse(String path) {
     path = p.normalize(p.absolute(path));
-    var parseResult = _getExistingSession(path).getParsedUnit(path);
+    var parseResult = _session.getParsedUnit(path);
     if (parseResult is ParsedUnitResult) {
       if (parseResult.errors.isNotEmpty) {
         throw AnalyzerErrorGroup(parseResult.errors);
@@ -93,10 +63,6 @@
 
   /// Return import and export directives in the file with the given [path].
   ///
-  /// One of the containing directories must be used to create analysis
-  /// contexts using [createContextsForDirectory]. Throws [StateError] if
-  /// this has not been done.
-  ///
   /// Throws [AnalyzerErrorGroup] is the file has parsing errors.
   List<UriBasedDirective> parseImportsAndExports(String path) {
     var unit = parse(path);
@@ -108,16 +74,6 @@
     }
     return uriDirectives;
   }
-
-  AnalysisSession _getExistingSession(String path) {
-    for (var context in _contexts.values) {
-      if (context.contextRoot.isAnalyzed(path)) {
-        return context.currentSession;
-      }
-    }
-
-    throw StateError('Unable to find the context to $path');
-  }
 }
 
 /// An error class that contains multiple [AnalysisError]s.
diff --git a/lib/src/validator/language_version.dart b/lib/src/validator/language_version.dart
index 2041bcb..ab2d868 100644
--- a/lib/src/validator/language_version.dart
+++ b/lib/src/validator/language_version.dart
@@ -20,8 +20,7 @@
   @override
   Future validate() async {
     var packagePath = p.normalize(p.absolute(entrypoint.root.dir));
-    final analysisContextManager = AnalysisContextManager()
-      ..createContextsForDirectory(packagePath);
+    final analysisContextManager = AnalysisContextManager(packagePath);
 
     final declaredLanguageVersion = entrypoint.root.pubspec.languageVersion;
 
diff --git a/lib/src/validator/strict_dependencies.dart b/lib/src/validator/strict_dependencies.dart
index ea481f5..17ee609 100644
--- a/lib/src/validator/strict_dependencies.dart
+++ b/lib/src/validator/strict_dependencies.dart
@@ -25,8 +25,7 @@
   Iterable<_Usage> _findPackages(Iterable<String> files) sync* {
     final packagePath = p.normalize(p.absolute(entrypoint.root.dir));
     final AnalysisContextManager analysisContextManager =
-        AnalysisContextManager();
-    analysisContextManager.createContextsForDirectory(packagePath);
+        AnalysisContextManager(packagePath);
 
     for (var file in files) {
       List<UriBasedDirective> directives;
diff --git a/test/validator/strict_dependencies_test.dart b/test/validator/strict_dependencies_test.dart
index 18ee9c7..3f30efd 100644
--- a/test/validator/strict_dependencies_test.dart
+++ b/test/validator/strict_dependencies_test.dart
@@ -178,6 +178,37 @@
 
       await expectValidation(strictDeps);
     });
+
+    test('has lib/analysis_options.yaml that excludes files', () async {
+      await d.dir(appPath, [
+        d.libPubspec('test_pkg', '1.0.0',
+            deps: {'silly_monkey': '^1.2.3'}, sdk: '>=1.8.0 <2.0.0'),
+        d.dir('lib', [
+          d.file('library.dart', r'''
+            import 'package:silly_monkey/silly_monkey.dart';
+          '''),
+          d.file('analysis_options.yaml', r'''
+analyzer:
+  exclude:
+    - '**'
+linter:
+  rules:
+    - avoid_catching_errors
+'''),
+        ]),
+        d.dir('test', [
+          d.dir('data', [
+            d.dir('mypkg', [
+              d.dir('lib', [
+                d.file('dummy.dart', '\n'),
+              ]),
+            ]),
+          ]),
+        ]),
+      ]).create();
+
+      await expectValidation(strictDeps);
+    });
   });
 
   group('should consider a package invalid if it', () {