Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: tomarrell/wrapcheck
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.8.3
Choose a base ref
...
head repository: tomarrell/wrapcheck
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v2.9.0
Choose a head ref
  • 1 commit
  • 2 files changed
  • 1 contributor

Commits on Jul 16, 2024

  1. feat: suppress reports from unexported interface methods (#52)

    When an interface method is not exported, its only implementations will
    be local to the module under analysis. Thus, the implementations can be
    checked, and the caller can assume the error was wrapped.
    
    This reasoning does not apply to exported interface methods, even if the
    interface happens to also have an unexported method. (An implementation
    can override just the public methods by embedding the interface or a
    struct that implements it.)
    MichaelUrman authored Jul 16, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    4a8f079 View commit details
Showing with 16 additions and 10 deletions.
  1. +13 −7 wrapcheck/testdata/interface_on_struct/main.go
  2. +3 −3 wrapcheck/wrapcheck.go
20 changes: 13 additions & 7 deletions wrapcheck/testdata/interface_on_struct/main.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
package main

import (
"encoding/json"
"strings"
)

type errorer interface {
Decode(v interface{}) error
decode(v interface{}) error
}

type foo struct {
bar errorer
}

func main() {
d := json.NewDecoder(strings.NewReader("hello world"))
do(foo{d})
do(foo{})
doInternal(foo{})
}

func do(f foo) error {
@@ -27,3 +23,13 @@ func do(f foo) error {

return nil
}

func doInternal(f foo) error {
var str string
err := f.bar.decode(&str)
if err != nil {
return err // unexported methods are validated at their implementation
}

return nil
}
6 changes: 3 additions & 3 deletions wrapcheck/wrapcheck.go
Original file line number Diff line number Diff line change
@@ -283,9 +283,9 @@ func reportUnwrapped(
}

// Check if the underlying type of the "x" in x.y.z is an interface, as
// errors returned from interface types should be wrapped, unless ignored
// as per `ignoreInterfaceRegexps`
if isInterface(pass, sel) {
// errors returned from exported interface types should be wrapped, unless
// ignored as per `ignoreInterfaceRegexps`
if sel.Sel.IsExported() && isInterface(pass, sel) {
pkgPath := pass.TypesInfo.ObjectOf(sel.Sel).Pkg().Path()
name := types.TypeString(pass.TypesInfo.TypeOf(sel.X), func(p *types.Package) string { return p.Name() })
if !containsMatch(regexpsInter, name) && !containsMatchGlob(pkgGlobs, pkgPath) {