this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

internal/cuetxtar: fix hidden-field path handling in source AST walker

Previously, extractTestAttrs called appendPath → cue.Label(ident) for
every AST field label. cue.Label returns a path-error selector for hidden
identifiers (_foo) with the message "use Hid to construct". As a result:
- The walkField/walkStruct recursion was silently skipped for any field
whose label is a hidden identifier, so @test annotations inside hidden
fields were never collected.
- applyShareIDAt used cue.ParsePath which likewise rejected hidden labels.
- at= in @test(err) and @test(eq) failed with "invalid path" when the
selector was a package-scoped hidden field like _foo$pkg.

Fixes:
- Add labelSelector(label, hidPkg) that creates cue.Hid(name, pkg) for
hidden idents. Source-file walkers pass hidPkg = ":" + f.PackageName()
(or "_" for anonymous files); eq-body walkers pass "" which triggers
$pkg-suffix parsing (same as astcmp.go).
- Rename appendPath to take the hidPkg argument and use labelSelector.
- extractTestAttrs now computes hidPkg from f.PackageName() and passes it
through walkField/walkStruct closures, so @test annotations on or inside
hidden fields are correctly collected and evaluated.
- parseAtPath (used by at= in @test(err) and @test(eq)) now splits on "."
and applies hidden-field handling to each segment, supporting paths like
a._foo$pkg.b.
- applyShareIDAt uses parseAtPath instead of cue.ParsePath.

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: Ieef7cf72a94a59b269fb6f84dab6c8e2c443cff6
Reviewed-on: https://cue.gerrithub.io/c/cue-lang/cue/+/1235355
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+78 -13
+1 -1
cue/testdata/builtins/and.txtar
··· 9 9 // https://cuelang.org/issue/3719 10 10 issue3719: { 11 11 #openStruct: {...} 12 - _filledLater: #openStruct.foo @test(err, code=incomplete, contains="undefined field: foo", pos=[0:10]) 12 + _filledLater: #openStruct.foo @test(err, code=incomplete, contains="undefined field: foo", pos=[0:28]) 13 13 14 14 // The comprehension below should work regardless of whether it's wrapped in "and". 15 15
+1 -1
cue/testdata/builtins/incomplete.txtar
··· 29 29 // This evaluates to a list with an incomplete element. 30 30 _Top: [ 31 31 for _, F in #Sub {F}, 32 - ] @test(err, code=incomplete, contains="undefined field: b", pos=[]) 32 + ] @test(err, code=incomplete, contains="undefined field: b", pos=[4:10]) 33 33 34 34 #Sub: a.b @test(err, code=incomplete, contains="undefined field: b", pos=[0:10]) 35 35
+74 -9
internal/cuetxtar/inline.go
··· 342 342 func extractTestAttrs(f *ast.File, fileName string) []attrRecord { 343 343 var records []attrRecord 344 344 345 + // hidPkg is the package scope for hidden fields in this file. 346 + // Inline-compiled sources use ":" + pkgname; anonymous files use "_". 347 + hidPkg := ":" + f.PackageName() 348 + if hidPkg == ":" { 349 + hidPkg = "_" 350 + } 351 + 345 352 // appendErrRecord records a @test attribute whose parseTestAttr call failed. 346 353 // The runner reports all parseErr records as test failures before running 347 354 // any assertions. ··· 416 423 }) 417 424 418 425 case *ast.Field: 419 - subPath := appendPath(path, e.Label) 426 + subPath := appendPath(path, e.Label, hidPkg) 420 427 if subPath.Err() == nil { 421 428 walkField(e, subPath) 422 429 } else { ··· 484 491 if !ok { 485 492 continue 486 493 } 487 - fieldPath := cue.MakePath(cue.Label(field.Label)) 494 + fieldPath := appendPath(cue.Path{}, field.Label, hidPkg) 488 495 if fieldPath.Err() == nil { 489 496 walkField(field, fieldPath) 490 497 } ··· 510 517 return "" 511 518 } 512 519 513 - // appendPath appends a selector for label to an existing path. 514 - func appendPath(base cue.Path, label ast.Label) cue.Path { 515 - return base.Append(cue.Label(label)) 520 + // labelSelector returns the cue.Selector for an AST label, correctly handling 521 + // hidden fields (_foo) in two contexts: 522 + // 523 + // - Source-file context: pass hidPkg = ":" + f.PackageName() (or "_" for 524 + // anonymous packages). The package scope is applied to all hidden idents. 525 + // - Eq-body context: pass hidPkg = "". The caller signals that the name may 526 + // carry a $pkg suffix (e.g. "_foo$mypkg"), which is stripped and converted 527 + // to ":" + pkgname. Without a suffix, "_" is used (anonymous hidden field). 528 + func labelSelector(label ast.Label, hidPkg string) cue.Selector { 529 + if ident, ok := label.(*ast.Ident); ok && internal.IsHidden(ident.Name) { 530 + name := ident.Name 531 + pkg := hidPkg 532 + if pkg == "" { 533 + if i := strings.IndexByte(name, '$'); i >= 0 { 534 + pkg = ":" + name[i+1:] 535 + name = name[:i] 536 + } else { 537 + pkg = "_" 538 + } 539 + } 540 + return cue.Hid(name, pkg) 541 + } 542 + return cue.Label(label) 543 + } 544 + 545 + // appendPath appends a selector for label to path. 546 + // hidPkg is forwarded to labelSelector; see its documentation. 547 + func appendPath(base cue.Path, label ast.Label, hidPkg string) cue.Path { 548 + return base.Append(labelSelector(label, hidPkg)) 549 + } 550 + 551 + // parseAtPath parses an at= selector string into a cue.Path. 552 + // Unlike cue.ParsePath, it handles hidden field names with a $pkg qualifier 553 + // (e.g. "_foo$pkg" → cue.Hid("_foo", ":pkg"), matching the same syntax 554 + // accepted inside @test(eq, {...}) bodies). Dotted paths are split on "." and 555 + // each segment is processed independently, so "a._foo$pkg.b" works correctly. 556 + func parseAtPath(at string) (cue.Path, error) { 557 + // Fast path: if there are no hidden-field indicators, delegate directly. 558 + if !strings.Contains(at, "_") { 559 + p := cue.ParsePath(at) 560 + return p, p.Err() 561 + } 562 + var sels []cue.Selector 563 + for _, seg := range strings.Split(at, ".") { 564 + if internal.IsHidden(seg) { 565 + name := seg 566 + pkg := "_" 567 + if i := strings.IndexByte(name, '$'); i >= 0 { 568 + pkg = ":" + name[i+1:] 569 + name = name[:i] 570 + } 571 + sels = append(sels, cue.Hid(name, pkg)) 572 + } else { 573 + p := cue.ParsePath(seg) 574 + if err := p.Err(); err != nil { 575 + return cue.Path{}, err 576 + } 577 + sels = append(sels, p.Selectors()...) 578 + } 579 + } 580 + return cue.MakePath(sels...), nil 516 581 } 517 582 518 583 // applyShareIDAt applies the at= field from a @test(shareID=...) attribute ··· 528 593 if n, err := strconv.Atoi(val); err == nil { 529 594 return base.Append(cue.Index(n)) 530 595 } 531 - if p := cue.ParsePath(val); p.Err() == nil { 596 + if p, err := parseAtPath(val); err == nil { 532 597 return base.Append(p.Selectors()...) 533 598 } 534 599 break ··· 1244 1309 1245 1310 // Navigate val to the at= sub-path if specified. 1246 1311 if atStr != "" { 1247 - atPath := cue.ParsePath(atStr) 1248 - if err := atPath.Err(); err != nil { 1312 + atPath, err := parseAtPath(atStr) 1313 + if err != nil { 1249 1314 t.Errorf("path %s: @test(eq, at=%s): invalid path: %v", path, atStr, err) 1250 1315 return 1251 1316 } ··· 1813 1878 if shareIDName == "" { 1814 1879 continue 1815 1880 } 1816 - fieldPath := applyShareIDAt(basePath.Append(cue.Label(f.Label)), pa) 1881 + fieldPath := applyShareIDAt(basePath.Append(labelSelector(f.Label, "")), pa) 1817 1882 if result == nil { 1818 1883 result = make(map[string][]cue.Path) 1819 1884 }
+2 -2
internal/cuetxtar/inline_err.go
··· 320 320 321 321 if ea.at != "" { 322 322 // @test(err, at=<path>, ...) — navigate to sub-path then check error. 323 - subPath := cue.ParsePath(ea.at) 324 - if err := subPath.Err(); err != nil { 323 + subPath, err := parseAtPath(ea.at) 324 + if err != nil { 325 325 t.Errorf("path %s: @test(err, at=%s): invalid path: %v", path, ea.at, err) 326 326 return 327 327 }