1// Copyright 2021 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Issue 42580: cmd/cgo: shifting identifier position in ast 6 7package errorstest 8 9import ( 10 "bytes" 11 "fmt" 12 "go/ast" 13 "go/parser" 14 "go/token" 15 "internal/testenv" 16 "os" 17 "os/exec" 18 "path/filepath" 19 "strings" 20 "testing" 21) 22 23type ShortPosition struct { 24 Line int 25 Column int 26 Visited bool 27} 28 29type IdentPositionInfo map[string][]ShortPosition 30 31type Visitor struct { 32 identPosInfo IdentPositionInfo 33 fset *token.FileSet 34 t *testing.T 35} 36 37func (v *Visitor) Visit(node ast.Node) ast.Visitor { 38 if ident, ok := node.(*ast.Ident); ok { 39 if expectedPositions, ok := v.identPosInfo[ident.Name]; ok { 40 gotMatch := false 41 var errorMessage strings.Builder 42 for caseIndex, expectedPos := range expectedPositions { 43 actualPosition := v.fset.PositionFor(ident.Pos(), true) 44 errorOccured := false 45 if expectedPos.Line != actualPosition.Line { 46 fmt.Fprintf(&errorMessage, "wrong line number for ident %s: expected: %d got: %d\n", ident.Name, expectedPos.Line, actualPosition.Line) 47 errorOccured = true 48 } 49 if expectedPos.Column != actualPosition.Column { 50 fmt.Fprintf(&errorMessage, "wrong column number for ident %s: expected: %d got: %d\n", ident.Name, expectedPos.Column, actualPosition.Column) 51 errorOccured = true 52 } 53 if errorOccured { 54 continue 55 } 56 gotMatch = true 57 expectedPositions[caseIndex].Visited = true 58 } 59 60 if !gotMatch { 61 v.t.Errorf(errorMessage.String()) 62 } 63 } 64 } 65 return v 66} 67 68func TestArgumentsPositions(t *testing.T) { 69 testenv.MustHaveCGO(t) 70 testenv.MustHaveExec(t) 71 72 testdata, err := filepath.Abs("testdata") 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 tmpPath := t.TempDir() 78 79 dir := filepath.Join(tmpPath, "src", "testpositions") 80 if err := os.MkdirAll(dir, 0755); err != nil { 81 t.Fatal(err) 82 } 83 84 cmd := exec.Command("go", "tool", "cgo", 85 "-srcdir", testdata, 86 "-objdir", dir, 87 "issue42580.go") 88 cmd.Stderr = new(bytes.Buffer) 89 90 err = cmd.Run() 91 if err != nil { 92 t.Fatalf("%s: %v\n%s", cmd, err, cmd.Stderr) 93 } 94 mainProcessed, err := os.ReadFile(filepath.Join(dir, "issue42580.cgo1.go")) 95 if err != nil { 96 t.Fatal(err) 97 } 98 fset := token.NewFileSet() 99 f, err := parser.ParseFile(fset, "", mainProcessed, parser.AllErrors) 100 if err != nil { 101 fmt.Println(err) 102 return 103 } 104 105 expectation := IdentPositionInfo{ 106 "checkedPointer": []ShortPosition{ 107 ShortPosition{ 108 Line: 32, 109 Column: 56, 110 }, 111 }, 112 "singleInnerPointerChecked": []ShortPosition{ 113 ShortPosition{ 114 Line: 37, 115 Column: 91, 116 }, 117 }, 118 "doublePointerChecked": []ShortPosition{ 119 ShortPosition{ 120 Line: 42, 121 Column: 91, 122 }, 123 }, 124 } 125 for _, decl := range f.Decls { 126 if fdecl, ok := decl.(*ast.FuncDecl); ok { 127 ast.Walk(&Visitor{expectation, fset, t}, fdecl.Body) 128 } 129 } 130 for ident, positions := range expectation { 131 for _, position := range positions { 132 if !position.Visited { 133 t.Errorf("Position %d:%d missed for %s ident", position.Line, position.Column, ident) 134 } 135 } 136 } 137} 138