bulk fix change mapping
Striving to do the "simplest thing that could possibly work" this may just be a conversation starter.
Change-Id: Id3deab6fd1541febbc090c696352563e6b5ce932
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/172460
Commit-Queue: Phil Quitslund <pquitslund@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index e739602..2e797f0 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -71,6 +71,7 @@
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
@@ -351,11 +352,13 @@
/// diagnostics.
ChangeBuilder builder;
+ /// A map associating libraries to fixes with change counts.
+ final ChangeMap changeMap = ChangeMap();
+
/// Initialize a newly created processor to create fixes for diagnostics in
/// libraries in the [workspace].
- BulkFixProcessor(this.instrumentationService, this.workspace) {
- builder = ChangeBuilder(workspace: workspace);
- }
+ BulkFixProcessor(this.instrumentationService, this.workspace)
+ : builder = ChangeBuilder(workspace: workspace);
/// Return a change builder that has been used to create fixes for the
/// diagnostics in the libraries in the given [contexts].
@@ -431,19 +434,38 @@
}
}
+ int computeChangeHash() {
+ var hash = 0;
+ var edits = builder.sourceChange.edits;
+ for (var i = 0; i < edits.length; ++i) {
+ hash = JenkinsSmiHash.combine(hash, edits[i].hashCode);
+ }
+ return JenkinsSmiHash.finish(hash);
+ }
+
+ Future<void> generate(CorrectionProducer producer, String code) async {
+ var oldHash = computeChangeHash();
+ await compute(producer);
+ var newHash = computeChangeHash();
+ if (newHash != oldHash) {
+ changeMap.add(result.path, code);
+ }
+ }
+
var errorCode = diagnostic.errorCode;
try {
+ var codeName = errorCode.name;
if (errorCode is LintCode) {
- var generators = lintProducerMap[errorCode.name];
+ var generators = lintProducerMap[codeName];
if (generators != null) {
for (var generator in generators) {
- await compute(generator());
+ await generate(generator(), codeName);
}
}
} else {
var generator = nonLintProducerMap[errorCode];
if (generator != null) {
- await compute(generator());
+ await generate(generator(), codeName);
}
var multiGenerators = nonLintMultiProducerMap[errorCode];
if (multiGenerators != null) {
@@ -451,7 +473,7 @@
var multiProducer = multiGenerator();
multiProducer.configure(context);
for (var producer in multiProducer.producers) {
- await compute(producer);
+ await generate(producer, codeName);
}
}
}
@@ -464,3 +486,15 @@
}
}
}
+
+/// Maps changes to library paths.
+class ChangeMap {
+ /// Map of paths to maps of codes to counts.
+ final Map<String, Map<String, int>> libraryMap = {};
+
+ /// Add an entry for the given [code] in the given [libraryPath].
+ void add(String libraryPath, String code) {
+ var changes = libraryMap.putIfAbsent(libraryPath, () => {});
+ changes.update(code, (value) => value + 1, ifAbsent: () => 1);
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
index 3e9e14c..1f45cc4 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
@@ -36,7 +36,7 @@
}
Future<void> assertHasFix(String expected) async {
- change = await _computeFixes();
+ change = await _computeSourceChange();
// apply to "file"
var fileEdits = change.edits;
@@ -48,11 +48,22 @@
}
Future<void> assertNoFix() async {
- change = await _computeFixes();
+ change = await _computeSourceChange();
var fileEdits = change.edits;
expect(fileEdits, isEmpty);
}
+ /// Computes fixes for the specified [testUnit].
+ Future<BulkFixProcessor> computeFixes() async {
+ var tracker = DeclarationsTracker(MemoryByteStore(), resourceProvider);
+ var analysisContext = contextFor(testFile);
+ tracker.addContext(analysisContext);
+ var processor =
+ BulkFixProcessor(InstrumentationService.NULL_SERVICE, workspace);
+ await processor.fixErrors([analysisContext]);
+ return processor;
+ }
+
@override
void setUp() {
super.setUp();
@@ -60,15 +71,10 @@
_createAnalysisOptionsFile();
}
- /// Computes fixes for the given [error] in [testUnit].
- Future<SourceChange> _computeFixes() async {
- var tracker = DeclarationsTracker(MemoryByteStore(), resourceProvider);
- var analysisContext = contextFor(testFile);
- tracker.addContext(analysisContext);
- var changeBuilder =
- await BulkFixProcessor(InstrumentationService.NULL_SERVICE, workspace)
- .fixErrors([analysisContext]);
- return changeBuilder.sourceChange;
+ /// Returns the source change for computed fixes in the specified [testUnit].
+ Future<SourceChange> _computeSourceChange() async {
+ var processor = await computeFixes();
+ return processor.builder.sourceChange;
}
/// Create the analysis options file needed in order to correctly analyze the
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart
new file mode 100644
index 0000000..8ac6ee0
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2020, 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:analysis_server/src/services/linter/lint_names.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'bulk_fix_processor.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ChangeMapTest);
+ });
+}
+
+@reflectiveTest
+class ChangeMapTest extends BulkFixProcessorTest {
+ Future<void> test_changeMap() async {
+ createAnalysisOptionsFile(experiments: experiments, lints: [
+ LintNames.annotate_overrides,
+ LintNames.unnecessary_new,
+ ]);
+
+ await resolveTestCode('''
+class A { }
+
+var a = new A();
+var aa = new A();
+''');
+
+ var processor = await computeFixes();
+ var changeMap = processor.changeMap;
+ var errors = changeMap.libraryMap[testFile];
+ expect(errors, hasLength(1));
+ expect(errors[LintNames.unnecessary_new], 2);
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
index 3b98bfd..14012da 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
@@ -9,6 +9,7 @@
import 'add_diagnostic_property_reference_test.dart'
as add_diagnostic_property_reference;
import 'add_override_test.dart' as add_override;
+import 'bulk_fix_processor_test.dart' as bulk_fix_processor;
import 'convert_documentation_into_line_test.dart'
as convert_documentation_into_line;
import 'convert_map_from_iterable_to_for_literal_test.dart'
@@ -70,6 +71,7 @@
add_const.main();
add_diagnostic_property_reference.main();
add_override.main();
+ bulk_fix_processor.main();
convert_documentation_into_line.main();
convert_map_from_iterable_to_for_literal.main();
convert_to_contains.main();