package名と変数名がかぶっているのをとにかく検出したい / I need detect to conflicts of identifier for Go

B5582ce2d9959dfcff0384a07003e188?s=47 mackee
June 18, 2019

package名と変数名がかぶっているのをとにかく検出したい / I need detect to conflicts of identifier for Go

B5582ce2d9959dfcff0384a07003e188?s=128

mackee

June 18, 2019
Tweet

Transcript

  1. package໊ͱม਺໊͕ ͔Ϳ͍ͬͯΔͷΛ ͱʹ͔͘ݕग़͍ͨ͠ golang.tokyo #25 2019-06-18 @mackee_w a.k.a macopy 1

  2. Ͳ͏͍͏͜ͱ͔ package main import ( "os" "errors" ) func main()

    { // Ҿ਺͔Β࣮ߦ͢Δ܅ΛऔΓग़͢ runner := NewRunners(os.Args[1:]) 2
  3. 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
  4. 1ߦา͍ͨΒ๨ΕͯΔ errors = append( errors, errors.New("result is nil"), ) •

    ౰વ͜Ε͸ίϯύΠϧ͕௨Βͳ͍ • errorsύοέʔδ͸طʹ࢖͑ͳ͘ͳ͍ͬͯΔͨΊ 4
  5. ͜ͷίʔυ͕ੜ·ΕΔࢥߟͷաఔ • errors ࢖͍͍ͨͳΝ(github.com/pkg/errorsͰ΋Մ) • ͦΕ͸͓͖ͯ͞errorΛ·ͱΊ͓͖͍͔ͯͨΒerrorsͱ͍͏ ม਺Λએݴ͢Δͧ • ΞϨϨɺerrors.Newͱ͔errors.Wrapͱ͔ͷิ׬͕ޮ͔ͳ ͍ͧ

    • ͔ͿͬͯΔʂʂʂ 5
  6. Έͳ͞Μ͸ͦΜͳܦݧ͸͋Γ·ͤΜ͔ʁ • ʮ໋໊͕ྑ͘ͳ͍͔ΒͰ͸ʁʯ • ͜͜·Ͱ͔͋Β͞·ͳ͜ͱ͸ͳͯ͘΋ɺύοέʔδ໊ͱม਺໊ ͕͔Ϳͬͯࠞཚ͢Δ͜ͱ͕͋Γ·͢ • ͪͳΈʹࢲ͸্هͷΑ͏ͳerrorsΛimport͍ͯ͠Δͷʹ errorsΛ࡞Γग़͢͜ͱ͕͋Γ·͢(ຊ౰ʹ) •

    ݪҼ͕ίϯύΠϧΤϥʔͱ͸ҧ͏Օॴʹ͋ΔͨΊΘ͔Γʹ͍͘ 6
  7. ͦͷଞղܾ͍ͨ͠έʔεstruct໊ͱม਺໊͕͔ͿΔ type sheet struct { // ... } func NewSheet()

    *sheet { return &sheet{} } func (s *sheet) String() string { // ... } 7
  8. ͦͷଞղܾ͍ͨ͠έʔεstruct໊ͱม਺໊͕͔ͿΔ ಉ͡ύοέʔδͷҧ͏ϑΝΠϧͰ func DoSomething() { sheet := NewSheet() // ...

    } 8
  9. ͜͏ॻ͔ΕΔͱԿ͕ى͜Δ͔ • ίϯύΠϧ͸௨Δ • DoSomethingͷ಺ͰsheetΛࣗ෼Ͱnew͸ग़དྷͳ͍ 9

  10. ύοέʔδͷ໊લͱԾҾ਺͕͔ͿΔ import "path" func ReadFromFile(path string) error { //... }

    10
  11. ͜͏ॻ͔ΕΔͱԿ͕ى͜Δ͔ • ίϯύΠϧ͸௨Δ • ReadFromFileͷதͰpathύοέʔδͷؔ਺͕ݺ΂ͳ͘ͳΔ 11

  12. ศརͳέʔε΋͋Δ Ұ෦ͷείʔϓ͚ͩlogΛผͷ΋ͷʹஔ͖׵͑Δͱ͔(ͦͦ͜͜अѱ import "log" // ͜ͷϝιουͷத͚ͩϑΝΠϧʹॻ͘ func Do() { log

    := log.New(logfile, "Do(): ", log.LstdFlags) // ্ͷ1ߦΛՃ͑Δ͚ͩͰଞͷߦ͸ॻ͖׵͑ͳ͍͍ͯ͘ log.Println("print something") } 12
  13. ݴޠ࢓༷͕ѱ͍ͱݴ͍͍ͨΘ͚Ͱ͸ͳ͘... ਓؒ͸ϛεΛ͢ΔͷͰ... 13

  14. ҙਤ͔ͤͣͿͬͯΔ έʔεΛݕ஌͍ͨ͠ 14

  15. github.com/mackee/conflic1dent 15

  16. ྫ pathύοέʔδͱmainؔ਺είʔϓͷpathม਺͕͔ͿͬͯΔ import "path" func main() { path := "example.txt"

    } 16
  17. ࣮ߦྫ ίϚϯυ࣮ߦ͢Δͱ $ conflictident . ग़ྗ͸͜Μͳײ͡ pkgident.go:12:2: conflict identifier name

    of 'path' by pkgident.go:4:2. 17
  18. ରԠ͍ͯ͠Δ͔Ϳ͍ͬͯΔྫ • ύοέʔδ໊ͱม਺໊ • ύοέʔδ໊ͱԾҾ਺໊ • ಉ͡ύοέʔδ಺ͷܕͱม਺໊/ԾҾ਺໊ • ಉ͡ύοέʔδ಺ͷconstͷ໊લͱม਺໊/ԾҾ਺໊ 18

  19. ͱʹ͔͘ศར... 19

  20. ྨࣅ඼ • 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
  21. ຊ೔ݴ͍͍ͨͷ͸ golang.org/x/tools/analysis ͕ศར... 21

  22. 3ߦͰΘ͔Δx/tools/analysis • ੩తղੳνΣοΧʔΛ࡞ΔϑϨʔϜϫʔΫతͳϥΠϒϥϦ • ੩తղੳʹඞཁͳ ಡΉ, ղੳ͢Δ, ग़ྗ͢Δ ͷ͏ͪ ಡΉ,

    ग़ྗ͢ Δ ΛΑ͠ͳʹ΍ͬͯ͘ΕΔ • ੩తղੳνΣοΧʔͷςετέʔεهड़͕௒ઈָ 22
  23. 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
  24. 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
  25. x/tools/analysisΛ࢖͍ͬͯΔίʔυ pass.Reportf( ident.Pos(), // ؒҧ͍ͬͯΔίʔυͷϙδγϣϯ "conflict identifier name of '%s'

    by %s.", name, pos, ) 25
  26. x/tools/analysisΛ࢖͍ͬͯΔίʔυ package main import ( "github.com/mackee/conflictident" "golang.org/x/tools/go/analysis/singlechecker" ) func main()

    { singlechecker.Main(conflictident.Analyzer) } 26
  27. conflic&dent͕΍͍ͬͯΔ͜ͱ • ύοέʔδείʔϓͷܕఆٛΛௐ΂Δ • ϑΝΠϧείʔϓͷimportએݴΛௐ΂Δ • ͦΕͧΕͷؔ਺είʔϓ಺Ͱએݴ͞ΕͯΔม਺໊΍ԾҾ਺໊͕ ্ه2ͭͱ͔ͿͬͯͨΒग़ྗΛग़͢ 27

  28. ͜ΕͰ͍͍ײ͡ʹίϚϯυΛ࡞ΕΔʂʂ 28

  29. ςετ͕ΊͬͪΌָͳͷΛओு͍ͨ͠ 29

  30. ͜͏͍͏ίϚϯυͷςετͷ೉͠͞ • ϑΝΠϧΛ৯ͬͯඪ४ग़ྗʹ݁ՌΛग़͢λΠϓͷίϚϯυ • ࣮௚ʹ΍Δͱςετ༻ͷϑΝΠϧΛ࡞ͬͯඪ४ग़ྗΛಡΜͰ จࣈྻύʔεͯ͠... • ͪΌΜͱೖྗͱग़ྗΛ෼͚ͯɺςετͰ͸ೖग़ྗΛϞοΫ͢Δ • ↑

    x/tools/analysisͰॻ͘ͱࣗવʹ͜Ε͕ग़དྷΔʂʂʂ 30
  31. testdataͷ࡞੒ • testdata/src ҎԼʹ੩తղੳνΣοΧʔͷςετσʔλͷ ίʔυΛॻ͘ • ςετσʔλͷதʹίϝϯτͰظ଴͢Δग़ྗΛॻ͘ • ςετଆ͸ x/tools/go/analysis/analysistest

    Λ࢖ͬ ͯهड़͢Δ 31
  32. 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
  33. 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
  34. ͦͷଞ͓ಘϙΠϯτ • go vetͳͲͰݴ͏ ./... Έ͍ͨͳͷ΋ͦͷ··࢖͑Δ • ϞδϡʔϧԽ͍ͯ͠ΔͷͰଞͷLinterͱҰॹʹ࣮ߦ͢ΔίϚϯυ Λ࡞ΕΔ •

    go modulesରԠࡁΈ 34
  35. ·ͱΊ • ࢲ͕ϛεΛ͠·͘ΔͷͰɺਖ਼͍͠ίʔυ͕ॻ͚ΔΑ͏ʹ੩తղ ੳνΣοΧʔΛ࡞Γ·ͨ͠ • golang.org/x/tools/analysis Λ࢖͏ͱLinter͕͔ͳΓ؆ ୯ʹॻ͚Δͧʂ • ղੳʹ͕͔͔࣌ؒΔͷͰνϡʔχϯά͍ͨ͠

    • ੩తղੳೖ໳ʹ࠷దͳͷͰΈΜͳ΍ͬͨΒ͍͍ 35
  36. Ͱɺ୭ʁ • mackee_w a.k.a @macopy • ໘ന๏ਓΧϠοΫ, 3DϓϦϯλ, ࣗ࡞ ΩʔϘʔυ

    • ←ࠓि౔༵೔ʹח૔Ͱ΍ΔͷͰདྷͯ͘ Εʂʂʂ 36