[dartdevc] fix to pass in analysis options to analysis context

Also switch to using the RestrictedAnalysisContext.

Change-Id: Ia9a07331592a3eaacacddb8b27ca08598d2c0773
Reviewed-on: https://dart-review.googlesource.com/c/88749
Commit-Queue: Jenny Messerly <jmesserly@google.com>
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index 6edbe05..d8063b5 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -74,7 +74,7 @@
   final Dart2TypeSystem rules;
 
   /// Errors that were produced during compilation, if any.
-  final List<AnalysisError> errors;
+  final ErrorCollector errors;
 
   JSTypeRep jsTypeRep;
 
@@ -5681,8 +5681,10 @@
       var nearest = (lexeme.startsWith("0x") || lexeme.startsWith("0X"))
           ? '0x${valueInJS.toRadixString(16)}'
           : '$valueInJS';
-      errors.add(AnalysisError(_currentCompilationUnit.source, node.offset,
-          node.length, invalidJSInteger, [lexeme, nearest]));
+      errors.add(
+          _currentCompilationUnit.lineInfo,
+          AnalysisError(_currentCompilationUnit.source, node.offset,
+              node.length, invalidJSInteger, [lexeme, nearest]));
     }
     return JS.LiteralNumber('$valueInJS');
   }
diff --git a/pkg/dev_compiler/lib/src/analyzer/driver.dart b/pkg/dev_compiler/lib/src/analyzer/driver.dart
index ec38410..cec419b 100644
--- a/pkg/dev_compiler/lib/src/analyzer/driver.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/driver.dart
@@ -9,14 +9,15 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/file_system/file_system.dart' show ResourceProvider;
-import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart' show AnalysisDriver;
 import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/analysis/library_analyzer.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
+import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
 import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/idl.dart';
@@ -241,17 +242,13 @@
     var bundle = PackageBundle.fromBuffer(summaryBytes);
 
     /// Create an analysis context to contain the state for this build unit.
-    var context =
-        AnalysisEngine.instance.createAnalysisContext() as AnalysisContextImpl;
-    context.sourceFactory = sourceFactory;
+    var context = RestrictedAnalysisContext(
+        analysisOptions, declaredVariables, sourceFactory);
     var resultProvider = InputPackagesResultProvider(
         context,
         SummaryDataStore([])
           ..addStore(summaryData)
           ..addBundle(null, bundle));
-    context.resultProvider = resultProvider;
-    context.contentCache = _ContentCacheWrapper(fsState);
-    context.analysisOptions = analysisOptions;
 
     var resynthesizer = resultProvider.resynthesizer;
     _extensionTypes ??= ExtensionTypeSet(context.typeProvider, resynthesizer);
@@ -316,10 +313,7 @@
       this._fsState,
       this._resourceProvider);
 
-  AnalysisContextImpl get context => resynthesizer.context;
-
-  /// Clean up any state used by this driver.
-  void dispose() => context.dispose();
+  TypeProvider get typeProvider => resynthesizer.typeProvider;
 
   /// True if [uri] refers to a Dart library (i.e. a Dart source file exists
   /// with this uri, and it is not a part file).
@@ -340,9 +334,9 @@
         declaredVariables,
         resynthesizer.sourceFactory,
         (uri) => _isLibraryUri('$uri'),
-        context,
+        resynthesizer.context,
         resynthesizer,
-        InheritanceManager2(context.typeSystem),
+        InheritanceManager2(resynthesizer.typeSystem),
         libraryFile,
         _resourceProvider);
     // TODO(jmesserly): ideally we'd use the existing public `analyze()` method,
@@ -361,51 +355,3 @@
     return resynthesizer.getLibraryElement(uri);
   }
 }
-
-/// [ContentCache] wrapper around [FileSystemState].
-class _ContentCacheWrapper implements ContentCache {
-  final FileSystemState fsState;
-
-  _ContentCacheWrapper(this.fsState);
-
-  @override
-  void accept(ContentCacheVisitor visitor) {
-    throw new UnimplementedError();
-  }
-
-  @override
-  String getContents(Source source) {
-    return _getFileForSource(source).content;
-  }
-
-  @override
-  bool getExists(Source source) {
-    if (source.isInSystemLibrary) {
-      return true;
-    }
-    String uriStr = source.uri.toString();
-    if (fsState.externalSummaries != null &&
-        fsState.externalSummaries.hasUnlinkedUnit(uriStr)) {
-      return true;
-    }
-    return _getFileForSource(source).exists;
-  }
-
-  @override
-  int getModificationStamp(Source source) {
-    if (source.isInSystemLibrary) {
-      return 0;
-    }
-    return _getFileForSource(source).exists ? 0 : -1;
-  }
-
-  @override
-  String setContents(Source source, String contents) {
-    throw new UnimplementedError();
-  }
-
-  FileState _getFileForSource(Source source) {
-    String path = source.fullName;
-    return fsState.getFileForPath(path);
-  }
-}
diff --git a/pkg/dev_compiler/lib/src/analyzer/error_helpers.dart b/pkg/dev_compiler/lib/src/analyzer/error_helpers.dart
index 0943c39..1528546 100644
--- a/pkg/dev_compiler/lib/src/analyzer/error_helpers.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/error_helpers.dart
@@ -2,33 +2,87 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:collection';
+
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/source/error_processor.dart' show ErrorProcessor;
+import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
+import 'package:analyzer/src/generated/engine.dart' show AnalysisOptions;
 import 'package:path/path.dart' as path;
 
-/// Sorts and formats errors, returning the error messages.
-List<String> formatErrors(AnalysisContext context, List<AnalysisError> errors) {
-  sortErrors(context, errors);
-  var result = <String>[];
-  for (var e in errors) {
-    var m = formatError(context, e);
-    if (m != null) result.add(m);
-  }
-  return result;
-}
+class ErrorCollector {
+  final bool _replCompile;
+  final AnalysisOptions _options;
+  SplayTreeMap<AnalysisError, String> _errors;
 
-// TODO(jmesserly): this code was taken from analyzer_cli.
-// It really should be in some common place so we can share it.
-// TODO(jmesserly): this shouldn't depend on `context` but we need it to compute
-// `errorSeverity` due to some APIs that need fixing.
-void sortErrors(AnalysisContext context, List<AnalysisError> errors) {
-  errors.sort((AnalysisError error1, AnalysisError error2) {
+  ErrorCollector(this._options, this._replCompile) {
+    _errors = SplayTreeMap<AnalysisError, String>(_compareErrors);
+  }
+
+  bool get hasFatalErrors => _errors.keys.any(_isFatalError);
+
+  Iterable<String> get formattedErrors => _errors.values;
+
+  void add(LineInfo lineInfo, AnalysisError error) {
+    if (_shouldIgnoreError(error)) return;
+
+    // Skip hints, some like TODOs are not useful.
+    if (_errorSeverity(error).ordinal <= ErrorSeverity.INFO.ordinal) return;
+
+    _errors[error] = _formatError(lineInfo, error);
+  }
+
+  void addAll(LineInfo lineInfo, Iterable<AnalysisError> errors) {
+    for (var e in errors) add(lineInfo, e);
+  }
+
+  ErrorSeverity _errorSeverity(AnalysisError error) {
+    var errorCode = error.errorCode;
+    if (errorCode == StrongModeCode.TOP_LEVEL_FUNCTION_LITERAL_BLOCK ||
+        errorCode == StrongModeCode.TOP_LEVEL_INSTANCE_GETTER ||
+        errorCode == StrongModeCode.TOP_LEVEL_INSTANCE_METHOD) {
+      // These are normally hints, but they should be errors when running DDC, so
+      // that users won't be surprised by behavioral differences between DDC and
+      // dart2js.
+      return ErrorSeverity.ERROR;
+    }
+
+    // TODO(jmesserly): remove support for customizing error levels via
+    // analysis_options from DDC. (it won't work with --kernel).
+    return ErrorProcessor.getProcessor(_options, error)?.severity ??
+        errorCode.errorSeverity;
+  }
+
+  String _formatError(LineInfo lineInfo, AnalysisError error) {
+    var location = lineInfo.getLocation(error.offset);
+
+    // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2)
+    return (StringBuffer()
+          ..write('[${_errorSeverity(error).displayName}] ')
+          ..write(error.message)
+          ..write(' (${path.prettyUri(error.source.uri)}')
+          ..write(
+              ', line ${location.lineNumber}, col ${location.columnNumber})'))
+        .toString();
+  }
+
+  bool _shouldIgnoreError(AnalysisError error) {
+    var uri = error.source.uri;
+    if (uri.scheme != 'dart') return false;
+    var sdkLib = uri.pathSegments[0];
+    if (sdkLib == 'html' || sdkLib == 'svg' || sdkLib == '_interceptors') {
+      var c = error.errorCode;
+      return c == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
+          c == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
+          c == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS;
+    }
+    return false;
+  }
+
+  int _compareErrors(AnalysisError error1, AnalysisError error2) {
     // severity
-    var severity1 = errorSeverity(context, error1);
-    var severity2 = errorSeverity(context, error2);
-    int compare = severity2.compareTo(severity1);
+    int compare = _errorSeverity(error2).compareTo(_errorSeverity(error1));
     if (compare != 0) return compare;
 
     // path
@@ -42,64 +96,22 @@
 
     // compare message, in worst case.
     return error1.message.compareTo(error2.message);
-  });
-}
-
-// TODO(jmesserly): this was from analyzer_cli, we should factor it differently.
-String formatError(AnalysisContext context, AnalysisError error) {
-  var severity = errorSeverity(context, error);
-  // Skip hints, some like TODOs are not useful.
-  if (severity.ordinal <= ErrorSeverity.INFO.ordinal) return null;
-
-  var lineInfo = context.computeLineInfo(error.source);
-  var location = lineInfo.getLocation(error.offset);
-
-  // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2)
-  return (StringBuffer()
-        ..write('[${severity.displayName}] ')
-        ..write(error.message)
-        ..write(' (${path.prettyUri(error.source.uri)}')
-        ..write(', line ${location.lineNumber}, col ${location.columnNumber})'))
-      .toString();
-}
-
-ErrorSeverity errorSeverity(AnalysisContext context, AnalysisError error) {
-  var errorCode = error.errorCode;
-  if (errorCode == StrongModeCode.TOP_LEVEL_FUNCTION_LITERAL_BLOCK ||
-      errorCode == StrongModeCode.TOP_LEVEL_INSTANCE_GETTER ||
-      errorCode == StrongModeCode.TOP_LEVEL_INSTANCE_METHOD) {
-    // These are normally hints, but they should be errors when running DDC, so
-    // that users won't be surprised by behavioral differences between DDC and
-    // dart2js.
-    return ErrorSeverity.ERROR;
   }
 
-  // TODO(jmesserly): this Analyzer API totally bonkers, but it's what
-  // analyzer_cli and server use.
-  //
-  // Among the issues with ErrorProcessor.getProcessor:
-  // * it needs to be called per-error, so it's a performance trap.
-  // * it can return null
-  // * using AnalysisError directly is now suspect, it's a correctness trap
-  // * it requires an AnalysisContext
-  return ErrorProcessor.getProcessor(context.analysisOptions, error)
-          ?.severity ??
-      errorCode.errorSeverity;
-}
+  bool _isFatalError(AnalysisError e) {
+    if (_errorSeverity(e) != ErrorSeverity.ERROR) return false;
 
-bool isFatalError(AnalysisContext context, AnalysisError e, bool replCompile) {
-  if (errorSeverity(context, e) != ErrorSeverity.ERROR) return false;
-
-  // These errors are not fatal in the REPL compile mode as we
-  // allow access to private members across library boundaries
-  // and those accesses will show up as undefined members unless
-  // additional analyzer changes are made to support them.
-  // TODO(jacobr): consider checking that the identifier name
-  // referenced by the error is private.
-  return !replCompile ||
-      (e.errorCode != StaticTypeWarningCode.UNDEFINED_GETTER &&
-          e.errorCode != StaticTypeWarningCode.UNDEFINED_SETTER &&
-          e.errorCode != StaticTypeWarningCode.UNDEFINED_METHOD);
+    // These errors are not fatal in the REPL compile mode as we
+    // allow access to private members across library boundaries
+    // and those accesses will show up as undefined members unless
+    // additional analyzer changes are made to support them.
+    // TODO(jacobr): consider checking that the identifier name
+    // referenced by the error is private.
+    return !_replCompile ||
+        (e.errorCode != StaticTypeWarningCode.UNDEFINED_GETTER &&
+            e.errorCode != StaticTypeWarningCode.UNDEFINED_SETTER &&
+            e.errorCode != StaticTypeWarningCode.UNDEFINED_METHOD);
+  }
 }
 
 const invalidImportDartMirrors = StrongModeCode(
diff --git a/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart b/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart
index 120f7dc..851d47b 100644
--- a/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart
@@ -18,7 +18,7 @@
   final ClassElement _jsString;
 
   JSTypeRep(this.rules, LinkedAnalysisDriver driver)
-      : types = driver.context.typeProvider,
+      : types = driver.typeProvider,
         _jsBool = driver.getClass('dart:_interceptors', 'JSBool'),
         _jsString = driver.getClass('dart:_interceptors', 'JSString'),
         _jsNumber = driver.getClass('dart:_interceptors', 'JSNumber');
diff --git a/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart b/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
index f62c54c..179dbb1 100644
--- a/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
@@ -10,7 +10,6 @@
     show LibraryElement, UriReferencedElement;
 import 'package:analyzer/error/error.dart';
 
-import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:args/args.dart' show ArgParser, ArgResults;
 import 'package:path/path.dart' as path;
@@ -57,7 +56,6 @@
     AnalyzerOptions analyzerOptions,
     CompilerOptions options) {
   var trees = <CompilationUnit>[];
-  var errors = <AnalysisError>[];
 
   var explicitSources = <Uri>[];
   var compilingSdk = false;
@@ -70,7 +68,17 @@
   }
   var driver = compilerDriver.linkLibraries(explicitSources, analyzerOptions);
 
+  var errors = ErrorCollector(driver.analysisOptions, options.replCompile);
   for (var libraryUri in driver.libraryUris) {
+    var analysisResults = driver.analyzeLibrary(libraryUri);
+
+    CompilationUnit definingUnit;
+    for (var result in analysisResults.values) {
+      if (result.file.uriStr == libraryUri) definingUnit = result.unit;
+      errors.addAll(result.unit.lineInfo, result.errors);
+      trees.add(result.unit);
+    }
+
     var library = driver.getLibrary(libraryUri);
 
     // TODO(jmesserly): remove "dart:mirrors" from DDC's SDK, and then remove
@@ -78,29 +86,19 @@
     if (!compilingSdk && !options.emitMetadata) {
       var node = _getDartMirrorsImport(library);
       if (node != null) {
-        errors.add(AnalysisError(library.source, node.uriOffset, node.uriEnd,
-            invalidImportDartMirrors));
+        errors.add(
+            definingUnit.lineInfo,
+            AnalysisError(library.source, node.uriOffset, node.uriEnd,
+                invalidImportDartMirrors));
       }
     }
-
-    var analysisResults = driver.analyzeLibrary(libraryUri);
-    for (var result in analysisResults.values) {
-      errors.addAll(_filterJsErrors(libraryUri, result.errors));
-      trees.add(result.unit);
-    }
-  }
-
-  var context = driver.context;
-
-  bool anyFatalErrors() {
-    return errors.any((e) => isFatalError(context, e, options.replCompile));
   }
 
   JS.Program jsProgram;
-  if (options.unsafeForceCompile || !anyFatalErrors()) {
+  if (options.unsafeForceCompile || !errors.hasFatalErrors) {
     var codeGenerator = CodeGenerator(
         driver,
-        driver.context.typeProvider,
+        driver.typeProvider,
         compilerDriver.summaryData,
         options,
         compilerDriver.extensionTypes,
@@ -110,37 +108,19 @@
     } catch (e) {
       // If force compilation failed, suppress the exception and report the
       // static errors instead. Otherwise, rethrow an internal compiler error.
-      if (!anyFatalErrors()) rethrow;
+      if (!errors.hasFatalErrors) rethrow;
     }
 
-    if (!options.unsafeForceCompile && anyFatalErrors()) {
+    if (!options.unsafeForceCompile && errors.hasFatalErrors) {
       jsProgram = null;
     }
   }
 
   var jsModule = JSModuleFile(
-      formatErrors(context, errors), options, jsProgram, driver.summaryBytes);
-  driver.dispose();
+      errors.formattedErrors.toList(), options, jsProgram, driver.summaryBytes);
   return jsModule;
 }
 
-Iterable<AnalysisError> _filterJsErrors(
-    String libraryUriStr, Iterable<AnalysisError> errors) {
-  if (libraryUriStr == 'dart:html' ||
-      libraryUriStr == 'dart:svg' ||
-      libraryUriStr == 'dart:_interceptors') {
-    return errors.where((error) {
-      return error.errorCode !=
-              StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 &&
-          error.errorCode !=
-              StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 &&
-          error.errorCode !=
-              StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS;
-    });
-  }
-  return errors;
-}
-
 UriReferencedElement _getDartMirrorsImport(LibraryElement library) {
   return library.imports.firstWhere(_isDartMirrorsImort, orElse: () => null) ??
       library.exports.firstWhere(_isDartMirrorsImort, orElse: () => null);
diff --git a/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart b/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
index 503c60f..5c91caa 100644
--- a/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
+++ b/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
@@ -883,8 +883,7 @@
     summaryData.addBundle(null, sdkSummaryBundle);
   }
 
-  // TODO(jmesserly): can we avoid creating an analysis context entirely?
-  // It doesn't look like StoreBasedSummaryResynthesizer uses much of it.
+  // TODO(jmesserly): use RestrictedAnalysisContext.
   var context = a.AnalysisEngine.instance.createAnalysisContext()
       as a.AnalysisContextImpl;
   context.sourceFactory = a.SourceFactory(