| // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 
 | // 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:io' as io; | 
 |  | 
 | import 'package:analyzer/dart/analysis/results.dart'; | 
 | import 'package:analyzer/file_system/file_system.dart'; | 
 | import 'package:analyzer/file_system/physical_file_system.dart'; | 
 | import 'package:analyzer/instrumentation/instrumentation.dart'; | 
 | import 'package:analyzer/source/source.dart'; | 
 | import 'package:analyzer/src/analysis_options/analysis_options_provider.dart'; | 
 | import 'package:analyzer/src/analysis_options/apply_options.dart'; | 
 | import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart'; | 
 | import 'package:analyzer/src/generated/engine.dart'; | 
 | import 'package:analyzer/src/generated/sdk.dart'; | 
 | import 'package:analyzer/src/lint/io.dart'; | 
 | import 'package:analyzer/src/lint/linter.dart'; | 
 |  | 
 | AnalysisOptionsProvider _optionsProvider = AnalysisOptionsProvider(); | 
 |  | 
 | Source createSource(Uri sourceUri) { | 
 |   return PhysicalResourceProvider.INSTANCE | 
 |       .getFile(sourceUri.toFilePath()) | 
 |       .createSource(sourceUri); | 
 | } | 
 |  | 
 | /// Print the given message and exit with the given [exitCode] | 
 | void printAndFail(String message, {int exitCode = 15}) { | 
 |   print(message); | 
 |   io.exit(exitCode); | 
 | } | 
 |  | 
 | void _updateAnalyzerOptions( | 
 |   AnalysisOptionsImpl analysisOptions, | 
 |   LinterOptions options, | 
 | ) { | 
 |   if (options.analysisOptions != null) { | 
 |     var map = _optionsProvider.getOptionsFromString(options.analysisOptions); | 
 |     analysisOptions.applyOptions(map); | 
 |   } | 
 |  | 
 |   analysisOptions.lint = options.enableLints; | 
 |   analysisOptions.warning = false; | 
 |   analysisOptions.enableTiming = options.enableTiming; | 
 |   analysisOptions.lintRules = options.enabledRules.toList(growable: false); | 
 | } | 
 |  | 
 | class DriverOptions { | 
 |   /// The maximum number of sources for which AST structures should be kept | 
 |   /// in the cache.  The default is 512. | 
 |   int cacheSize = 512; | 
 |  | 
 |   /// The path to the dart SDK. | 
 |   String? dartSdkPath; | 
 |  | 
 |   /// Whether to show lint warnings. | 
 |   bool enableLints = true; | 
 |  | 
 |   /// Whether to gather timing data during analysis. | 
 |   bool enableTiming = false; | 
 |  | 
 |   /// The path to a `.packages` configuration file | 
 |   String? packageConfigPath; | 
 |  | 
 |   /// Whether to use Dart's Strong Mode analyzer. | 
 |   bool strongMode = true; | 
 |  | 
 |   /// The mock SDK (to speed up testing) or `null` to use the actual SDK. | 
 |   @Deprecated('Use createMockSdk() and set dartSdkPath') | 
 |   DartSdk? mockSdk; | 
 |  | 
 |   /// Return `true` is the parser is able to parse asserts in the initializer | 
 |   /// list of a constructor. | 
 |   @deprecated | 
 |   bool get enableAssertInitializer => true; | 
 |  | 
 |   /// Set whether the parser is able to parse asserts in the initializer list of | 
 |   /// a constructor to match [enable]. | 
 |   @deprecated | 
 |   set enableAssertInitializer(bool enable) { | 
 |     // Ignored because the option is now always enabled. | 
 |   } | 
 | } | 
 |  | 
 | /// A driver _only used_ by [DartLinter], which is only used by package:linter | 
 | /// tests and tools. | 
 | class LintDriver { | 
 |   /// The files which have been analyzed so far.  This is used to compute the | 
 |   /// total number of files analyzed for statistics. | 
 |   final Set<String> _filesAnalyzed = {}; | 
 |  | 
 |   final LinterOptions options; | 
 |  | 
 |   final ResourceProvider _resourceProvider; | 
 |  | 
 |   LintDriver(this.options, this._resourceProvider); | 
 |  | 
 |   /// Return the number of sources that have been analyzed so far. | 
 |   int get numSourcesAnalyzed => _filesAnalyzed.length; | 
 |  | 
 |   Future<List<AnalysisErrorInfo>> analyze(Iterable<io.File> files) async { | 
 |     AnalysisEngine.instance.instrumentationService = StdInstrumentation(); | 
 |  | 
 |     // TODO(scheglov): Enforce normalized absolute paths in the config. | 
 |     var packageConfigPath = options.packageConfigPath; | 
 |     packageConfigPath = _absoluteNormalizedPath.ifNotNull(packageConfigPath); | 
 |  | 
 |     var contextCollection = AnalysisContextCollectionImpl( | 
 |       resourceProvider: _resourceProvider, | 
 |       packagesFile: packageConfigPath, | 
 |       sdkPath: options.dartSdkPath, | 
 |       includedPaths: | 
 |           files.map((file) => _absoluteNormalizedPath(file.path)).toList(), | 
 |       updateAnalysisOptions2: ({ | 
 |         required analysisOptions, | 
 |         required contextRoot, | 
 |         required sdk, | 
 |       }) { | 
 |         _updateAnalyzerOptions(analysisOptions, options); | 
 |       }, | 
 |     ); | 
 |  | 
 |     for (io.File file in files) { | 
 |       var path = _absoluteNormalizedPath(file.path); | 
 |       _filesAnalyzed.add(path); | 
 |     } | 
 |  | 
 |     var result = <AnalysisErrorInfo>[]; | 
 |     for (var path in _filesAnalyzed) { | 
 |       var analysisContext = contextCollection.contextFor(path); | 
 |       var analysisSession = analysisContext.currentSession; | 
 |       var errorsResult = await analysisSession.getErrors(path); | 
 |       if (errorsResult is ErrorsResult) { | 
 |         result.add( | 
 |           AnalysisErrorInfoImpl( | 
 |             errorsResult.errors, | 
 |             errorsResult.lineInfo, | 
 |           ), | 
 |         ); | 
 |       } | 
 |     } | 
 |     return result; | 
 |   } | 
 |  | 
 |   String _absoluteNormalizedPath(String path) { | 
 |     var pathContext = _resourceProvider.pathContext; | 
 |     path = pathContext.absolute(path); | 
 |     path = pathContext.normalize(path); | 
 |     return path; | 
 |   } | 
 | } | 
 |  | 
 | /// Prints logging information comments to the [outSink] and error messages to | 
 | /// [errorSink]. | 
 | class StdInstrumentation extends NoopInstrumentationService { | 
 |   @override | 
 |   void logError(String message, [Object? exception]) { | 
 |     errorSink.writeln(message); | 
 |     if (exception != null) { | 
 |       errorSink.writeln(exception); | 
 |     } | 
 |   } | 
 |  | 
 |   @override | 
 |   void logException(dynamic exception, | 
 |       [StackTrace? stackTrace, | 
 |       List<InstrumentationServiceAttachment>? attachments]) { | 
 |     errorSink.writeln(exception); | 
 |     errorSink.writeln(stackTrace); | 
 |   } | 
 |  | 
 |   @override | 
 |   void logInfo(String message, [Object? exception]) { | 
 |     outSink.writeln(message); | 
 |     if (exception != null) { | 
 |       outSink.writeln(exception); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | extension _UnaryFunctionExtension<T, R> on R Function(T) { | 
 |   /// Invoke this function if [t] is not `null`, otherwise return `null`. | 
 |   R? ifNotNull(T? t) { | 
 |     if (t != null) { | 
 |       return this(t); | 
 |     } else { | 
 |       return null; | 
 |     } | 
 |   } | 
 | } |