package名と変数名がかぶっているのをとにかく検出したい / I need detect to conflicts of identifier for Go
by
mackee
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Slide 1
Slide 1 text
package໊ͱม໊͕ ͔Ϳ͍ͬͯΔͷΛ ͱʹ͔͘ݕग़͍ͨ͠ golang.tokyo #25 2019-06-18 @mackee_w a.k.a macopy 1
Slide 2
Slide 2 text
Ͳ͏͍͏͜ͱ͔ package main import ( "os" "errors" ) func main() { // Ҿ͔Β࣮ߦ͢Δ܅ΛऔΓग़͢ runner := NewRunners(os.Args[1:]) 2
Slide 3
Slide 3 text
errors := make([]error, 0, len(runner)) for _, r := range runners { result, err := runner.Run() if err != nil { errors = append(errors, err) } if result == nil { errors = append( errors, errors.New("result is nil"), ) } 3
Slide 4
Slide 4 text
1ߦา͍ͨΒΕͯΔ errors = append( errors, errors.New("result is nil"), ) • વ͜ΕίϯύΠϧ͕௨Βͳ͍ • errorsύοέʔδطʹ͑ͳ͘ͳ͍ͬͯΔͨΊ 4
Slide 5
Slide 5 text
͜ͷίʔυ͕ੜ·ΕΔࢥߟͷաఔ • errors ͍͍ͨͳΝ(github.com/pkg/errorsͰՄ) • ͦΕ͓͖ͯ͞errorΛ·ͱΊ͓͖͍͔ͯͨΒerrorsͱ͍͏ มΛએݴ͢Δͧ • ΞϨϨɺerrors.Newͱ͔errors.Wrapͱ͔ͷิ͕ޮ͔ͳ ͍ͧ • ͔ͿͬͯΔʂʂʂ 5
Slide 6
Slide 6 text
Έͳ͞ΜͦΜͳܦݧ͋Γ·ͤΜ͔ʁ • ʮ໋໊͕ྑ͘ͳ͍͔ΒͰʁʯ • ͜͜·Ͱ͔͋Β͞·ͳ͜ͱͳͯ͘ɺύοέʔδ໊ͱม໊ ͕͔Ϳͬͯࠞཚ͢Δ͜ͱ͕͋Γ·͢ • ͪͳΈʹࢲ্هͷΑ͏ͳerrorsΛimport͍ͯ͠Δͷʹ errorsΛ࡞Γग़͢͜ͱ͕͋Γ·͢(ຊʹ) • ݪҼ͕ίϯύΠϧΤϥʔͱҧ͏Օॴʹ͋ΔͨΊΘ͔Γʹ͍͘ 6
Slide 7
Slide 7 text
ͦͷଞղܾ͍ͨ͠έʔεstruct໊ͱม໊͕͔ͿΔ type sheet struct { // ... } func NewSheet() *sheet { return &sheet{} } func (s *sheet) String() string { // ... } 7
Slide 8
Slide 8 text
ͦͷଞղܾ͍ͨ͠έʔεstruct໊ͱม໊͕͔ͿΔ ಉ͡ύοέʔδͷҧ͏ϑΝΠϧͰ func DoSomething() { sheet := NewSheet() // ... } 8
Slide 9
Slide 9 text
͜͏ॻ͔ΕΔͱԿ͕ى͜Δ͔ • ίϯύΠϧ௨Δ • DoSomethingͷͰsheetΛࣗͰnewग़དྷͳ͍ 9
Slide 10
Slide 10 text
ύοέʔδͷ໊લͱԾҾ͕͔ͿΔ import "path" func ReadFromFile(path string) error { //... } 10
Slide 11
Slide 11 text
͜͏ॻ͔ΕΔͱԿ͕ى͜Δ͔ • ίϯύΠϧ௨Δ • ReadFromFileͷதͰpathύοέʔδͷ͕ؔݺͳ͘ͳΔ 11
Slide 12
Slide 12 text
ศརͳέʔε͋Δ Ұ෦ͷείʔϓ͚ͩlogΛผͷͷʹஔ͖͑Δͱ͔(ͦͦ͜͜अѱ import "log" // ͜ͷϝιουͷத͚ͩϑΝΠϧʹॻ͘ func Do() { log := log.New(logfile, "Do(): ", log.LstdFlags) // ্ͷ1ߦΛՃ͑Δ͚ͩͰଞͷߦॻ͖͑ͳ͍͍ͯ͘ log.Println("print something") } 12
Slide 13
Slide 13 text
ݴޠ༷͕ѱ͍ͱݴ͍͍ͨΘ͚Ͱͳ͘... ਓؒϛεΛ͢ΔͷͰ... 13
Slide 14
Slide 14 text
ҙਤ͔ͤͣͿͬͯΔ έʔεΛݕ͍ͨ͠ 14
Slide 15
Slide 15 text
github.com/mackee/conflic1dent 15
Slide 16
Slide 16 text
ྫ pathύοέʔδͱmainؔείʔϓͷpathม͕͔ͿͬͯΔ import "path" func main() { path := "example.txt" } 16
Slide 17
Slide 17 text
࣮ߦྫ ίϚϯυ࣮ߦ͢Δͱ $ conflictident . ग़ྗ͜Μͳײ͡ pkgident.go:12:2: conflict identifier name of 'path' by pkgident.go:4:2. 17
Slide 18
Slide 18 text
ରԠ͍ͯ͠Δ͔Ϳ͍ͬͯΔྫ • ύοέʔδ໊ͱม໊ • ύοέʔδ໊ͱԾҾ໊ • ಉ͡ύοέʔδͷܕͱม໊/ԾҾ໊ • ಉ͡ύοέʔδͷconstͷ໊લͱม໊/ԾҾ໊ 18
Slide 19
Slide 19 text
ͱʹ͔͘ศར... 19
Slide 20
Slide 20 text
ྨࣅ • golang.org/x/tools/go/analysis/passes/shadow/ cmd/shadow • มͷshadowingΛݕͯ͘͠ΕΔ func BadRead(f *os.File, buf []byte) error { var err error for { n, err := f.Read(buf) // shadows the function variable 'err' if err != nil { break // causes return of wrong value } foo(buf) } return err } 20
Slide 21
Slide 21 text
ຊݴ͍͍ͨͷ golang.org/x/tools/analysis ͕ศར... 21
Slide 22
Slide 22 text
3ߦͰΘ͔Δx/tools/analysis • ੩తղੳνΣοΧʔΛ࡞ΔϑϨʔϜϫʔΫతͳϥΠϒϥϦ • ੩తղੳʹඞཁͳ ಡΉ, ղੳ͢Δ, ग़ྗ͢Δ ͷ͏ͪ ಡΉ, ग़ྗ͢ Δ ΛΑ͠ͳʹͬͯ͘ΕΔ • ੩తղੳνΣοΧʔͷςετέʔεهड़͕ઈָ 22
Slide 23
Slide 23 text
x/tools/analysisΛ͍ͬͯΔίʔυ package conflictident import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" ) var Analyzer = &analysis.Analyzer{ Name: "conflictident", Doc: Doc, Run: run, Requires: []*analysis.Analyzer{ inspect.Analyzer, }, } 23
Slide 24
Slide 24 text
x/tools/analysisΛ͍ͬͯΔίʔυ func run(pass *analysis.Pass) (interface{}, error) { ins := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ // ͜͜ʹཉ͍͠ASTͷϊʔυೖΕΑ͏ } ins.WithStack(nodeFilter, func(n ast.Node, push bool, stack []ast.Node) bool { // ϑΟϧλʹઃఆͨ͠ASTͷϊʔυ͕ͬͯ͘Δͧ ͦΕΛݟ͍͍ͯײ͡ʹग़ྗ͠Α͏ }) } 24
Slide 25
Slide 25 text
x/tools/analysisΛ͍ͬͯΔίʔυ pass.Reportf( ident.Pos(), // ؒҧ͍ͬͯΔίʔυͷϙδγϣϯ "conflict identifier name of '%s' by %s.", name, pos, ) 25
Slide 26
Slide 26 text
x/tools/analysisΛ͍ͬͯΔίʔυ package main import ( "github.com/mackee/conflictident" "golang.org/x/tools/go/analysis/singlechecker" ) func main() { singlechecker.Main(conflictident.Analyzer) } 26
Slide 27
Slide 27 text
conflic&dent͕͍ͬͯΔ͜ͱ • ύοέʔδείʔϓͷܕఆٛΛௐΔ • ϑΝΠϧείʔϓͷimportએݴΛௐΔ • ͦΕͧΕͷؔείʔϓͰએݴ͞ΕͯΔม໊ԾҾ໊͕ ্ه2ͭͱ͔ͿͬͯͨΒग़ྗΛग़͢ 27
Slide 28
Slide 28 text
͜ΕͰ͍͍ײ͡ʹίϚϯυΛ࡞ΕΔʂʂ 28
Slide 29
Slide 29 text
ςετ͕ΊͬͪΌָͳͷΛओு͍ͨ͠ 29
Slide 30
Slide 30 text
͜͏͍͏ίϚϯυͷςετͷ͠͞ • ϑΝΠϧΛ৯ͬͯඪ४ग़ྗʹ݁ՌΛग़͢λΠϓͷίϚϯυ • ࣮ʹΔͱςετ༻ͷϑΝΠϧΛ࡞ͬͯඪ४ग़ྗΛಡΜͰ จࣈྻύʔεͯ͠... • ͪΌΜͱೖྗͱग़ྗΛ͚ͯɺςετͰೖग़ྗΛϞοΫ͢Δ • ↑ x/tools/analysisͰॻ͘ͱࣗવʹ͜Ε͕ग़དྷΔʂʂʂ 30
Slide 31
Slide 31 text
testdataͷ࡞ • testdata/src ҎԼʹ੩తղੳνΣοΧʔͷςετσʔλͷ ίʔυΛॻ͘ • ςετσʔλͷதʹίϝϯτͰظ͢Δग़ྗΛॻ͘ • ςετଆ x/tools/go/analysis/analysistest Λͬ ͯهड़͢Δ 31
Slide 32
Slide 32 text
testdata/src/pkgident/pkgident.go package pkgident import ( "path" ) func hoge() { _ = path.ErrBadPattern } func main() { path, fuga := 1, 1 // want "conflict identifier name of 'path' by testdata/src/pkgident/pkgident.go:4:2." _, _ = path, fuga } func p(path string) { // want "conflict identifier name of 'path' by testdata/src/pkgident/pkgident.go:4:2." } 32
Slide 33
Slide 33 text
conflic&dent_test.go package conflictident_test import ( "testing" "github.com/mackee/conflictident" "golang.org/x/tools/go/analysis/analysistest" ) func Test(t *testing.T) { testdata := analysistest.TestData() analysistest.Run(t, testdata, conflictident.Analyzer, "varspec", "funcarg") } 33
Slide 34
Slide 34 text
ͦͷଞ͓ಘϙΠϯτ • go vetͳͲͰݴ͏ ./... Έ͍ͨͳͷͦͷ··͑Δ • ϞδϡʔϧԽ͍ͯ͠ΔͷͰଞͷLinterͱҰॹʹ࣮ߦ͢ΔίϚϯυ Λ࡞ΕΔ • go modulesରԠࡁΈ 34
Slide 35
Slide 35 text
·ͱΊ • ࢲ͕ϛεΛ͠·͘ΔͷͰɺਖ਼͍͠ίʔυ͕ॻ͚ΔΑ͏ʹ੩తղ ੳνΣοΧʔΛ࡞Γ·ͨ͠ • golang.org/x/tools/analysis Λ͏ͱLinter͕͔ͳΓ؆ ୯ʹॻ͚Δͧʂ • ղੳʹ͕͔͔࣌ؒΔͷͰνϡʔχϯά͍ͨ͠ • ੩తղੳೖʹ࠷దͳͷͰΈΜͳͬͨΒ͍͍ 35
Slide 36
Slide 36 text
Ͱɺ୭ʁ • mackee_w a.k.a @macopy • ໘ന๏ਓΧϠοΫ, 3DϓϦϯλ, ࣗ࡞ ΩʔϘʔυ • ←ࠓि༵ʹחͰΔͷͰདྷͯ͘ Εʂʂʂ 36