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