Skip to content

Commit 1d72384

Browse files
authored
Merge pull request #12 from uudashr/unexported-analyzer
Add unexported analyzer
2 parents 572f40c + f45db8d commit 1d72384

File tree

9 files changed

+450
-1
lines changed

9 files changed

+450
-1
lines changed

.golangci.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ linters:
1010
- copyloopvar
1111
- decorder
1212
- dogsled
13-
- dupl
1413
- dupword
1514
- durationcheck
1615
- err113

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ It consists of several analyzers:
88
1. `unused`: Identifies interfaces that are not used anywhere in the same package where the interface is defined.
99
2. `identical`: Identifies interfaces in the same package with identical methods or constraints.
1010
3. `opaque`: Identifies functions that return interfaces, but the actual returned value is always a single concrete implementation.
11+
4. `unexported`: Identifies interfaces that are not exported but are used in exported functions or methods.
1112

1213
## Usage
1314

@@ -21,6 +22,7 @@ To install individual linter, use the following command:
2122
go install github.com/uudashr/iface/unused/cmd/unusediface@latest
2223
go install github.com/uudashr/iface/identical/cmd/identicaliface@latest
2324
go install github.com/uudashr/iface/opaque/cmd/opaqueiface@latest
25+
go install github.com/uudashr/iface/unexported/cmd/unexportediface@latest
2426
```
2527

2628
Run the linter

cmd/ifacecheck/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"github.com/uudashr/iface/identical"
55
"github.com/uudashr/iface/opaque"
6+
"github.com/uudashr/iface/unexported"
67
"github.com/uudashr/iface/unused"
78
"golang.org/x/tools/go/analysis/multichecker"
89
)
@@ -12,5 +13,6 @@ func main() {
1213
unused.Analyzer,
1314
identical.Analyzer,
1415
opaque.Analyzer,
16+
unexported.Analyzer,
1517
)
1618
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import (
4+
"github.com/uudashr/iface/unexported"
5+
"golang.org/x/tools/go/analysis/singlechecker"
6+
)
7+
8+
func main() {
9+
singlechecker.Main(unexported.Analyzer)
10+
}

unexported/doc.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Package unexported defines an Analyzer that identifies interfaces that are
2+
// not exported but are used in exported functions or methods.
3+
package unexported

unexported/testdata/src/a/a.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package a
2+
3+
import (
4+
"io"
5+
)
6+
7+
// unexportedReader is an unexported interface.
8+
type unexportedReader interface {
9+
Read([]byte) (int, error)
10+
}
11+
12+
// ExportedWriter is an exported interface.
13+
type ExportedWriter interface {
14+
Write([]byte) (int, error)
15+
}
16+
17+
// 1. Function with unexported arg type interface
18+
func ReadAll(r unexportedReader) ([]byte, error) { // want "unexported interface 'unexportedReader' used as parameter in exported function 'ReadAll'"
19+
buf := make([]byte, 1024)
20+
_, err := r.Read(buf)
21+
return buf, err
22+
}
23+
24+
// 2. Function with exported arg type interface
25+
func WriteHello(w ExportedWriter) error {
26+
_, err := w.Write([]byte("hello"))
27+
return err
28+
}
29+
30+
// 3. Function with unexported return type interface
31+
func NewUnexportedReader() unexportedReader { // want "unexported interface 'unexportedReader' used as return value in exported function 'NewUnexportedReader'"
32+
return nil // stub
33+
}
34+
35+
// 4. Function with exported return type interface
36+
func NewWriter() ExportedWriter {
37+
return nil // stub
38+
}
39+
40+
// 5. Function with both unexported arg and return type interface
41+
func WrapReader(r unexportedReader) unexportedReader { // want "unexported interface 'unexportedReader' used as parameter in exported function 'WrapReader'" "unexported interface 'unexportedReader' used as return value in exported function 'WrapReader'"
42+
return r
43+
}
44+
45+
// 6. Function with both exported arg and return type interface
46+
func WrapWriter(w ExportedWriter) ExportedWriter {
47+
return w
48+
}
49+
50+
// 7. Function with unexported arg type interface and exported return type interface
51+
func PromoteReader(r unexportedReader) ExportedWriter { // want "unexported interface 'unexportedReader' used as parameter in exported function 'PromoteReader'"
52+
return nil // stub
53+
}
54+
55+
// 8. Function with exported arg type interface and unexported return type interface
56+
func DemoteWriter(w ExportedWriter) unexportedReader { // want "unexported interface 'unexportedReader' used as return value in exported function 'DemoteWriter'"
57+
return nil // stub
58+
}
59+
60+
// 9. Function with external arg type interface (io.Writer)
61+
func WriteToExternal(w io.Writer) error {
62+
_, err := w.Write([]byte("external"))
63+
return err
64+
}
65+
66+
// 10. Function with external return type interface (io.Writer)
67+
func NewExternalWriter() io.Writer {
68+
return nil // stub
69+
}
70+
71+
// 11. Function with both external arg and return type interface (io.Writer)
72+
func WrapExternalWriter(w io.Writer) io.Writer {
73+
return w
74+
}
75+
76+
// 12. Function with any arg type
77+
func Print(a any) {
78+
}
79+
80+
// 13. Function witn interface{} arg type
81+
func Write(i interface{}) {
82+
}
83+
84+
// 14. Function with error arg type
85+
func Capture(err error) {}
86+
87+
// 15. Function with no arg and no return type interface
88+
func Ping() {}
89+
90+
// 16. Function with primitive arg type
91+
func AddOne(x int) int {
92+
return x + 1
93+
}
94+
95+
// 17. Function with primitive return type
96+
func GetZero() int {
97+
return 0
98+
}
99+
100+
// 18. Function with both primitive arg and return type
101+
func Double(x int) int {
102+
return x * 2
103+
}

unexported/testdata/src/b/b.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package b
2+
3+
import "io"
4+
5+
// unexportedReader is an unexported interface.
6+
type unexportedReader interface {
7+
Read([]byte) (int, error)
8+
}
9+
10+
// ExportedWriter is an exported interface.
11+
type ExportedWriter interface {
12+
Write([]byte) (int, error)
13+
}
14+
15+
// ExportedType is an exported struct type.
16+
type ExportedType struct{}
17+
18+
// 1. Method with unexported arg type interface
19+
func (e *ExportedType) ReadAll(r unexportedReader) ([]byte, error) { // want "unexported interface 'unexportedReader' used as parameter in exported method 'ExportedType.ReadAll'"
20+
buf := make([]byte, 1024)
21+
_, err := r.Read(buf)
22+
return buf, err
23+
}
24+
25+
// 2. Method with exported arg type interface
26+
func (e *ExportedType) WriteHello(w ExportedWriter) error {
27+
_, err := w.Write([]byte("hello"))
28+
return err
29+
}
30+
31+
// 3. Method with unexported return type interface
32+
func (e *ExportedType) NewUnexportedReader() unexportedReader { // want "unexported interface 'unexportedReader' used as return value in exported method 'ExportedType.NewUnexportedReader'"
33+
return nil // stub
34+
}
35+
36+
// 4. Method with exported return type interface
37+
func (e *ExportedType) NewWriter() ExportedWriter {
38+
return nil // stub
39+
}
40+
41+
// 5. Method with both unexported arg and return type interface
42+
func (e *ExportedType) WrapReader(r unexportedReader) unexportedReader { // want "unexported interface 'unexportedReader' used as parameter in exported method 'ExportedType.WrapReader'" "unexported interface 'unexportedReader' used as return value in exported method 'ExportedType.WrapReader'"
43+
return r
44+
}
45+
46+
// 6. Method with both exported arg and return type interface
47+
func (e *ExportedType) WrapWriter(w ExportedWriter) ExportedWriter {
48+
return w
49+
}
50+
51+
// 7. Method with unexported arg type interface and exported return type interface
52+
func (e *ExportedType) PromoteReader(r unexportedReader) ExportedWriter { // want "unexported interface 'unexportedReader' used as parameter in exported method 'ExportedType.PromoteReader'"
53+
return nil // stub
54+
}
55+
56+
// 8. Method with exported arg type interface and unexported return type interface
57+
func (e *ExportedType) DemoteWriter(w ExportedWriter) unexportedReader { // want "unexported interface 'unexportedReader' used as return value in exported method 'ExportedType.DemoteWriter'"
58+
return nil // stub
59+
}
60+
61+
// 9. Method with external arg type interface (io.Writer)
62+
func (e *ExportedType) WriteToExternal(w io.Writer) error {
63+
_, err := w.Write([]byte("external"))
64+
return err
65+
}
66+
67+
// 10. Method with external return type interface (io.Writer)
68+
func (e *ExportedType) NewExternalWriter() io.Writer {
69+
return nil // stub
70+
}
71+
72+
// 11. Method with both external arg and return type interface (io.Writer)
73+
func (e *ExportedType) WrapExternalWriter(w io.Writer) io.Writer {
74+
return w
75+
}
76+
77+
// 13. Method with any arg type
78+
func (e *ExportedType) Print(a any) {
79+
}
80+
81+
// 14. Method with interface{} arg type
82+
func (e *ExportedType) Write(i interface{}) {
83+
}
84+
85+
// 15. Method with error arg type
86+
func (e *ExportedType) Capture(err error) {}
87+
88+
// 16. Method with no arg and no return type interface
89+
func (e *ExportedType) Ping() {}
90+
91+
// 17. Method with primitive arg type
92+
func (e *ExportedType) AddOne(x int) int {
93+
return x + 1
94+
}
95+
96+
// 18. Method with primitive return type
97+
func (e *ExportedType) GetZero() int {
98+
return 0
99+
}
100+
101+
// 19. Method with both primitive arg and return type
102+
func (e *ExportedType) Double(x int) int {
103+
return x * 2
104+
}

0 commit comments

Comments
 (0)