Skip to content

Commit 610657f

Browse files
authored
fix(injector): preserve negated may matches (#857)
## Summary - make `MatchType.Not` conservative for existential may-match results - prevent negated receiver constraints from filtering an aspect before AST matching - add an injector regression fixture for `crypto/sha1.Sum` versus `(*digest).Sum` ## Root cause `may.Match` means that at least one node may match. Negating that result as `NeverMatch` was unsound: a package can contain both a matching receiver method and another function that satisfies the complete join point. The early package filter therefore discarded the aspect before node-level matching could distinguish them. ## Testing - `go test -count=1 -run 'Test/function-body-negated-receiver$' -v ./internal/injector`\n- `GOPROXY=https://proxy.golang.org,direct go test -race -shuffle=on -count=1 ./internal/injector/...`\n- `golangci-lint run ./internal/injector/aspect/may/... ./internal/injector/aspect/join/... ./internal/injector/parse/...`\n- `GOPROXY=https://proxy.golang.org,direct go build ./...`
1 parent a2efd5a commit 610657f

3 files changed

Lines changed: 53 additions & 3 deletions

File tree

internal/injector/aspect/may/match.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,19 @@ const (
2121
NeverMatch MatchType = 'N'
2222
)
2323

24-
// Not returns the logical NOT of a MatchType value
24+
// Not returns the conservative logical NOT of a MatchType value.
25+
// A Match only proves that some node may match, so its negation remains unknown.
2526
// Truth table:
2627
//
2728
// | A | NOT A |
2829
// |---|-------|
2930
// | N | Y |
3031
// | ? | ? |
31-
// | Y | N |
32+
// | Y | ? |
3233
func (m MatchType) Not() MatchType {
3334
switch m {
3435
case Match:
35-
return NeverMatch
36+
return Unknown
3637
case NeverMatch:
3738
return Match
3839
case Unknown:
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
%YAML 1.1
2+
---
3+
aspects:
4+
- id: crypto/sha1.Sum
5+
join-point:
6+
all-of:
7+
- import-path: crypto/sha1
8+
- function-body:
9+
all-of:
10+
- function:
11+
- name: Sum
12+
- not:
13+
function:
14+
- receiver: "*crypto/sha1.digest"
15+
advice:
16+
- prepend-statements:
17+
template: print("should trigger")
18+
19+
import-path: crypto/sha1
20+
21+
code: |-
22+
package sha1
23+
24+
type digest struct{}
25+
26+
func Sum(data []byte) [20]byte {
27+
return [20]byte{}
28+
}
29+
30+
func (d *digest) Sum(data []byte) []byte {
31+
return data
32+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//line input.go:1:1
2+
package sha1
3+
4+
type digest struct{}
5+
6+
func Sum(data []byte) [20]byte {
7+
//line <generated>:1
8+
{
9+
print("should trigger")
10+
}
11+
//line input.go:6
12+
return [20]byte{}
13+
}
14+
15+
func (d *digest) Sum(data []byte) []byte {
16+
return data
17+
}

0 commit comments

Comments
 (0)