// Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Issue 42580: cmd/cgo: shifting identifier position in ast package errorstest import ( "bytes" "fmt" "go/ast" "go/parser" "go/token" "io/ioutil" "os" "os/exec" "path/filepath" "strings" "testing" ) type ShortPosition struct { Line int Column int Visited bool } type IdentPositionInfo map[string][]ShortPosition type Visitor struct { identPosInfo IdentPositionInfo fset *token.FileSet t *testing.T } func (v *Visitor) Visit(node ast.Node) ast.Visitor { if ident, ok := node.(*ast.Ident); ok { if expectedPositions, ok := v.identPosInfo[ident.Name]; ok { gotMatch := false var errorMessage strings.Builder for caseIndex, expectedPos := range expectedPositions { actualPosition := v.fset.PositionFor(ident.Pos(), true) errorOccured := false if expectedPos.Line != actualPosition.Line { fmt.Fprintf(&errorMessage, "wrong line number for ident %s: expected: %d got: %d\n", ident.Name, expectedPos.Line, actualPosition.Line) errorOccured = true } if expectedPos.Column != actualPosition.Column { fmt.Fprintf(&errorMessage, "wrong column number for ident %s: expected: %d got: %d\n", ident.Name, expectedPos.Column, actualPosition.Column) errorOccured = true } if errorOccured { continue } gotMatch = true expectedPositions[caseIndex].Visited = true } if !gotMatch { v.t.Errorf(errorMessage.String()) } } } return v } func TestArgumentsPositions(t *testing.T) { testdata, err := filepath.Abs("testdata") if err != nil { t.Fatal(err) } tmpPath := t.TempDir() dir := filepath.Join(tmpPath, "src", "testpositions") if err := os.MkdirAll(dir, 0755); err != nil { t.Fatal(err) } cmd := exec.Command("go", "tool", "cgo", "-srcdir", testdata, "-objdir", dir, "issue42580.go") cmd.Stderr = new(bytes.Buffer) err = cmd.Run() if err != nil { t.Fatalf("%s: %v\n%s", cmd, err, cmd.Stderr) } mainProcessed, err := ioutil.ReadFile(filepath.Join(dir, "issue42580.cgo1.go")) if err != nil { t.Fatal(err) } fset := token.NewFileSet() f, err := parser.ParseFile(fset, "", mainProcessed, parser.AllErrors) if err != nil { fmt.Println(err) return } expectation := IdentPositionInfo{ "checkedPointer": []ShortPosition{ ShortPosition{ Line: 32, Column: 56, }, }, "singleInnerPointerChecked": []ShortPosition{ ShortPosition{ Line: 37, Column: 91, }, }, "doublePointerChecked": []ShortPosition{ ShortPosition{ Line: 42, Column: 91, }, }, } for _, decl := range f.Decls { if fdecl, ok := decl.(*ast.FuncDecl); ok { ast.Walk(&Visitor{expectation, fset, t}, fdecl.Body) } } for ident, positions := range expectation { for _, position := range positions { if !position.Visited { t.Errorf("Position %d:%d missed for %s ident", position.Line, position.Column, ident) } } } }