@@ -69,6 +69,13 @@ class DartLocation {
6969 this .column,
7070 );
7171
72+ int compareTo (DartLocation other) => compareToLine (other.line, other.column);
73+
74+ int compareToLine (int otherLine, int otherColumn) {
75+ var result = line.compareTo (otherLine);
76+ return result == 0 ? column.compareTo (otherColumn) : result;
77+ }
78+
7279 @override
7380 String toString () => '[${uri .serverPath }:$line :$column ]' ;
7481
@@ -92,6 +99,13 @@ class JsLocation {
9299 this .column,
93100 );
94101
102+ int compareTo (JsLocation other) => compareToLine (other.line, other.column);
103+
104+ int compareToLine (int otherLine, int otherColumn) {
105+ var result = line.compareTo (otherLine);
106+ return result == 0 ? column.compareTo (otherColumn) : result;
107+ }
108+
95109 @override
96110 String toString () => '[$module :$line :$column ]' ;
97111
@@ -177,7 +191,7 @@ class Locations {
177191 if (location.dartLocation.line == line &&
178192 location.dartLocation.column >= column) {
179193 bestLocation ?? = location;
180- if (location.dartLocation.column < bestLocation.dartLocation.column ) {
194+ if (location.dartLocation.compareTo ( bestLocation.dartLocation) < 0 ) {
181195 bestLocation = location;
182196 }
183197 }
@@ -188,76 +202,23 @@ class Locations {
188202 /// Find closest existing JavaScript location for the line and column.
189203 ///
190204 /// Some JS locations are not stored in the source maps, so we find the
191- /// closest existing location, preferring the one coming after the given
192- /// column, if the current break is at an expression statement, or the
193- /// one coming before if the current break is at a function call.
205+ /// closest existing location coming before the given column.
194206 ///
195207 /// This is a known problem that other code bases solve using by finding
196208 /// the closest location to the current one:
197209 ///
198210 /// https://github.com/microsoft/vscode-js-debug/blob/536f96bae61a3d87546b61bc7916097904c81429/src/common/sourceUtils.ts#L286
199- ///
200- /// Unfortunately, this approach fails for Flutter code too often, as it
201- /// frequently contains multi-line statements with nested objects.
202- ///
203- /// For example:
204- ///
205- /// - `t33 = main.doSomething()` in top frame:
206- /// Current column is at `t33`. Return existing location starting
207- /// at `main`.
208- /// - `main.doSomething()` in top frame:
209- /// Current column is at `main`. Return existing location starting
210- /// at `main`.
211- /// - `main.doSomething()` in a frame down the stack:
212- /// Current column is at `doSomething`. Source map does not have a
213- /// location stored that starts at `doSomething()`. Return existing
214- /// location starting at `main`.
215211 Location _bestJsLocation (Iterable <Location > locations, int line, int column) {
216- Location bestLocationBefore;
217- Location bestLocationAfter;
218-
219- var locationsAfter = locations.where ((location) =>
220- location.jsLocation.line == line &&
221- location.jsLocation.column >= column);
222- var locationsBefore = locations.where ((location) =>
223- location.jsLocation.line == line &&
224- location.jsLocation.column < column);
225-
226- for (var location in locationsAfter) {
227- bestLocationAfter ?? = location;
228- if (location.jsLocation.column < bestLocationAfter.jsLocation.column) {
229- bestLocationAfter = location;
230- }
231- }
232- for (var location in locationsBefore) {
233- bestLocationBefore ?? = location;
234- if (location.jsLocation.column > bestLocationBefore.jsLocation.column) {
235- bestLocationBefore = location;
212+ Location bestLocation;
213+ for (var location in locations) {
214+ if (location.jsLocation.compareToLine (line, column) <= 0 ) {
215+ bestLocation ?? = location;
216+ if (location.jsLocation.compareTo (bestLocation.jsLocation) > 0 ) {
217+ bestLocation = location;
218+ }
236219 }
237220 }
238- if (bestLocationAfter == null ) return bestLocationBefore;
239- if (bestLocationBefore == null ) return bestLocationAfter;
240-
241- if (bestLocationAfter.jsLocation.line == line &&
242- bestLocationAfter.jsLocation.column == column) {
243- // Prefer exact match.
244- return bestLocationAfter;
245- }
246-
247- // Return the closest location after the current if the current location
248- // is at the beginning of the line (i.e. on expression statement).
249- // Return the closest location before the current if the current location
250- // is in the middle of the line (i.e. on function call).
251- if (locationsBefore.length == 1 &&
252- locationsBefore.first.jsLocation.column == 0 ) {
253- // Best guess on whether the the current location is at the beginning of
254- // the line (i.e. expression statement):
255- // The only location on the left has column 0, so only spaces are on the
256- // left.
257- return bestLocationAfter;
258- }
259- // Current column is in the middle of the line (i.e .function call).
260- return bestLocationBefore;
221+ return bestLocation;
261222 }
262223
263224 /// Returns the tokenPosTable for the provided Dart script path as defined
0 commit comments