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  }