mirror of
https://github.com/dart-lang/sdk
synced 2024-09-06 00:59:09 +00:00
Add navigation targets to the containing unit info
Change-Id: I5d4707f019254e9b338eae23bb8a9fb61ef14e54 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119085 Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
30b2a5dbb3
commit
6eaebb8463
|
@ -35,6 +35,10 @@ class InfoBuilder {
|
|||
/// The listener used to gather the changes to be applied.
|
||||
final DartFixListener listener;
|
||||
|
||||
/// A map from the path of a compilation unit to the information about that
|
||||
/// unit.
|
||||
final Map<String, UnitInfo> unitMap = {};
|
||||
|
||||
/// Initialize a newly created builder.
|
||||
InfoBuilder(this.info, this.listener);
|
||||
|
||||
|
@ -112,46 +116,47 @@ class InfoBuilder {
|
|||
/// Return the migration information for the given unit.
|
||||
UnitInfo _explainUnit(SourceInformation sourceInfo, ParsedUnitResult result,
|
||||
SourceFileEdit fileEdit) {
|
||||
List<RegionInfo> regions = [];
|
||||
UnitInfo unitInfo = _unitForPath(result.path);
|
||||
String content = result.content;
|
||||
// [fileEdit] is null when a file has no edits.
|
||||
if (fileEdit == null) {
|
||||
return UnitInfo(result.path, content, regions);
|
||||
}
|
||||
List<SourceEdit> edits = fileEdit.edits;
|
||||
edits.sort((first, second) => first.offset.compareTo(second.offset));
|
||||
// Compute the deltas for the regions that will be computed as we apply the
|
||||
// edits. We need the deltas because the offsets to the regions are relative
|
||||
// to the edited source, but the edits are being applied in reverse order so
|
||||
// the offset in the pre-edited source will not match the offset in the
|
||||
// post-edited source. The deltas compensate for that difference.
|
||||
List<int> deltas = [];
|
||||
int previousDelta = 0;
|
||||
for (SourceEdit edit in edits) {
|
||||
deltas.add(previousDelta);
|
||||
previousDelta += (edit.replacement.length - edit.length);
|
||||
}
|
||||
// Apply edits in reverse order and build the regions.
|
||||
int index = edits.length - 1;
|
||||
for (SourceEdit edit in edits.reversed) {
|
||||
int offset = edit.offset;
|
||||
int length = edit.length;
|
||||
String replacement = edit.replacement;
|
||||
int end = offset + length;
|
||||
int delta = deltas[index--];
|
||||
// Insert the replacement text without deleting the replaced text.
|
||||
content = content.replaceRange(end, end, replacement);
|
||||
FixInfo fixInfo = _findFixInfo(sourceInfo, offset);
|
||||
String explanation = '${fixInfo.fix.description.appliedMessage}.';
|
||||
List<RegionDetail> details = _computeDetails(fixInfo);
|
||||
if (length > 0) {
|
||||
regions.add(RegionInfo(offset + delta, length, explanation, details));
|
||||
if (fileEdit != null) {
|
||||
List<RegionInfo> regions = unitInfo.regions;
|
||||
List<SourceEdit> edits = fileEdit.edits;
|
||||
edits.sort((first, second) => first.offset.compareTo(second.offset));
|
||||
// Compute the deltas for the regions that will be computed as we apply the
|
||||
// edits. We need the deltas because the offsets to the regions are relative
|
||||
// to the edited source, but the edits are being applied in reverse order so
|
||||
// the offset in the pre-edited source will not match the offset in the
|
||||
// post-edited source. The deltas compensate for that difference.
|
||||
List<int> deltas = [];
|
||||
int previousDelta = 0;
|
||||
for (SourceEdit edit in edits) {
|
||||
deltas.add(previousDelta);
|
||||
previousDelta += (edit.replacement.length - edit.length);
|
||||
}
|
||||
regions.add(
|
||||
RegionInfo(end + delta, replacement.length, explanation, details));
|
||||
// Apply edits in reverse order and build the regions.
|
||||
int index = edits.length - 1;
|
||||
for (SourceEdit edit in edits.reversed) {
|
||||
int offset = edit.offset;
|
||||
int length = edit.length;
|
||||
String replacement = edit.replacement;
|
||||
int end = offset + length;
|
||||
int delta = deltas[index--];
|
||||
// Insert the replacement text without deleting the replaced text.
|
||||
content = content.replaceRange(end, end, replacement);
|
||||
FixInfo fixInfo = _findFixInfo(sourceInfo, offset);
|
||||
String explanation = '${fixInfo.fix.description.appliedMessage}.';
|
||||
List<RegionDetail> details = _computeDetails(fixInfo);
|
||||
if (length > 0) {
|
||||
regions.add(RegionInfo(offset + delta, length, explanation, details));
|
||||
}
|
||||
regions.add(
|
||||
RegionInfo(end + delta, replacement.length, explanation, details));
|
||||
}
|
||||
regions.sort((first, second) => first.offset.compareTo(second.offset));
|
||||
}
|
||||
regions.sort((first, second) => first.offset.compareTo(second.offset));
|
||||
return UnitInfo(result.path, content, regions);
|
||||
unitInfo.content = content;
|
||||
return unitInfo;
|
||||
}
|
||||
|
||||
/// Return information about the fix that was applied at the given [offset],
|
||||
|
@ -168,8 +173,19 @@ class InfoBuilder {
|
|||
return null;
|
||||
}
|
||||
|
||||
/// Return the navigation target
|
||||
NavigationTarget _targetFor(EdgeOriginInfo origin) {
|
||||
AstNode node = origin.node;
|
||||
return NavigationTarget(origin.source.fullName, node.offset, node.length);
|
||||
String filePath = origin.source.fullName;
|
||||
UnitInfo unitInfo = _unitForPath(filePath);
|
||||
NavigationTarget target =
|
||||
NavigationTarget(filePath, node.offset, node.length);
|
||||
unitInfo.targets.add(target);
|
||||
return target;
|
||||
}
|
||||
|
||||
/// Return the unit info for the file at the given [path].
|
||||
UnitInfo _unitForPath(String path) {
|
||||
return unitMap.putIfAbsent(path, () => UnitInfo(path));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// 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/src/generated/utilities_general.dart';
|
||||
|
||||
/// The migration information associated with a single library.
|
||||
class LibraryInfo {
|
||||
/// The information about the units in the library. The information about the
|
||||
|
@ -24,7 +26,18 @@ class NavigationTarget {
|
|||
final int length;
|
||||
|
||||
/// Initialize a newly created anchor.
|
||||
const NavigationTarget(this.filePath, this.offset, this.length);
|
||||
NavigationTarget(this.filePath, this.offset, this.length);
|
||||
|
||||
@override
|
||||
int get hashCode => JenkinsSmiHash.hash3(filePath.hashCode, offset, length);
|
||||
|
||||
@override
|
||||
bool operator ==(other) {
|
||||
return other is NavigationTarget &&
|
||||
other.filePath == filePath &&
|
||||
other.offset == offset &&
|
||||
other.length == length;
|
||||
}
|
||||
}
|
||||
|
||||
/// An additional detail related to a region.
|
||||
|
@ -65,12 +78,15 @@ class UnitInfo {
|
|||
final String path;
|
||||
|
||||
/// The content of unit.
|
||||
final String content;
|
||||
String content;
|
||||
|
||||
/// The information about the regions that have an explanation associated with
|
||||
/// them.
|
||||
final List<RegionInfo> regions;
|
||||
final List<RegionInfo> regions = [];
|
||||
|
||||
/// The navigation targets that are located in this file.
|
||||
final Set<NavigationTarget> targets = {};
|
||||
|
||||
/// Initialize a newly created unit.
|
||||
UnitInfo(this.path, this.content, this.regions);
|
||||
UnitInfo(this.path);
|
||||
}
|
||||
|
|
|
@ -19,12 +19,12 @@ main() {
|
|||
class InstrumentationRendererTest extends AbstractAnalysisTest {
|
||||
test_outputContainsEachPath() async {
|
||||
LibraryInfo info = LibraryInfo([
|
||||
UnitInfo('/lib/a.dart', 'int? a = null;',
|
||||
[RegionInfo(3, 1, 'null was assigned', [])]),
|
||||
UnitInfo('/lib/part1.dart', 'int? b = null;',
|
||||
[RegionInfo(3, 1, 'null was assigned', [])]),
|
||||
UnitInfo('/lib/part2.dart', 'int? c = null;',
|
||||
[RegionInfo(3, 1, 'null was assigned', [])]),
|
||||
unit('/lib/a.dart', 'int? a = null;',
|
||||
regions: [RegionInfo(3, 1, 'null was assigned', [])]),
|
||||
unit('/lib/part1.dart', 'int? b = null;',
|
||||
regions: [RegionInfo(3, 1, 'null was assigned', [])]),
|
||||
unit('/lib/part2.dart', 'int? c = null;',
|
||||
regions: [RegionInfo(3, 1, 'null was assigned', [])]),
|
||||
]);
|
||||
String output = InstrumentationRenderer(info).render();
|
||||
expect(output, contains('<h2>/lib/a.dart</h2>'));
|
||||
|
@ -34,8 +34,8 @@ class InstrumentationRendererTest extends AbstractAnalysisTest {
|
|||
|
||||
test_outputContainsEscapedHtml() async {
|
||||
LibraryInfo info = LibraryInfo([
|
||||
UnitInfo('/lib/a.dart', 'List<String>? a = null;',
|
||||
[RegionInfo(12, 1, 'null was assigned', [])]),
|
||||
unit('/lib/a.dart', 'List<String>? a = null;',
|
||||
regions: [RegionInfo(12, 1, 'null was assigned', [])]),
|
||||
]);
|
||||
String output = InstrumentationRenderer(info).render();
|
||||
expect(
|
||||
|
@ -46,7 +46,7 @@ class InstrumentationRendererTest extends AbstractAnalysisTest {
|
|||
|
||||
test_outputContainsEscapedHtml_ampersand() async {
|
||||
LibraryInfo info = LibraryInfo([
|
||||
UnitInfo('/lib/a.dart', 'bool a = true && false;', []),
|
||||
unit('/lib/a.dart', 'bool a = true && false;', regions: []),
|
||||
]);
|
||||
String output = InstrumentationRenderer(info).render();
|
||||
expect(output, contains('bool a = true && false;'));
|
||||
|
@ -54,8 +54,8 @@ class InstrumentationRendererTest extends AbstractAnalysisTest {
|
|||
|
||||
test_outputContainsModifiedAndUnmodifiedRegions() async {
|
||||
LibraryInfo info = LibraryInfo([
|
||||
UnitInfo('/lib/a.dart', 'int? a = null;',
|
||||
[RegionInfo(3, 1, 'null was assigned', [])]),
|
||||
unit('/lib/a.dart', 'int? a = null;',
|
||||
regions: [RegionInfo(3, 1, 'null was assigned', [])]),
|
||||
]);
|
||||
String output = InstrumentationRenderer(info).render();
|
||||
expect(
|
||||
|
@ -63,4 +63,10 @@ class InstrumentationRendererTest extends AbstractAnalysisTest {
|
|||
contains('int<span class="region">?'
|
||||
'<span class="tooltip">null was assigned</span></span> a = null;'));
|
||||
}
|
||||
|
||||
UnitInfo unit(String path, String content, {List<RegionInfo> regions}) {
|
||||
return UnitInfo(path)
|
||||
..content = content
|
||||
..regions.addAll(regions);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue