github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/loader/source_test.go (about) 1 // Copyright 2013 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 package loader_test 6 7 // This file defines tests of source utilities. 8 9 import ( 10 "go/ast" 11 "go/parser" 12 "go/token" 13 "strings" 14 "testing" 15 16 "llvm.org/llgo/third_party/gotools/go/ast/astutil" 17 "llvm.org/llgo/third_party/gotools/go/loader" 18 "llvm.org/llgo/third_party/gotools/go/ssa" 19 ) 20 21 // findInterval parses input and returns the [start, end) positions of 22 // the first occurrence of substr in input. f==nil indicates failure; 23 // an error has already been reported in that case. 24 // 25 func findInterval(t *testing.T, fset *token.FileSet, input, substr string) (f *ast.File, start, end token.Pos) { 26 f, err := parser.ParseFile(fset, "<input>", input, 0) 27 if err != nil { 28 t.Errorf("parse error: %s", err) 29 return 30 } 31 32 i := strings.Index(input, substr) 33 if i < 0 { 34 t.Errorf("%q is not a substring of input", substr) 35 f = nil 36 return 37 } 38 39 filePos := fset.File(f.Package) 40 return f, filePos.Pos(i), filePos.Pos(i + len(substr)) 41 } 42 43 func TestEnclosingFunction(t *testing.T) { 44 tests := []struct { 45 input string // the input file 46 substr string // first occurrence of this string denotes interval 47 fn string // name of expected containing function 48 }{ 49 // We use distinctive numbers as syntactic landmarks. 50 51 // Ordinary function: 52 {`package main 53 func f() { println(1003) }`, 54 "100", "main.f"}, 55 // Methods: 56 {`package main 57 type T int 58 func (t T) f() { println(200) }`, 59 "200", "(main.T).f"}, 60 // Function literal: 61 {`package main 62 func f() { println(func() { print(300) }) }`, 63 "300", "main.f$1"}, 64 // Doubly nested 65 {`package main 66 func f() { println(func() { print(func() { print(350) })})}`, 67 "350", "main.f$1$1"}, 68 // Implicit init for package-level var initializer. 69 {"package main; var a = 400", "400", "main.init"}, 70 // No code for constants: 71 {"package main; const a = 500", "500", "(none)"}, 72 // Explicit init() 73 {"package main; func init() { println(600) }", "600", "main.init#1"}, 74 // Multiple explicit init functions: 75 {`package main 76 func init() { println("foo") } 77 func init() { println(800) }`, 78 "800", "main.init#2"}, 79 // init() containing FuncLit. 80 {`package main 81 func init() { println(func(){print(900)}) }`, 82 "900", "main.init#1$1"}, 83 } 84 for _, test := range tests { 85 conf := loader.Config{Fset: token.NewFileSet()} 86 f, start, end := findInterval(t, conf.Fset, test.input, test.substr) 87 if f == nil { 88 continue 89 } 90 path, exact := astutil.PathEnclosingInterval(f, start, end) 91 if !exact { 92 t.Errorf("EnclosingFunction(%q) not exact", test.substr) 93 continue 94 } 95 96 conf.CreateFromFiles("main", f) 97 98 iprog, err := conf.Load() 99 if err != nil { 100 t.Error(err) 101 continue 102 } 103 prog := ssa.Create(iprog, 0) 104 pkg := prog.Package(iprog.Created[0].Pkg) 105 pkg.Build() 106 107 name := "(none)" 108 fn := ssa.EnclosingFunction(pkg, path) 109 if fn != nil { 110 name = fn.String() 111 } 112 113 if name != test.fn { 114 t.Errorf("EnclosingFunction(%q in %q) got %s, want %s", 115 test.substr, test.input, name, test.fn) 116 continue 117 } 118 119 // While we're here: test HasEnclosingFunction. 120 if has := ssa.HasEnclosingFunction(pkg, path); has != (fn != nil) { 121 t.Errorf("HasEnclosingFunction(%q in %q) got %v, want %v", 122 test.substr, test.input, has, fn != nil) 123 continue 124 } 125 } 126 }