Skip to content

Commit bf40c24

Browse files
committed
dap: improve location resolution for duplicate digests
This improves location resolution for duplicate digests by making some assumptions about the file structure to determine a "best match" when there are multiple possible locations. It uses the next operation (that this digest is the input for) to determine a location. If the location of the current operation is before the next operation, this location is preferred. If there are multiple locations that happen before the next operation, the one closest to the next operation (aka later in the file) is used instead. This resolves the most common case of multiple identical `FROM` statements without adding more code to the frontends themselves. Signed-off-by: Jonathan A. Sternberg <[email protected]>
1 parent bafc4e2 commit bf40c24

File tree

2 files changed

+46
-19
lines changed

2 files changed

+46
-19
lines changed

dap/thread.go

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,11 @@ type thread struct {
3333
sourcePath string
3434

3535
// LLB state for the evaluate call.
36-
def *llb.Definition
37-
ops map[digest.Digest]*pb.Op
38-
head digest.Digest
39-
bps map[digest.Digest]int
40-
41-
frames map[int32]*frame
42-
framesByDigest map[digest.Digest]*frame
36+
def *llb.Definition
37+
ops map[digest.Digest]*pb.Op
38+
head digest.Digest
39+
bps map[digest.Digest]int
40+
frames map[int32]*frame
4341

4442
// Runtime state for the evaluate call.
4543
entrypoint *step
@@ -141,14 +139,13 @@ type step struct {
141139
}
142140

143141
func (t *thread) createProgram() error {
144-
t.framesByDigest = make(map[digest.Digest]*frame)
145142
t.frames = make(map[int32]*frame)
146143

147144
// Create the entrypoint by using the last node.
148145
// We will build on top of that.
149146
head := &step{
150147
dgst: t.head,
151-
frame: t.getStackFrame(t.head),
148+
frame: t.getStackFrame(t.head, nil),
152149
}
153150
t.entrypoint = t.createBranch(head)
154151
return nil
@@ -166,7 +163,7 @@ func (t *thread) createBranch(last *step) (first *step) {
166163
// exit point always matches the one set on first
167164
out: first.out,
168165
// always set to the same as next which is always first
169-
frame: t.getStackFrame(first.dgst),
166+
frame: t.getStackFrame(first.dgst, first),
170167
}
171168

172169
op := t.ops[first.dgst]
@@ -195,7 +192,7 @@ func (t *thread) createBranch(last *step) (first *step) {
195192
in: exit,
196193
next: exit,
197194
out: exit,
198-
frame: t.getStackFrame(digest.Digest(inp.Digest)),
195+
frame: t.getStackFrame(digest.Digest(inp.Digest), nil),
199196
}
200197
prev.in = t.createBranch(head)
201198
}
@@ -213,11 +210,7 @@ func (t *thread) createBranch(last *step) (first *step) {
213210
return first
214211
}
215212

216-
func (t *thread) getStackFrame(dgst digest.Digest) *frame {
217-
if f := t.framesByDigest[dgst]; f != nil {
218-
return f
219-
}
220-
213+
func (t *thread) getStackFrame(dgst digest.Digest, next *step) *frame {
221214
f := &frame{
222215
op: t.ops[dgst],
223216
}
@@ -226,7 +219,7 @@ func (t *thread) getStackFrame(dgst digest.Digest) *frame {
226219
f.setNameFromMeta(meta)
227220
}
228221
if loc, ok := t.def.Source.Locations[string(dgst)]; ok {
229-
f.fillLocation(t.def, loc, t.sourcePath)
222+
f.fillLocation(t.def, loc, t.sourcePath, next)
230223
}
231224
t.frames[int32(f.Id)] = f
232225
return f

dap/variables.go

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,17 @@ func (f *frame) setNameFromMeta(meta llb.OpMetadata) {
3535
// TODO: should we infer the name from somewhere else?
3636
}
3737

38-
func (f *frame) fillLocation(def *llb.Definition, loc *pb.Locations, ws string) {
38+
func (f *frame) fillLocation(def *llb.Definition, loc *pb.Locations, ws string, next *step) {
3939
for _, l := range loc.Locations {
4040
for _, r := range l.Ranges {
41+
if next != nil && f.Line != 0 {
42+
// We have location information. See if the new location
43+
// information matches with our location better.
44+
if !betterLocation(r, f, next) {
45+
continue
46+
}
47+
}
48+
4149
f.Line = int(r.Start.Line)
4250
f.Column = int(r.Start.Character)
4351
f.EndLine = int(r.End.Line)
@@ -48,7 +56,13 @@ func (f *frame) fillLocation(def *llb.Definition, loc *pb.Locations, ws string)
4856
Name: path.Base(info.Filename),
4957
Path: filepath.Join(ws, info.Filename),
5058
}
51-
return
59+
60+
// If we do not have a next operation, then we don't have
61+
// any information to make a determination about the "best" fit
62+
// that happens at the beginning of this section. Exit early.
63+
if next == nil {
64+
return
65+
}
5266
}
5367
}
5468
}
@@ -402,3 +416,23 @@ func brief(s string) string {
402416
}
403417
return s
404418
}
419+
420+
func betterLocation(r *pb.Range, f *frame, next *step) bool {
421+
// Ideal guess is one that is before the next frame.
422+
if int(r.Start.Line) <= next.frame.Line {
423+
// And is later than our current guess.
424+
if int(r.Start.Line) > f.Line {
425+
return true
426+
}
427+
}
428+
429+
// We're after the next frame so this is a bad guess.
430+
// Was our original one even worse?
431+
if int(r.Start.Line) < f.Line {
432+
// Yes it was. We'll consider this a better location.
433+
return true
434+
}
435+
436+
// Doesn't seem to be a better location.
437+
return false
438+
}

0 commit comments

Comments
 (0)