1159405ad4
This reverts commit 261f8199af
Reason for revert: it breaks flutter customer testing on hh and on the roller.
Original change's description:
> [DAS] Trigger incompatible lint for included rules
>
> Fixes: https://github.com/dart-lang/sdk/issues/60125
> Change-Id: Icc0b8efda0e7e915d7315a1c2e70c1a7a5093057
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/419982
> Auto-Submit: Felipe Morschel <git@fmorschel.dev>
> Reviewed-by: Samuel Rawlins <srawlins@google.com>
> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Change-Id: I0db90864092760efde1cb02cc792c1de14eabf2d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/429381
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Alexander Aprelev <aam@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
659 lines
22 KiB
Dart
659 lines
22 KiB
Dart
// 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/dart/sdk/build_sdk_summary.dart';
|
|
import 'package:analyzer/diagnostic/diagnostic.dart';
|
|
import 'package:analyzer/error/error.dart';
|
|
import 'package:analyzer/file_system/file_system.dart';
|
|
import 'package:analyzer/file_system/physical_file_system.dart';
|
|
import 'package:analyzer/source/file_source.dart';
|
|
import 'package:analyzer/source/line_info.dart';
|
|
import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
|
|
import 'package:analyzer/src/dart/analysis/analysis_options.dart';
|
|
import 'package:analyzer/src/dart/analysis/byte_store.dart';
|
|
import 'package:analyzer/src/dart/analysis/driver.dart';
|
|
import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
|
|
import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
|
|
import 'package:analyzer/src/dart/analysis/file_state.dart';
|
|
import 'package:analyzer/src/dart/analysis/results.dart';
|
|
import 'package:analyzer/src/generated/sdk.dart';
|
|
import 'package:analyzer/src/manifest/manifest_validator.dart';
|
|
import 'package:analyzer/src/pubspec/pubspec_validator.dart';
|
|
import 'package:analyzer/src/source/path_filter.dart';
|
|
import 'package:analyzer/src/task/options.dart';
|
|
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
|
|
import 'package:analyzer/src/util/yaml.dart';
|
|
import 'package:analyzer/src/workspace/pub.dart';
|
|
import 'package:analyzer_cli/src/analyzer_impl.dart';
|
|
import 'package:analyzer_cli/src/batch_mode.dart';
|
|
import 'package:analyzer_cli/src/error_formatter.dart';
|
|
import 'package:analyzer_cli/src/error_severity.dart';
|
|
import 'package:analyzer_cli/src/options.dart';
|
|
import 'package:analyzer_cli/src/perf_report.dart';
|
|
import 'package:analyzer_cli/starter.dart' show CommandLineStarter;
|
|
import 'package:linter/src/rules.dart' as linter;
|
|
import 'package:meta/meta.dart';
|
|
import 'package:path/path.dart' as path;
|
|
import 'package:yaml/yaml.dart';
|
|
|
|
/// Shared IO sink for standard error reporting.
|
|
StringSink errorSink = io.stderr;
|
|
|
|
/// Shared IO sink for standard out reporting.
|
|
StringSink outSink = io.stdout;
|
|
|
|
/// Test this option map to see if it specifies lint rules.
|
|
bool containsLintRuleEntry(YamlMap options) {
|
|
var linterNode = options.valueAt('linter');
|
|
return linterNode is YamlMap && linterNode.valueAt('rules') != null;
|
|
}
|
|
|
|
class Driver implements CommandLineStarter {
|
|
static final ByteStore analysisDriverMemoryByteStore = MemoryByteStore();
|
|
|
|
bool _isStarted = false;
|
|
|
|
late _AnalysisContextProvider _analysisContextProvider;
|
|
DriverBasedAnalysisContext? analysisContext;
|
|
|
|
/// The driver that was most recently created by a call to [_analyzeAll].
|
|
@visibleForTesting
|
|
AnalysisDriver? analysisDriver;
|
|
|
|
/// The total number of source files loaded by an AnalysisContext.
|
|
int _analyzedFileCount = 0;
|
|
|
|
/// The resource provider used to access the file system.
|
|
final ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
|
|
|
|
/// Collected analysis statistics.
|
|
final AnalysisStats stats = AnalysisStats();
|
|
|
|
/// The [PathFilter] for excluded files with wildcards, etc.
|
|
late PathFilter pathFilter;
|
|
|
|
/// Create a new Driver instance.
|
|
Driver({@Deprecated('This parameter has no effect') bool isTesting = false});
|
|
|
|
/// Converts the given [filePath] into absolute and normalized.
|
|
String normalizePath(String filePath) {
|
|
filePath = filePath.trim();
|
|
filePath = resourceProvider.pathContext.absolute(filePath);
|
|
filePath = resourceProvider.pathContext.normalize(filePath);
|
|
return filePath;
|
|
}
|
|
|
|
@override
|
|
Future<void> start(List<String> arguments) async {
|
|
if (_isStarted) {
|
|
throw StateError('start() can only be called once');
|
|
}
|
|
_isStarted = true;
|
|
var startTime = DateTime.now().millisecondsSinceEpoch;
|
|
|
|
linter.registerLintRules();
|
|
|
|
// Parse commandline options.
|
|
var options = CommandLineOptions.parse(resourceProvider, arguments)!;
|
|
|
|
_analysisContextProvider = _AnalysisContextProvider(resourceProvider);
|
|
|
|
// Do analysis.
|
|
if (options.batchMode) {
|
|
var batchRunner = BatchRunner(outSink, errorSink);
|
|
batchRunner.runAsBatch(arguments, (List<String> args) async {
|
|
var options = CommandLineOptions.parse(resourceProvider, args)!;
|
|
return await _analyzeAll(options);
|
|
});
|
|
} else {
|
|
var severity = await _analyzeAll(options);
|
|
// Propagate issues to the exit code.
|
|
if (_shouldBeFatal(severity)) {
|
|
io.exitCode = severity.ordinal;
|
|
}
|
|
}
|
|
|
|
// When training a snapshot, in addition to training regular analysis
|
|
// (above), we train build mode as well.
|
|
if (options.trainSnapshot) {
|
|
// TODO(devoncarew): Iterate on this training to make it more
|
|
// representative of what we see internally; call into _buildModeAnalyze()
|
|
// with some appropriate options.
|
|
print('\nGenerating strong mode summary...');
|
|
final stopwatch = Stopwatch()..start();
|
|
|
|
for (var i = 0; i < 3; i++) {
|
|
await buildSdkSummary(
|
|
resourceProvider: PhysicalResourceProvider.INSTANCE,
|
|
sdkPath: options.dartSdkPath!,
|
|
);
|
|
}
|
|
|
|
print('Done in ${stopwatch.elapsedMilliseconds} ms.');
|
|
}
|
|
|
|
if (analysisDriver != null) {
|
|
_analyzedFileCount += analysisDriver!.knownFiles.length;
|
|
}
|
|
|
|
await _analysisContextProvider.dispose();
|
|
|
|
if (options.perfReport != null) {
|
|
var json = makePerfReport(
|
|
startTime,
|
|
currentTimeMillis,
|
|
options,
|
|
_analyzedFileCount,
|
|
stats,
|
|
);
|
|
io.File(options.perfReport!).writeAsStringSync(json);
|
|
}
|
|
}
|
|
|
|
/// Perform analysis according to the given [options].
|
|
Future<DiagnosticSeverity> _analyzeAll(CommandLineOptions options) async {
|
|
if (!options.jsonFormat && !options.machineFormat) {
|
|
var fileNames =
|
|
options.sourceFiles.map((String file) {
|
|
file = path.normalize(file);
|
|
if (file == '.') {
|
|
file = path.basename(path.current);
|
|
} else if (file == '..') {
|
|
file = path.basename(path.normalize(path.absolute(file)));
|
|
}
|
|
return file;
|
|
}).toList();
|
|
|
|
outSink.writeln("Analyzing ${fileNames.join(', ')}...");
|
|
}
|
|
|
|
_verifyAnalysisOptionsFileExists(options);
|
|
|
|
// These are used to do part file analysis across sources.
|
|
var dartFiles = <String>{};
|
|
final analyzedFiles = <FileState>{};
|
|
final partFiles = <FileState>{};
|
|
|
|
// Note: This references analysisDriver via closure, so it will change over
|
|
// time during the following analysis.
|
|
SeverityProcessor defaultSeverityProcessor;
|
|
defaultSeverityProcessor = (Diagnostic diagnostic) {
|
|
var filePath = diagnostic.source.fullName;
|
|
var file = analysisDriver!.resourceProvider.getFile(filePath);
|
|
return determineProcessedSeverity(
|
|
diagnostic,
|
|
options,
|
|
analysisDriver!.getAnalysisOptionsForFile(file),
|
|
);
|
|
};
|
|
|
|
// We currently print out to stderr to ensure that when in batch mode we
|
|
// print to stderr, this is because the prints from batch are made to
|
|
// stderr. The reason that options.shouldBatch isn't used is because when
|
|
// the argument flags are constructed in BatchRunner and passed in from
|
|
// batch mode which removes the batch flag to prevent the "cannot have the
|
|
// batch flag and source file" error message.
|
|
ErrorFormatter formatter;
|
|
if (options.jsonFormat) {
|
|
formatter = JsonErrorFormatter(
|
|
outSink,
|
|
options,
|
|
stats,
|
|
severityProcessor: defaultSeverityProcessor,
|
|
);
|
|
} else if (options.machineFormat) {
|
|
// The older machine format emits to stderr (instead of stdout) for legacy
|
|
// reasons.
|
|
formatter = MachineErrorFormatter(
|
|
errorSink,
|
|
options,
|
|
stats,
|
|
severityProcessor: defaultSeverityProcessor,
|
|
);
|
|
} else {
|
|
formatter = HumanErrorFormatter(
|
|
outSink,
|
|
options,
|
|
stats,
|
|
severityProcessor: defaultSeverityProcessor,
|
|
);
|
|
}
|
|
|
|
var allResult = DiagnosticSeverity.NONE;
|
|
|
|
void reportPartError(String partPath) {
|
|
errorSink.writeln('$partPath is a part and cannot be analyzed.');
|
|
errorSink.writeln('Please pass in a library that contains this part.');
|
|
io.exitCode = DiagnosticSeverity.ERROR.ordinal;
|
|
allResult = allResult.max(DiagnosticSeverity.ERROR);
|
|
}
|
|
|
|
var pathList = options.sourceFiles.map(normalizePath).toList();
|
|
_analysisContextProvider.setCommandLineOptions(options, pathList);
|
|
|
|
for (var sourcePath in pathList) {
|
|
_analysisContextProvider.configureForPath(sourcePath);
|
|
analysisContext = _analysisContextProvider.analysisContext;
|
|
final analysisDriver =
|
|
this.analysisDriver = _analysisContextProvider.analysisDriver;
|
|
pathFilter = _analysisContextProvider.pathFilter;
|
|
|
|
// Add all the files to be analyzed en masse to the context. Skip any
|
|
// files that were added earlier (whether explicitly or implicitly) to
|
|
// avoid causing those files to be unnecessarily re-read.
|
|
var filesToAnalyze = <String>{};
|
|
|
|
// Collect files for analysis.
|
|
// Note that these files will all be analyzed in the same context.
|
|
// This should be updated when the ContextManager re-work is complete
|
|
// (See: https://github.com/dart-lang/sdk/issues/24133)
|
|
var files = _collectFiles(sourcePath);
|
|
if (files.isEmpty) {
|
|
errorSink.writeln('No dart files found at: $sourcePath');
|
|
io.exitCode = DiagnosticSeverity.ERROR.ordinal;
|
|
return DiagnosticSeverity.ERROR;
|
|
}
|
|
|
|
for (var file in files) {
|
|
filesToAnalyze.add(file.absolute.path);
|
|
}
|
|
|
|
// Analyze the libraries.
|
|
var pathContext = resourceProvider.pathContext;
|
|
for (var path in filesToAnalyze) {
|
|
if (file_paths.isAnalysisOptionsYaml(pathContext, path)) {
|
|
var fileResult = analysisDriver.currentSession.getFile(path);
|
|
if (fileResult is! FileResult) continue;
|
|
var file = fileResult.file;
|
|
var content = file.readAsStringSync();
|
|
var lineInfo = LineInfo.fromContent(content);
|
|
var contextRoot =
|
|
analysisDriver.currentSession.analysisContext.contextRoot;
|
|
var package = contextRoot.workspace.findPackageFor(file.path);
|
|
var sdkVersionConstraint =
|
|
(package is PubPackage) ? package.sdkVersionConstraint : null;
|
|
var errors = analyzeAnalysisOptions(
|
|
FileSource(file),
|
|
content,
|
|
analysisDriver.sourceFactory,
|
|
contextRoot.root.path,
|
|
sdkVersionConstraint,
|
|
);
|
|
var analysisOptions = fileResult.analysisOptions;
|
|
await formatter.formatErrors([
|
|
ErrorsResultImpl(
|
|
session: analysisDriver.currentSession,
|
|
file: file,
|
|
content: content,
|
|
uri: pathContext.toUri(path),
|
|
lineInfo: lineInfo,
|
|
isLibrary: true,
|
|
isPart: false,
|
|
errors: errors,
|
|
analysisOptions: analysisOptions,
|
|
),
|
|
]);
|
|
for (var error in errors) {
|
|
var severity = determineProcessedSeverity(
|
|
error,
|
|
options,
|
|
analysisOptions,
|
|
);
|
|
if (severity != null) {
|
|
allResult = allResult.max(severity);
|
|
}
|
|
}
|
|
} else if (file_paths.isPubspecYaml(pathContext, path)) {
|
|
var diagnostics = <Diagnostic>[];
|
|
try {
|
|
var file = resourceProvider.getFile(path);
|
|
var analysisOptions = analysisDriver.currentSession.analysisContext
|
|
.getAnalysisOptionsForFile(file);
|
|
var content = file.readAsStringSync();
|
|
var node = loadYamlNode(content, sourceUrl: file.toUri());
|
|
|
|
if (node is YamlMap) {
|
|
diagnostics.addAll(
|
|
validatePubspec(
|
|
contents: node,
|
|
source: FileSource(file),
|
|
provider: resourceProvider,
|
|
analysisOptions: analysisOptions,
|
|
),
|
|
);
|
|
}
|
|
if (diagnostics.isNotEmpty) {
|
|
for (var error in diagnostics) {
|
|
var severity =
|
|
determineProcessedSeverity(
|
|
error,
|
|
options,
|
|
analysisOptions,
|
|
)!;
|
|
allResult = allResult.max(severity);
|
|
}
|
|
var lineInfo = LineInfo.fromContent(content);
|
|
await formatter.formatErrors([
|
|
ErrorsResultImpl(
|
|
session: analysisDriver.currentSession,
|
|
file: file,
|
|
content: content,
|
|
uri: pathContext.toUri(path),
|
|
lineInfo: lineInfo,
|
|
isLibrary: true,
|
|
isPart: false,
|
|
errors: diagnostics,
|
|
analysisOptions: analysisOptions,
|
|
),
|
|
]);
|
|
}
|
|
} catch (exception) {
|
|
// If the file cannot be analyzed, ignore it.
|
|
}
|
|
} else if (file_paths.isAndroidManifestXml(pathContext, path)) {
|
|
try {
|
|
var file = resourceProvider.getFile(path);
|
|
var analysisOptions = analysisDriver.getAnalysisOptionsForFile(
|
|
file,
|
|
);
|
|
var content = file.readAsStringSync();
|
|
var source = FileSource(file);
|
|
var validator = ManifestValidator(source);
|
|
var lineInfo = LineInfo.fromContent(content);
|
|
var errors = validator.validate(
|
|
content,
|
|
analysisOptions.chromeOsManifestChecks,
|
|
);
|
|
await formatter.formatErrors([
|
|
ErrorsResultImpl(
|
|
session: analysisDriver.currentSession,
|
|
file: file,
|
|
content: content,
|
|
uri: pathContext.toUri(path),
|
|
lineInfo: lineInfo,
|
|
isLibrary: true,
|
|
isPart: false,
|
|
errors: errors,
|
|
analysisOptions: analysisOptions,
|
|
),
|
|
]);
|
|
for (var error in errors) {
|
|
var severity =
|
|
determineProcessedSeverity(error, options, analysisOptions)!;
|
|
allResult = allResult.max(severity);
|
|
}
|
|
} catch (exception) {
|
|
// If the file cannot be analyzed, ignore it.
|
|
}
|
|
} else {
|
|
dartFiles.add(path);
|
|
var file = analysisDriver.fsState.getFileForPath(path);
|
|
|
|
final kind = file.kind;
|
|
if (kind is LibraryFileKind) {
|
|
var status = await _runAnalyzer(file, options, formatter);
|
|
allResult = allResult.max(status);
|
|
analyzedFiles.addAll(kind.files);
|
|
} else if (kind is PartFileKind) {
|
|
partFiles.add(file);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// We are done analyzing this batch of files.
|
|
// The next batch should not be affected by a previous batch.
|
|
// E.g. the same parts in both batches, but with different libraries.
|
|
for (var path in dartFiles) {
|
|
analysisDriver!.removeFile(path);
|
|
}
|
|
|
|
// Any dangling parts still in this list were definitely dangling.
|
|
for (var partFile in partFiles) {
|
|
if (!analyzedFiles.contains(partFile)) {
|
|
reportPartError(partFile.path);
|
|
}
|
|
}
|
|
|
|
formatter.flush();
|
|
|
|
if (!options.machineFormat && !options.jsonFormat) {
|
|
stats.print(outSink);
|
|
}
|
|
|
|
return allResult;
|
|
}
|
|
|
|
/// Collect all analyzable files at [filePath], recursively if it's a
|
|
/// directory, ignoring links.
|
|
Iterable<io.File> _collectFiles(String filePath) {
|
|
var files = <io.File>[];
|
|
var file = io.File(filePath);
|
|
if (file.existsSync()) {
|
|
files.add(file);
|
|
} else {
|
|
var directory = io.Directory(filePath);
|
|
if (directory.existsSync()) {
|
|
var pathContext = resourceProvider.pathContext;
|
|
for (var entry in directory.listSync(
|
|
recursive: true,
|
|
followLinks: false,
|
|
)) {
|
|
var relative = path.relative(entry.path, from: directory.path);
|
|
if ((file_paths.isDart(pathContext, entry.path) ||
|
|
file_paths.isAndroidManifestXml(pathContext, entry.path)) &&
|
|
entry is io.File &&
|
|
!pathFilter.ignored(entry.path) &&
|
|
!_isInHiddenDir(relative)) {
|
|
files.add(entry);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return files;
|
|
}
|
|
|
|
/// Returns `true` if this relative path is a hidden directory.
|
|
bool _isInHiddenDir(String relative) =>
|
|
path.split(relative).any((part) => part.startsWith('.'));
|
|
|
|
/// Analyze a single source.
|
|
Future<DiagnosticSeverity> _runAnalyzer(
|
|
FileState file,
|
|
CommandLineOptions options,
|
|
ErrorFormatter formatter,
|
|
) {
|
|
var startTime = currentTimeMillis;
|
|
final analysisDriver = this.analysisDriver!;
|
|
var analysisOptions = analysisDriver.getAnalysisOptionsForFile(
|
|
file.resource,
|
|
);
|
|
var analyzer = AnalyzerImpl(
|
|
analysisOptions,
|
|
analysisDriver,
|
|
file,
|
|
options,
|
|
stats,
|
|
startTime,
|
|
);
|
|
return analyzer.analyze(formatter);
|
|
}
|
|
|
|
bool _shouldBeFatal(DiagnosticSeverity severity) =>
|
|
severity == DiagnosticSeverity.ERROR;
|
|
|
|
void _verifyAnalysisOptionsFileExists(CommandLineOptions options) {
|
|
var path = options.defaultAnalysisOptionsPath;
|
|
if (path != null) {
|
|
if (!resourceProvider.getFile(path).exists) {
|
|
printAndFail(
|
|
'Options file not found: $path',
|
|
exitCode: DiagnosticSeverity.ERROR.ordinal,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void verbosePrint(String text) {
|
|
outSink.writeln(text);
|
|
}
|
|
|
|
/// Return whether the [newOptions] are equal to the [previous].
|
|
static bool _equalCommandLineOptions(
|
|
CommandLineOptions? previous,
|
|
CommandLineOptions newOptions,
|
|
) {
|
|
return previous != null &&
|
|
newOptions.defaultPackagesPath == previous.defaultPackagesPath &&
|
|
_equalMaps(newOptions.declaredVariables, previous.declaredVariables) &&
|
|
newOptions.log == previous.log &&
|
|
newOptions.disableCacheFlushing == previous.disableCacheFlushing &&
|
|
_equalLists(newOptions.enabledExperiments, previous.enabledExperiments);
|
|
}
|
|
|
|
/// Perform a deep comparison of two string lists.
|
|
static bool _equalLists(List<String> l1, List<String> l2) {
|
|
if (l1.length != l2.length) {
|
|
return false;
|
|
}
|
|
for (var i = 0; i < l1.length; i++) {
|
|
if (l1[i] != l2[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// Perform a deep comparison of two string maps.
|
|
static bool _equalMaps(Map<String, String> m1, Map<String, String> m2) {
|
|
if (m1.length != m2.length) {
|
|
return false;
|
|
}
|
|
for (var key in m1.keys) {
|
|
if (!m2.containsKey(key) || m1[key] != m2[key]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
class _AnalysisContextProvider {
|
|
final ResourceProvider _resourceProvider;
|
|
final FileContentCache _fileContentCache;
|
|
|
|
CommandLineOptions? _commandLineOptions;
|
|
late List<String> _pathList;
|
|
|
|
final List<AnalysisContextCollectionImpl> _toDispose = [];
|
|
final Map<Folder, DriverBasedAnalysisContext?> _folderContexts = {};
|
|
AnalysisContextCollectionImpl? _collection;
|
|
DriverBasedAnalysisContext? _analysisContext;
|
|
|
|
_AnalysisContextProvider(this._resourceProvider)
|
|
: _fileContentCache = FileContentCache(_resourceProvider);
|
|
|
|
DriverBasedAnalysisContext? get analysisContext {
|
|
return _analysisContext;
|
|
}
|
|
|
|
AnalysisDriver get analysisDriver {
|
|
return _analysisContext!.driver;
|
|
}
|
|
|
|
// TODO(scheglov): Use analyzedFiles()
|
|
PathFilter get pathFilter {
|
|
var contextRoot = analysisContext!.contextRoot;
|
|
var optionsFile = contextRoot.optionsFile;
|
|
|
|
// If there is no options file, there can be no excludes.
|
|
if (optionsFile == null) {
|
|
return PathFilter(contextRoot.root.path, contextRoot.root.path, []);
|
|
}
|
|
|
|
// Exclude patterns are relative to the directory with the options file.
|
|
return PathFilter(
|
|
contextRoot.root.path,
|
|
optionsFile.parent.path,
|
|
analysisContext!.getAnalysisOptionsForFile(optionsFile).excludePatterns,
|
|
);
|
|
}
|
|
|
|
void configureForPath(String path) {
|
|
var folder = _resourceProvider.getFolder(path);
|
|
if (!folder.exists) {
|
|
folder = _resourceProvider.getFile(path).parent;
|
|
}
|
|
|
|
// In batch mode we are given separate file paths to analyze.
|
|
// All files of a folder have the same configuration.
|
|
// So, reuse the corresponding analysis context.
|
|
_analysisContext = _folderContexts[folder];
|
|
if (_analysisContext != null) {
|
|
return;
|
|
}
|
|
|
|
if (_collection != null) {
|
|
try {
|
|
_setContextForPath(path);
|
|
return;
|
|
} on StateError {
|
|
// The previous collection cannot analyze the path.
|
|
_collection = null;
|
|
}
|
|
}
|
|
|
|
_collection = AnalysisContextCollectionImpl(
|
|
byteStore: Driver.analysisDriverMemoryByteStore,
|
|
includedPaths: _pathList,
|
|
optionsFile: _commandLineOptions!.defaultAnalysisOptionsPath,
|
|
packagesFile: _commandLineOptions!.defaultPackagesPath,
|
|
resourceProvider: _resourceProvider,
|
|
sdkPath: _commandLineOptions!.dartSdkPath,
|
|
updateAnalysisOptions3: _updateAnalysisOptions,
|
|
fileContentCache: _fileContentCache,
|
|
);
|
|
_toDispose.add(_collection!);
|
|
|
|
_setContextForPath(path);
|
|
_folderContexts[folder] = _analysisContext;
|
|
}
|
|
|
|
Future<void> dispose() async {
|
|
_collection = null;
|
|
var toDispose = _toDispose.toList();
|
|
_toDispose.clear();
|
|
for (var collection in toDispose) {
|
|
await collection.dispose();
|
|
}
|
|
}
|
|
|
|
void setCommandLineOptions(
|
|
CommandLineOptions options,
|
|
List<String> pathList,
|
|
) {
|
|
if (!Driver._equalCommandLineOptions(_commandLineOptions, options)) {
|
|
_folderContexts.clear();
|
|
_collection = null;
|
|
_analysisContext = null;
|
|
}
|
|
_commandLineOptions = options;
|
|
_pathList = pathList;
|
|
}
|
|
|
|
void _setContextForPath(String path) {
|
|
_analysisContext = _collection!.contextFor(path);
|
|
}
|
|
|
|
void _updateAnalysisOptions({
|
|
required AnalysisOptionsImpl analysisOptions,
|
|
required DartSdk sdk,
|
|
}) {
|
|
_commandLineOptions!.updateAnalysisOptions(analysisOptions);
|
|
}
|
|
}
|