Files
sdk/pkg/analyzer/test/source/error_processor_test.dart
T
Sam Rawlins e29aa0cf3f analyzer: Convert applyOptions extension method into AnalysisOptionsBuilder builder.
Previously, the fields in an AnalysisOptionsImpl were primarily
arranged by an extension method, declared externally, called
`applyOptions`. It seemed very odd that this wasn't just a method on
AnalysisOptionsImpl; the "Impl" class is already private.

But it turns out that an AnalysisOptionsImpl is _mostly_ not mutated
in practice; the class wants to be immutable, with final fields.

In this change, I make AnalysisOptionsImpl mostly immutable, and
convert the `applyOptions` extension method, and all of its helper
code, into a builder class, AnalysisOptionsBuilder. While we don't
use a lot of builders in analyzer packages, this is a much more common
and idiomatic pattern for setting up complicated data, multiple values,
and then finalizing it all into an object that will not be changed
again during it's lifetime.

One big benefit of this refactoring is that most fields in AnalysisOptionsImpl are now final:

* sourceLanguageConstraint
* errorProcessors
* excludePatterns
* file
* strictCasts
* strictInference
* strictRawTypes
* chromeOsManifestChecks
* codeStyleOptions
* formatterOptions
* unignorableNames

Whereas before, they _all_ had to be mutable, as `applyOptions`, the
primary mechanism for setting up an AnalysisOptionsImpl, had to able
to write any field.

Other changes:

* Flip the instantiation of AnalysisOptionsImpl and CodeStyleOptions;
  now CodeStyleOptions is instatiated first, and AnalysisOptionsImpl
  sets itself as `codeStyleOptions.options`.
* Remove the private, deprecated, `applyToAnalysisOptions` function.

Change-Id: I6595d88aa5721e4f9a8b2b987482f9f43d27efd1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/390660
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
2024-10-17 21:54:40 +00:00

182 lines
5.6 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 'package:analyzer/error/error.dart';
import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/src/analysis_options/analysis_options_provider.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:collection/collection.dart';
import 'package:test/test.dart';
import 'package:yaml/yaml.dart';
import '../generated/test_support.dart';
import '../src/util/yaml_test.dart';
main() {
AnalysisError invalid_assignment = AnalysisError.tmp(
source: TestSource(),
offset: 0,
length: 1,
errorCode: CompileTimeErrorCode.INVALID_ASSIGNMENT,
arguments: [
['x'],
['y'],
],
);
AnalysisError assignment_of_do_not_store = AnalysisError.tmp(
source: TestSource(),
offset: 0,
length: 1,
errorCode: WarningCode.ASSIGNMENT_OF_DO_NOT_STORE,
arguments: [
['x'],
],
);
AnalysisError unused_local_variable = AnalysisError.tmp(
source: TestSource(),
offset: 0,
length: 1,
errorCode: WarningCode.UNUSED_LOCAL_VARIABLE,
arguments: [
['x'],
],
);
AnalysisError use_of_void_result = AnalysisError.tmp(
source: TestSource(),
offset: 0,
length: 1,
errorCode: CompileTimeErrorCode.USE_OF_VOID_RESULT,
);
// We in-line a lint code here in order to avoid adding a dependency on the
// linter package.
AnalysisError annotate_overrides = AnalysisError.tmp(
source: TestSource(),
offset: 0,
length: 1,
errorCode: LintCode('annotate_overrides', ''),
);
group('ErrorProcessor', () {
late _TestContext context;
setUp(() {
context = _TestContext();
});
test('configureOptions', () {
context.configureOptions('''
analyzer:
errors:
invalid_assignment: error # severity ERROR
assignment_of_do_not_store: false # ignore
unused_local_variable: true # skipped
use_of_void_result: unsupported_action # skipped
''');
expect(context.getProcessor(invalid_assignment)!.severity,
ErrorSeverity.ERROR);
expect(
context.getProcessor(assignment_of_do_not_store)!.severity, isNull);
expect(context.getProcessor(unused_local_variable), isNull);
expect(context.getProcessor(use_of_void_result), isNull);
});
test('does not upgrade other warnings to errors in strong mode', () {
context.configureOptions('''
analyzer:
strong-mode: true
''');
expect(context.getProcessor(unused_local_variable), isNull);
});
});
group('ErrorConfig', () {
var config = '''
analyzer:
errors:
invalid_assignment: unsupported_action # should be skipped
assignment_of_do_not_store: false
unused_local_variable: error
''';
group('processing', () {
test('yaml map', () {
var options = AnalysisOptionsProvider().getOptionsFromString(config);
var errorConfig = ErrorConfig(
(options['analyzer'] as YamlMap)['errors'] as YamlNode?);
expect(errorConfig.processors, hasLength(2));
// ignore
var missingReturnProcessor = errorConfig.processors
.firstWhere((p) => p.appliesTo(assignment_of_do_not_store));
expect(missingReturnProcessor.severity, isNull);
// error
var unusedLocalProcessor = errorConfig.processors
.firstWhere((p) => p.appliesTo(unused_local_variable));
expect(unusedLocalProcessor.severity, ErrorSeverity.ERROR);
// skip
var invalidAssignmentProcessor = errorConfig.processors
.firstWhereOrNull((p) => p.appliesTo(invalid_assignment));
expect(invalidAssignmentProcessor, isNull);
});
test('string map', () {
var options = wrap({
'invalid_assignment': 'unsupported_action', // should be skipped
'assignment_of_do_not_store': 'false',
'unused_local_variable': 'error'
});
var errorConfig = ErrorConfig(options);
expect(errorConfig.processors, hasLength(2));
// ignore
var missingReturnProcessor = errorConfig.processors
.firstWhere((p) => p.appliesTo(assignment_of_do_not_store));
expect(missingReturnProcessor.severity, isNull);
// error
var unusedLocalProcessor = errorConfig.processors
.firstWhere((p) => p.appliesTo(unused_local_variable));
expect(unusedLocalProcessor.severity, ErrorSeverity.ERROR);
// skip
var invalidAssignmentProcessor = errorConfig.processors
.firstWhereOrNull((p) => p.appliesTo(invalid_assignment));
expect(invalidAssignmentProcessor, isNull);
});
});
test('configure lints', () {
var options = AnalysisOptionsProvider().getOptionsFromString(
'analyzer:\n errors:\n annotate_overrides: warning\n');
var errorConfig =
ErrorConfig((options['analyzer'] as YamlMap)['errors'] as YamlNode?);
expect(errorConfig.processors, hasLength(1));
ErrorProcessor processor = errorConfig.processors.first;
expect(processor.appliesTo(annotate_overrides), true);
expect(processor.severity, ErrorSeverity.WARNING);
});
});
}
class _TestContext {
late AnalysisOptions analysisOptions;
void configureOptions(String options) {
analysisOptions = AnalysisOptionsImpl.fromYaml(
optionsMap: AnalysisOptionsProvider().getOptionsFromString(options));
}
ErrorProcessor? getProcessor(AnalysisError error) {
return ErrorProcessor.getProcessor(analysisOptions, error);
}
}