Merge pull request #15714 from lavalamp/go2idl.2
Auto commit by PR queue bot
This commit is contained in:
		
							
								
								
									
										56
									
								
								cmd/libs/go2idl/generator/default_generator.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								cmd/libs/go2idl/generator/default_generator.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package generator | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
|  | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/namer" | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/types" | ||||
| ) | ||||
|  | ||||
| // DefaultGen implements a do-nothing Generator. | ||||
| // | ||||
| // It can be used to implement static content files. | ||||
| type DefaultGen struct { | ||||
| 	// OptionalName, if present, will be used for the generator's name, and | ||||
| 	// the filename (with ".go" appended). | ||||
| 	OptionalName string | ||||
|  | ||||
| 	// OptionalBody, if present, will be used as the return from the "Init" | ||||
| 	// method. This causes it to be static content for the entire file if | ||||
| 	// no other generator touches the file. | ||||
| 	OptionalBody []byte | ||||
| } | ||||
|  | ||||
| func (d DefaultGen) Name() string                                        { return d.OptionalName } | ||||
| func (d DefaultGen) Filter(*Context, *types.Type) bool                   { return true } | ||||
| func (d DefaultGen) Namers(*Context) namer.NameSystems                   { return nil } | ||||
| func (d DefaultGen) Imports(*Context) []string                           { return []string{} } | ||||
| func (d DefaultGen) PackageVars(*Context) []string                       { return []string{} } | ||||
| func (d DefaultGen) PackageConsts(*Context) []string                     { return []string{} } | ||||
| func (d DefaultGen) GenerateType(*Context, *types.Type, io.Writer) error { return nil } | ||||
| func (d DefaultGen) Filename() string                                    { return d.OptionalName + ".go" } | ||||
|  | ||||
| func (d DefaultGen) Init(c *Context, w io.Writer) error { | ||||
| 	_, err := w.Write(d.OptionalBody) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	_ = Generator(DefaultGen{}) | ||||
| ) | ||||
							
								
								
									
										72
									
								
								cmd/libs/go2idl/generator/default_package.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								cmd/libs/go2idl/generator/default_package.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package generator | ||||
|  | ||||
| import ( | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/types" | ||||
| ) | ||||
|  | ||||
| // DefaultPackage contains a default implentation of Package. | ||||
| type DefaultPackage struct { | ||||
| 	// Short name of package, used in the "package xxxx" line. | ||||
| 	PackageName string | ||||
| 	// Import path of the package, and the location on disk of the package. | ||||
| 	PackagePath string | ||||
|  | ||||
| 	// Emitted at the top of every file. | ||||
| 	HeaderText []byte | ||||
|  | ||||
| 	// Emitted only for a "doc.go" file; appended to the HeaderText for | ||||
| 	// that file. | ||||
| 	PackageDocumentation []byte | ||||
|  | ||||
| 	// If non-nil, will be called on "Generators"; otherwise, the static | ||||
| 	// list will be used. So you should set only one of these two fields. | ||||
| 	GeneratorFunc func(*Context) []Generator | ||||
| 	GeneratorList []Generator | ||||
|  | ||||
| 	// Optional; filters the types exposed to the generators. | ||||
| 	FilterFunc func(*Context, *types.Type) bool | ||||
| } | ||||
|  | ||||
| func (d *DefaultPackage) Name() string { return d.PackageName } | ||||
| func (d *DefaultPackage) Path() string { return d.PackagePath } | ||||
|  | ||||
| func (d *DefaultPackage) Filter(c *Context, t *types.Type) bool { | ||||
| 	if d.FilterFunc != nil { | ||||
| 		return d.FilterFunc(c, t) | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func (d *DefaultPackage) Generators(c *Context) []Generator { | ||||
| 	if d.GeneratorFunc != nil { | ||||
| 		return d.GeneratorFunc(c) | ||||
| 	} | ||||
| 	return d.GeneratorList | ||||
| } | ||||
|  | ||||
| func (d *DefaultPackage) Header(filename string) []byte { | ||||
| 	if filename == "doc.go" { | ||||
| 		return append(d.HeaderText, d.PackageDocumentation...) | ||||
| 	} | ||||
| 	return d.HeaderText | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	_ = Package(&DefaultPackage{}) | ||||
| ) | ||||
							
								
								
									
										31
									
								
								cmd/libs/go2idl/generator/doc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								cmd/libs/go2idl/generator/doc.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| // Package generator defines an interface for code generators to implement. | ||||
| // | ||||
| // To use this package, you'll implement the "Package" and "Generator" | ||||
| // interfaces; you'll call NewContext to load up the types you want to work | ||||
| // with, and then you'll call one or more of the Execute methods. See the | ||||
| // interface definitions for explanations. All output will have gofmt called on | ||||
| // it automatically, so you do not need to worry about generating correct | ||||
| // indentation. | ||||
| // | ||||
| // This package also exposes SnippetWriter. SnippetWriter reduces to a minimum | ||||
| // the boilerplate involved in setting up a template from go's text/template | ||||
| // package. Additionally, all naming systems in the Context will be added as | ||||
| // functions to the parsed template, so that they can be called directly from | ||||
| // your templates! | ||||
| package generator | ||||
							
								
								
									
										50
									
								
								cmd/libs/go2idl/generator/error_tracker.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								cmd/libs/go2idl/generator/error_tracker.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package generator | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| // ErrorTracker tracks errors to the underlying writer, so that you can ignore | ||||
| // them until you're ready to return. | ||||
| type ErrorTracker struct { | ||||
| 	io.Writer | ||||
| 	err error | ||||
| } | ||||
|  | ||||
| // NewErrorTracker makes a new error tracker; note that it implements io.Writer. | ||||
| func NewErrorTracker(w io.Writer) *ErrorTracker { | ||||
| 	return &ErrorTracker{Writer: w} | ||||
| } | ||||
|  | ||||
| // Write intercepts calls to Write. | ||||
| func (et *ErrorTracker) Write(p []byte) (n int, err error) { | ||||
| 	if et.err != nil { | ||||
| 		return 0, et.err | ||||
| 	} | ||||
| 	n, err = et.Writer.Write(p) | ||||
| 	if err != nil { | ||||
| 		et.err = err | ||||
| 	} | ||||
| 	return n, err | ||||
| } | ||||
|  | ||||
| // Error returns nil if no error has occurred, otherwise it returns the error. | ||||
| func (et *ErrorTracker) Error() error { | ||||
| 	return et.err | ||||
| } | ||||
							
								
								
									
										226
									
								
								cmd/libs/go2idl/generator/execute.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								cmd/libs/go2idl/generator/execute.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package generator | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go/format" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/namer" | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/types" | ||||
| ) | ||||
|  | ||||
| // ExecutePackages runs the generators for every package in 'packages'. 'outDir' | ||||
| // is the base directory in which to place all the generated packages; it | ||||
| // should be a physical path on disk, not an import path. e.g.: | ||||
| // /path/to/home/path/to/gopath/src/ | ||||
| // Each package has its import path already, this will be appended to 'outDir'. | ||||
| func (c *Context) ExecutePackages(outDir string, packages Packages) error { | ||||
| 	for _, p := range packages { | ||||
| 		if err := c.ExecutePackage(outDir, p); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type file struct { | ||||
| 	name        string | ||||
| 	packageName string | ||||
| 	header      []byte | ||||
| 	imports     map[string]struct{} | ||||
| 	vars        bytes.Buffer | ||||
| 	consts      bytes.Buffer | ||||
| 	body        bytes.Buffer | ||||
| } | ||||
|  | ||||
| func (f *file) assembleToFile(pathname string) error { | ||||
| 	log.Printf("Assembling file %q", pathname) | ||||
| 	destFile, err := os.Create(pathname) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer destFile.Close() | ||||
|  | ||||
| 	b := &bytes.Buffer{} | ||||
| 	et := NewErrorTracker(b) | ||||
| 	f.assemble(et) | ||||
| 	if et.Error() != nil { | ||||
| 		return et.Error() | ||||
| 	} | ||||
| 	if formatted, err := format.Source(b.Bytes()); err != nil { | ||||
| 		log.Printf("Warning: unable to run gofmt on %q (%v).", pathname, err) | ||||
| 		_, err = destFile.Write(b.Bytes()) | ||||
| 		return err | ||||
| 	} else { | ||||
| 		_, err = destFile.Write(formatted) | ||||
| 		return err | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (f *file) assemble(w io.Writer) { | ||||
| 	w.Write(f.header) | ||||
| 	fmt.Fprintf(w, "package %v\n\n", f.packageName) | ||||
|  | ||||
| 	if len(f.imports) > 0 { | ||||
| 		fmt.Fprint(w, "import (\n") | ||||
| 		for i := range f.imports { | ||||
| 			if strings.Contains(i, "\"") { | ||||
| 				// they included quotes, or are using the | ||||
| 				// `name "path/to/pkg"` format. | ||||
| 				fmt.Fprintf(w, "\t%s\n", i) | ||||
| 			} else { | ||||
| 				fmt.Fprintf(w, "\t%q\n", i) | ||||
| 			} | ||||
| 		} | ||||
| 		fmt.Fprint(w, ")\n\n") | ||||
| 	} | ||||
|  | ||||
| 	if f.vars.Len() > 0 { | ||||
| 		fmt.Fprint(w, "var (\n") | ||||
| 		w.Write(f.vars.Bytes()) | ||||
| 		fmt.Fprint(w, ")\n\n") | ||||
| 	} | ||||
|  | ||||
| 	if f.consts.Len() > 0 { | ||||
| 		fmt.Fprint(w, "const (\n") | ||||
| 		w.Write(f.consts.Bytes()) | ||||
| 		fmt.Fprint(w, ")\n\n") | ||||
| 	} | ||||
|  | ||||
| 	w.Write(f.body.Bytes()) | ||||
| } | ||||
|  | ||||
| // format should be one line only, and not end with \n. | ||||
| func addIndentHeaderComment(b *bytes.Buffer, format string, args ...interface{}) { | ||||
| 	if b.Len() > 0 { | ||||
| 		fmt.Fprintf(b, "\n\t// "+format+"\n", args...) | ||||
| 	} else { | ||||
| 		fmt.Fprintf(b, "\t// "+format+"\n", args...) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *Context) filteredBy(f func(*Context, *types.Type) bool) *Context { | ||||
| 	c2 := *c | ||||
| 	c2.Order = []*types.Type{} | ||||
| 	for _, t := range c.Order { | ||||
| 		if f(c, t) { | ||||
| 			c2.Order = append(c2.Order, t) | ||||
| 		} | ||||
| 	} | ||||
| 	return &c2 | ||||
| } | ||||
|  | ||||
| // make a new context; inheret c.Namers, but add on 'namers'. In case of a name | ||||
| // collision, the namer in 'namers' wins. | ||||
| func (c *Context) addNameSystems(namers namer.NameSystems) *Context { | ||||
| 	if namers == nil { | ||||
| 		return c | ||||
| 	} | ||||
| 	c2 := *c | ||||
| 	// Copy the existing name systems so we don't corrupt a parent context | ||||
| 	c2.Namers = namer.NameSystems{} | ||||
| 	for k, v := range c.Namers { | ||||
| 		c2.Namers[k] = v | ||||
| 	} | ||||
|  | ||||
| 	for name, namer := range namers { | ||||
| 		c2.Namers[name] = namer | ||||
| 	} | ||||
| 	return &c2 | ||||
| } | ||||
|  | ||||
| // ExecutePackage executes a single package. 'outDir' is the base directory in | ||||
| // which to place the package; it should be a physical path on disk, not an | ||||
| // import path. e.g.: '/path/to/home/path/to/gopath/src/' The package knows its | ||||
| // import path already, this will be appended to 'outDir'. | ||||
| func (c *Context) ExecutePackage(outDir string, p Package) error { | ||||
| 	path := filepath.Join(outDir, p.Path()) | ||||
| 	log.Printf("Executing package %v into %v", p.Name(), path) | ||||
| 	// Filter out any types the *package* doesn't care about. | ||||
| 	packageContext := c.filteredBy(p.Filter) | ||||
| 	os.MkdirAll(path, 0755) | ||||
| 	files := map[string]*file{} | ||||
| 	for _, g := range p.Generators(packageContext) { | ||||
| 		// Filter out types the *generator* doesn't care about. | ||||
| 		genContext := packageContext.filteredBy(g.Filter) | ||||
| 		// Now add any extra name systems defined by this generator | ||||
| 		genContext = genContext.addNameSystems(g.Namers(genContext)) | ||||
|  | ||||
| 		f := files[g.Filename()] | ||||
| 		if f == nil { | ||||
| 			// This is the first generator to reference this file, so start it. | ||||
| 			f = &file{ | ||||
| 				name:        g.Filename(), | ||||
| 				packageName: p.Name(), | ||||
| 				header:      p.Header(g.Filename()), | ||||
| 				imports:     map[string]struct{}{}, | ||||
| 			} | ||||
| 			files[f.name] = f | ||||
| 		} | ||||
| 		if vars := g.PackageVars(genContext); len(vars) > 0 { | ||||
| 			addIndentHeaderComment(&f.vars, "Package-wide variables from generator %q.", g.Name()) | ||||
| 			for _, v := range vars { | ||||
| 				if _, err := fmt.Fprintf(&f.vars, "\t%s\n", v); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if consts := g.PackageVars(genContext); len(consts) > 0 { | ||||
| 			addIndentHeaderComment(&f.consts, "Package-wide consts from generator %q.", g.Name()) | ||||
| 			for _, v := range consts { | ||||
| 				if _, err := fmt.Fprintf(&f.consts, "\t%s\n", v); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if err := genContext.executeBody(&f.body, g); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if imports := g.Imports(genContext); len(imports) > 0 { | ||||
| 			for _, i := range imports { | ||||
| 				f.imports[i] = struct{}{} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, f := range files { | ||||
| 		if err := f.assembleToFile(filepath.Join(path, f.name)); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *Context) executeBody(w io.Writer, generator Generator) error { | ||||
| 	et := NewErrorTracker(w) | ||||
| 	if err := generator.Init(c, et); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, t := range c.Order { | ||||
| 		if err := generator.GenerateType(c, t, et); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return et.Error() | ||||
| } | ||||
							
								
								
									
										160
									
								
								cmd/libs/go2idl/generator/generator.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								cmd/libs/go2idl/generator/generator.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package generator | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
|  | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/namer" | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/parser" | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/types" | ||||
| ) | ||||
|  | ||||
| // Package contains the contract for generating a package. | ||||
| type Package interface { | ||||
| 	// Name returns the package short name. | ||||
| 	Name() string | ||||
| 	// Path returns the package import path. | ||||
| 	Path() string | ||||
|  | ||||
| 	// Filter should return true if this package cares about this type. | ||||
| 	// Otherwise, this type will be ommitted from the type ordering for | ||||
| 	// this package. | ||||
| 	Filter(*Context, *types.Type) bool | ||||
|  | ||||
| 	// Header should return a header for the file, including comment markers. | ||||
| 	// Useful for copyright notices and doc strings. Include an | ||||
| 	// autogeneration notice! Do not include the "package x" line. | ||||
| 	Header(filename string) []byte | ||||
|  | ||||
| 	// Generators returns the list of generators for this package. It is | ||||
| 	// allowed for more than one generator to write to the same file. | ||||
| 	// A Context is passed in case the list of generators depends on the | ||||
| 	// input types. | ||||
| 	Generators(*Context) []Generator | ||||
| } | ||||
|  | ||||
| // Packages is a list of packages to generate. | ||||
| type Packages []Package | ||||
|  | ||||
| // Generator is the contract for anything that wants to do auto-generation. | ||||
| // It's expected that the io.Writers passed to the below functions will be | ||||
| // ErrorTrackers; this allows implementations to not check for io errors, | ||||
| // making more readable code. | ||||
| // | ||||
| // The call order for the functions that take a Context is: | ||||
| // 1. Filter()        // Subsequent calls see only types that pass this. | ||||
| // 2. Namers()        // Subsequent calls see the namers provided by this. | ||||
| // 3. PackageVars() | ||||
| // 4. PackageConsts() | ||||
| // 5. Init() | ||||
| // 6. GenerateType()  // Called N times, once per type in the context's Order. | ||||
| // 7. Imports() | ||||
| // | ||||
| // You may have multiple generators for the same file. | ||||
| type Generator interface { | ||||
| 	// The name of this generator. Will be included in generated comments. | ||||
| 	Name() string | ||||
|  | ||||
| 	// Filter should return true if this generator cares about this type. | ||||
| 	// (otherwise, GenerateType will not be called.) | ||||
| 	// | ||||
| 	// Filter is called before any of the generator's other functions; | ||||
| 	// subsequent calls will get a context with only the types that passed | ||||
| 	// this filter. | ||||
| 	Filter(*Context, *types.Type) bool | ||||
|  | ||||
| 	// If this generator needs special namers, return them here. These will | ||||
| 	// override the original namers in the context if there is a collision. | ||||
| 	// You may return nil if you don't need special names. These names will | ||||
| 	// be available in the context passed to the rest of the generator's | ||||
| 	// functions. | ||||
| 	// | ||||
| 	// A use case for this is to return a namer that tracks imports. | ||||
| 	Namers(*Context) namer.NameSystems | ||||
|  | ||||
| 	// Init should write an init function, and any other content that's not | ||||
| 	// generated per-type. (It's not intended for generator specific | ||||
| 	// initialization! Do that when your Package constructs the | ||||
| 	// Generators.) | ||||
| 	Init(*Context, io.Writer) error | ||||
|  | ||||
| 	// PackageVars should emit an array of variable lines. They will be | ||||
| 	// placed in a var ( ... ) block. There's no need to include a leading | ||||
| 	// \t or trailing \n. | ||||
| 	PackageVars(*Context) []string | ||||
|  | ||||
| 	// PackageConsts should emit an array of constant lines. They will be | ||||
| 	// placed in a const ( ... ) block. There's no need to include a leading | ||||
| 	// \t or trailing \n. | ||||
| 	PackageConsts(*Context) []string | ||||
|  | ||||
| 	// GenerateType should emit the code for a particular type. | ||||
| 	GenerateType(*Context, *types.Type, io.Writer) error | ||||
|  | ||||
| 	// Imports should return a list of necessary imports. They will be | ||||
| 	// formatted correctly. You do not need to include quotation marks, | ||||
| 	// return only the package name; alternatively, you can also return | ||||
| 	// imports in the format `name "path/to/pkg"`. Imports will be called | ||||
| 	// after Init, PackageVars, PackageConsts, and GenerateType, to allow | ||||
| 	// you to keep track of what imports you actually need. | ||||
| 	Imports(*Context) []string | ||||
|  | ||||
| 	// Preferred file name of this generator, not including a path. It is | ||||
| 	// allowed for multiple generators to use the same filename, but it's | ||||
| 	// up to you to make sure they don't have colliding import names. | ||||
| 	// TODO: provide per-file import tracking, removing the requirement | ||||
| 	// that generators coordinate.. | ||||
| 	Filename() string | ||||
| } | ||||
|  | ||||
| // Context is global context for individual generators to consume. | ||||
| type Context struct { | ||||
| 	// A map from the naming system to the names for that system. E.g., you | ||||
| 	// might have public names and several private naming systems. | ||||
| 	Namers namer.NameSystems | ||||
|  | ||||
| 	// All the types, in case you want to look up something. | ||||
| 	Universe types.Universe | ||||
|  | ||||
| 	// The canonical ordering of the types (will be filtered by both the | ||||
| 	// Package's and Generator's Filter methods). | ||||
| 	Order []*types.Type | ||||
| } | ||||
|  | ||||
| // NewContext generates a context from the given builder, naming systems, and | ||||
| // the naming system you wish to construct the canonical ordering from. | ||||
| func NewContext(b *parser.Builder, nameSystems namer.NameSystems, canonicalOrderName string) (*Context, error) { | ||||
| 	u, err := b.FindTypes() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	c := &Context{ | ||||
| 		Namers:   namer.NameSystems{}, | ||||
| 		Universe: u, | ||||
| 	} | ||||
|  | ||||
| 	for name, systemNamer := range nameSystems { | ||||
| 		c.Namers[name] = systemNamer | ||||
| 		if name == canonicalOrderName { | ||||
| 			orderer := namer.Orderer{systemNamer} | ||||
| 			c.Order = orderer.Order(u) | ||||
| 		} | ||||
| 	} | ||||
| 	return c, nil | ||||
| } | ||||
							
								
								
									
										97
									
								
								cmd/libs/go2idl/generator/import_tracker.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								cmd/libs/go2idl/generator/import_tracker.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package generator | ||||
|  | ||||
| import ( | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/types" | ||||
| ) | ||||
|  | ||||
| // ImportTracker may be passed to a namer.RawNamer, to track the imports needed | ||||
| // for the types it names. | ||||
| // | ||||
| // TODO: pay attention to the package name (instead of renaming every package). | ||||
| // TODO: Figure out the best way to make names for packages that collide. | ||||
| type ImportTracker struct { | ||||
| 	pathToName map[string]string | ||||
| 	// forbidden names are in here. (e.g. "go" is a directory in which | ||||
| 	// there is code, but "go" is not a legal name for a package, so we put | ||||
| 	// it here to prevent us from naming any package "go") | ||||
| 	nameToPath map[string]string | ||||
| } | ||||
|  | ||||
| func NewImportTracker(types ...*types.Type) *ImportTracker { | ||||
| 	tracker := &ImportTracker{ | ||||
| 		pathToName: map[string]string{}, | ||||
| 		nameToPath: map[string]string{ | ||||
| 			"go": "", | ||||
| 			// Add other forbidden keywords that also happen to be | ||||
| 			// package names here. | ||||
| 		}, | ||||
| 	} | ||||
| 	tracker.AddTypes(types...) | ||||
| 	return tracker | ||||
| } | ||||
|  | ||||
| func (tracker *ImportTracker) AddTypes(types ...*types.Type) { | ||||
| 	for _, t := range types { | ||||
| 		tracker.AddType(t) | ||||
| 	} | ||||
| } | ||||
| func (tracker *ImportTracker) AddType(t *types.Type) { | ||||
| 	path := t.Name.Package | ||||
| 	if path == "" { | ||||
| 		return | ||||
| 	} | ||||
| 	if _, ok := tracker.pathToName[path]; ok { | ||||
| 		return | ||||
| 	} | ||||
| 	dirs := strings.Split(path, string(filepath.Separator)) | ||||
| 	for n := len(dirs) - 1; n >= 0; n-- { | ||||
| 		// TODO: bikeshed about whether it's more readable to have an | ||||
| 		// _, something else, or nothing between directory names. | ||||
| 		name := strings.Join(dirs[n:], "_") | ||||
| 		// These characters commonly appear in import paths for go | ||||
| 		// packages, but aren't legal go names. So we'll sanitize. | ||||
| 		name = strings.Replace(name, ".", "_", -1) | ||||
| 		name = strings.Replace(name, "-", "_", -1) | ||||
| 		if _, found := tracker.nameToPath[name]; found { | ||||
| 			// This name collides with some other package | ||||
| 			continue | ||||
| 		} | ||||
| 		tracker.nameToPath[name] = path | ||||
| 		tracker.pathToName[path] = name | ||||
| 		return | ||||
| 	} | ||||
| 	panic("can't find import for " + path) | ||||
| } | ||||
|  | ||||
| func (tracker *ImportTracker) ImportLines() []string { | ||||
| 	out := []string{} | ||||
| 	for path, name := range tracker.pathToName { | ||||
| 		out = append(out, name+" \""+path+"\"") | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
|  | ||||
| // LocalNameOf returns the name you would use to refer to the package at the | ||||
| // specified path within the body of a file. | ||||
| func (tracker *ImportTracker) LocalNameOf(path string) string { | ||||
| 	return tracker.pathToName[path] | ||||
| } | ||||
							
								
								
									
										122
									
								
								cmd/libs/go2idl/generator/snippet_writer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								cmd/libs/go2idl/generator/snippet_writer.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package generator | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"runtime" | ||||
| 	"text/template" | ||||
| ) | ||||
|  | ||||
| // SnippetWriter is an attempt to make the template library usable. | ||||
| // Methods are chainable, and you don't have to check Error() until you're all | ||||
| // done. | ||||
| type SnippetWriter struct { | ||||
| 	w       io.Writer | ||||
| 	context *Context | ||||
| 	// Left & right delimiters. text/template defaults to "{{" and "}}" | ||||
| 	// which is totally unusable for go code based templates. | ||||
| 	left, right string | ||||
| 	funcMap     template.FuncMap | ||||
| 	err         error | ||||
| } | ||||
|  | ||||
| // w is the destination; left and right are the delimiters; @ and $ are both | ||||
| // reasonable choices. | ||||
| // | ||||
| // c is used to make a function for every naming system, to which you can pass | ||||
| // a type and get the corresponding name. | ||||
| func NewSnippetWriter(w io.Writer, c *Context, left, right string) *SnippetWriter { | ||||
| 	sw := &SnippetWriter{ | ||||
| 		w:       w, | ||||
| 		context: c, | ||||
| 		left:    left, | ||||
| 		right:   right, | ||||
| 		funcMap: template.FuncMap{}, | ||||
| 	} | ||||
| 	for name, namer := range c.Namers { | ||||
| 		sw.funcMap[name] = namer.Name | ||||
| 	} | ||||
| 	return sw | ||||
| } | ||||
|  | ||||
| // Do parses format and runs args through it. You can have arbitrary logic in | ||||
| // the format (see the text/template documentation), but consider running many | ||||
| // short templaces, with ordinary go logic in between--this may be more | ||||
| // readable. Do is chainable. Any error causes every other call to do to be | ||||
| // ignored, and the error will be returned by Error(). So you can check it just | ||||
| // once, at the end of your function. | ||||
| // | ||||
| // 'args' can be quite literally anything; read the text/template documentation | ||||
| // for details. Maps and structs work particularly nicely. Conveniently, the | ||||
| // types package is designed to have structs that are easily referencable from | ||||
| // the template language. | ||||
| // | ||||
| // Example: | ||||
| // | ||||
| // sw := generator.NewSnippetWriter(outBuffer, context, "$", "$") | ||||
| // sw.Do(`The public type name is: $.type|public$`, map[string]interface{}{"type": t}) | ||||
| // return sw.Error() | ||||
| // | ||||
| // Where: | ||||
| // * "$" starts a template directive | ||||
| // * "." references the entire thing passed as args | ||||
| // * "type" therefore sees a map and looks up the key "type" | ||||
| // * "|" means "pass the thing on the left to the thing on the right" | ||||
| // * "public" is the name of a naming system, so the SnippetWriter has given | ||||
| //   the template a function called "public" that takes a *types.Type and | ||||
| //   returns the naming system's name. E.g., if the type is "string" this might | ||||
| //   return "String". | ||||
| // * the second "$" ends the template directive. | ||||
| // | ||||
| // The map is actually not necessary. The below does the same thing: | ||||
| // | ||||
| // sw.Do(`The public type name is: $.|public$`, t) | ||||
| // | ||||
| // You may or may not find it more readable to use the map with a descriptive | ||||
| // key, but if you want to pass more than one arg, the map or a custom struct | ||||
| // becomes a requirement. You can do arbitrary logic inside these templates, | ||||
| // but you should consider doing the logic in go and stitching them together | ||||
| // for the sake of your readers. | ||||
| func (s *SnippetWriter) Do(format string, args interface{}) *SnippetWriter { | ||||
| 	if s.err != nil { | ||||
| 		return s | ||||
| 	} | ||||
| 	// Name the template by source file:line so it can be found when | ||||
| 	// there's an error. | ||||
| 	_, file, line, _ := runtime.Caller(1) | ||||
| 	tmpl, err := template. | ||||
| 		New(fmt.Sprintf("%s:%d", file, line)). | ||||
| 		Delims(s.left, s.right). | ||||
| 		Funcs(s.funcMap). | ||||
| 		Parse(format) | ||||
| 	if err != nil { | ||||
| 		s.err = err | ||||
| 		return s | ||||
| 	} | ||||
| 	err = tmpl.Execute(s.w, args) | ||||
| 	if err != nil { | ||||
| 		s.err = err | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // Error returns any encountered error. | ||||
| func (s *SnippetWriter) Error() error { | ||||
| 	return s.err | ||||
| } | ||||
							
								
								
									
										88
									
								
								cmd/libs/go2idl/generator/snippet_writer_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								cmd/libs/go2idl/generator/snippet_writer_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package generator_test | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/generator" | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/namer" | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/parser" | ||||
| ) | ||||
|  | ||||
| func construct(t *testing.T, files map[string]string) *generator.Context { | ||||
| 	b := parser.New() | ||||
| 	for name, src := range files { | ||||
| 		if err := b.AddFile(name, []byte(src)); err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
| 	} | ||||
| 	c, err := generator.NewContext(b, namer.NameSystems{ | ||||
| 		"public":  namer.NewPublicNamer(0), | ||||
| 		"private": namer.NewPrivateNamer(0), | ||||
| 	}, "public") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| func TestSnippetWriter(t *testing.T) { | ||||
| 	var structTest = map[string]string{ | ||||
| 		"base/foo/proto/foo.go": ` | ||||
| package foo | ||||
|  | ||||
| // Blah is a test. | ||||
| // A test, I tell you. | ||||
| type Blah struct { | ||||
| 	// A is the first field. | ||||
| 	A int64 ` + "`" + `json:"a"` + "`" + ` | ||||
|  | ||||
| 	// B is the second field. | ||||
| 	// Multiline comments work. | ||||
| 	B string ` + "`" + `json:"b"` + "`" + ` | ||||
| } | ||||
| `, | ||||
| 	} | ||||
|  | ||||
| 	c := construct(t, structTest) | ||||
| 	b := &bytes.Buffer{} | ||||
| 	err := generator.NewSnippetWriter(b, c, "$", "$"). | ||||
| 		Do("$.|public$$.|private$", c.Order[0]). | ||||
| 		Error() | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Unexpected error %v", err) | ||||
| 	} | ||||
| 	if e, a := "Blahblah", b.String(); e != a { | ||||
| 		t.Errorf("Expected %q, got %q", e, a) | ||||
| 	} | ||||
|  | ||||
| 	err = generator.NewSnippetWriter(b, c, "$", "$"). | ||||
| 		Do("$.|public", c.Order[0]). | ||||
| 		Error() | ||||
| 	if err == nil { | ||||
| 		t.Errorf("expected error on invalid template") | ||||
| 	} else { | ||||
| 		// Dear reader, I apologize for making the worst change | ||||
| 		// detection test in the history of ever. | ||||
| 		if e, a := "snippet_writer_test.go:78", err.Error(); !strings.Contains(a, e) { | ||||
| 			t.Errorf("Expected %q but didn't find it in %q", e, a) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										31
									
								
								cmd/libs/go2idl/namer/doc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								cmd/libs/go2idl/namer/doc.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| // Package namer has support for making different type naming systems. | ||||
| // | ||||
| // This is because sometimes you want to refer to the literal type, sometimes | ||||
| // you want to make a name for the thing you're generating, and you want to | ||||
| // make the name based on the type. For example, if you have `type foo string`, | ||||
| // you want to be able to generate something like `func FooPrinter(f *foo) { | ||||
| // Print(string(*f)) }`; that is, you want to refer to a public name, a literal | ||||
| // name, and the underlying literal name. | ||||
| // | ||||
| // This package supports the idea of a "Namer" and a set of "NameSystems" to | ||||
| // support these use cases. | ||||
| // | ||||
| // Additionally, a "RawNamer" can optionally keep track of what needs to be | ||||
| // imported. | ||||
| package namer | ||||
							
								
								
									
										347
									
								
								cmd/libs/go2idl/namer/namer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										347
									
								
								cmd/libs/go2idl/namer/namer.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,347 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package namer | ||||
|  | ||||
| import ( | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/types" | ||||
| ) | ||||
|  | ||||
| // NewPublicNamer is a helper function that returns a namer that makes | ||||
| // CamelCase names. See the NameStrategy struct for an explanation of the | ||||
| // arguments to this constructor. | ||||
| func NewPublicNamer(prependPackageNames int, ignoreWords ...string) *NameStrategy { | ||||
| 	n := &NameStrategy{ | ||||
| 		Join:                Joiner(IC, IC), | ||||
| 		IgnoreWords:         map[string]bool{}, | ||||
| 		PrependPackageNames: prependPackageNames, | ||||
| 	} | ||||
| 	for _, w := range ignoreWords { | ||||
| 		n.IgnoreWords[w] = true | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| // NewPrivateNamer is a helper function that returns a namer that makes | ||||
| // camelCase names. See the NameStrategy struct for an explanation of the | ||||
| // arguments to this constructor. | ||||
| func NewPrivateNamer(prependPackageNames int, ignoreWords ...string) *NameStrategy { | ||||
| 	n := &NameStrategy{ | ||||
| 		Join:                Joiner(IL, IC), | ||||
| 		IgnoreWords:         map[string]bool{}, | ||||
| 		PrependPackageNames: prependPackageNames, | ||||
| 	} | ||||
| 	for _, w := range ignoreWords { | ||||
| 		n.IgnoreWords[w] = true | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| // NewRawNamer will return a Namer that makes a name by which you would | ||||
| // directly refer to a type, optionally keeping track of the import paths | ||||
| // necessary to reference the names it provides. Tracker may be nil. | ||||
| // | ||||
| // For example, if the type is map[string]int, a raw namer will literally | ||||
| // return "map[string]int". | ||||
| // | ||||
| // Or if the type, in package foo, is "type Bar struct { ... }", then the raw | ||||
| // namer will return "foo.Bar" as the name of the type, and if 'tracker' was | ||||
| // not nil, will record that package foo needs to be imported. | ||||
| func NewRawNamer(tracker ImportTracker) *rawNamer { | ||||
| 	return &rawNamer{tracker: tracker} | ||||
| } | ||||
|  | ||||
| // Names is a map from Type to name, as defined by some Namer. | ||||
| type Names map[*types.Type]string | ||||
|  | ||||
| // Namer takes a type, and assigns a name. | ||||
| // | ||||
| // The purpose of this complexity is so that you can assign coherent | ||||
| // side-by-side systems of names for the types. For example, you might want a | ||||
| // public interface, a private implementation struct, and also to reference | ||||
| // literally the type name. | ||||
| // | ||||
| // Note that it is safe to call your own Name() function recursively to find | ||||
| // the names of keys, elements, etc. This is because anonymous types can't have | ||||
| // cycles in their names, and named types don't require the sort of recursion | ||||
| // that would be problematic. | ||||
| type Namer interface { | ||||
| 	Name(*types.Type) string | ||||
| } | ||||
|  | ||||
| // NameSystems is a map of a system name to a namer for that system. | ||||
| type NameSystems map[string]Namer | ||||
|  | ||||
| // NameStrategy is a general Namer. The easiest way to use it is to copy the | ||||
| // Public/PrivateNamer variables, and modify the members you wish to change. | ||||
| // | ||||
| // The Name method produces a name for the given type, of the forms: | ||||
| // Anonymous types: <Prefix><Type description><Suffix> | ||||
| // Named types: <Prefix><Optional Prepended Package name(s)><Original name><Suffix> | ||||
| // | ||||
| // In all cases, every part of the name is run through the capitalization | ||||
| // functions. | ||||
| // | ||||
| // The IgnoreWords map can be set if you have directory names that are | ||||
| // semantically meaningless for naming purposes, e.g. "proto". | ||||
| // | ||||
| // Prefix and Suffix can be used to disambiguate parallel systems of type | ||||
| // names. For example, if you want to generate an interface and an | ||||
| // implementation, you might want to suffix one with "Interface" and the other | ||||
| // with "Implementation". Another common use-- if you want to generate private | ||||
| // types, and one of your source types could be "string", you can't use the | ||||
| // default lowercase private namer. You'll have to add a suffix or prefix. | ||||
| type NameStrategy struct { | ||||
| 	Prefix, Suffix string | ||||
| 	Join           func(pre string, parts []string, post string) string | ||||
|  | ||||
| 	// Add non-meaningful package directory names here (e.g. "proto") and | ||||
| 	// they will be ignored. | ||||
| 	IgnoreWords map[string]bool | ||||
|  | ||||
| 	// If > 0, prepend exactly that many package directory names (or as | ||||
| 	// many as there are).  Package names listed in "IgnoreWords" will be | ||||
| 	// ignored. | ||||
| 	// | ||||
| 	// For example, if Ignore words lists "proto" and type Foo is in | ||||
| 	// pkg/server/frobbing/proto, then a value of 1 will give a type name | ||||
| 	// of FrobbingFoo, 2 gives ServerFrobbingFoo, etc. | ||||
| 	PrependPackageNames int | ||||
|  | ||||
| 	// A cache of names thus far assigned by this namer. | ||||
| 	Names | ||||
| } | ||||
|  | ||||
| // IC ensures the first character is uppercase. | ||||
| func IC(in string) string { | ||||
| 	if in == "" { | ||||
| 		return in | ||||
| 	} | ||||
| 	return strings.ToUpper(in[:1]) + in[1:] | ||||
| } | ||||
|  | ||||
| // IL ensures the first character is lowercase. | ||||
| func IL(in string) string { | ||||
| 	if in == "" { | ||||
| 		return in | ||||
| 	} | ||||
| 	return strings.ToLower(in[:1]) + in[1:] | ||||
| } | ||||
|  | ||||
| // Joiner lets you specify functions that preprocess the various components of | ||||
| // a name before joining them. You can construct e.g. camelCase or CamelCase or | ||||
| // any other way of joining words. (See the IC and IL convenience functions.) | ||||
| func Joiner(first, others func(string) string) func(pre string, in []string, post string) string { | ||||
| 	return func(pre string, in []string, post string) string { | ||||
| 		tmp := []string{others(pre)} | ||||
| 		for i := range in { | ||||
| 			tmp = append(tmp, others(in[i])) | ||||
| 		} | ||||
| 		tmp = append(tmp, others(post)) | ||||
| 		return first(strings.Join(tmp, "")) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (ns *NameStrategy) removePrefixAndSuffix(s string) string { | ||||
| 	// The join function may have changed capitalization. | ||||
| 	lowerIn := strings.ToLower(s) | ||||
| 	lowerP := strings.ToLower(ns.Prefix) | ||||
| 	lowerS := strings.ToLower(ns.Suffix) | ||||
| 	b, e := 0, len(s) | ||||
| 	if strings.HasPrefix(lowerIn, lowerP) { | ||||
| 		b = len(ns.Prefix) | ||||
| 	} | ||||
| 	if strings.HasSuffix(lowerIn, lowerS) { | ||||
| 		e -= len(ns.Suffix) | ||||
| 	} | ||||
| 	return s[b:e] | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	importPathNameSanitizer = strings.NewReplacer("-", "_", ".", "") | ||||
| ) | ||||
|  | ||||
| // filters out unwanted directory names and sanitizes remaining names. | ||||
| func (ns *NameStrategy) filterDirs(path string) []string { | ||||
| 	allDirs := strings.Split(path, string(filepath.Separator)) | ||||
| 	dirs := make([]string, 0, len(allDirs)) | ||||
| 	for _, p := range allDirs { | ||||
| 		if ns.IgnoreWords == nil || !ns.IgnoreWords[p] { | ||||
| 			dirs = append(dirs, importPathNameSanitizer.Replace(p)) | ||||
| 		} | ||||
| 	} | ||||
| 	return dirs | ||||
| } | ||||
|  | ||||
| // See the comment on NameStrategy. | ||||
| func (ns *NameStrategy) Name(t *types.Type) string { | ||||
| 	if ns.Names == nil { | ||||
| 		ns.Names = Names{} | ||||
| 	} | ||||
| 	if s, ok := ns.Names[t]; ok { | ||||
| 		return s | ||||
| 	} | ||||
|  | ||||
| 	if t.Name.Package != "" { | ||||
| 		dirs := append(ns.filterDirs(t.Name.Package), t.Name.Name) | ||||
| 		i := ns.PrependPackageNames + 1 | ||||
| 		dn := len(dirs) | ||||
| 		if i > dn { | ||||
| 			i = dn | ||||
| 		} | ||||
| 		name := ns.Join(ns.Prefix, dirs[dn-i:], ns.Suffix) | ||||
| 		ns.Names[t] = name | ||||
| 		return name | ||||
| 	} | ||||
|  | ||||
| 	// Only anonymous types remain. | ||||
| 	var name string | ||||
| 	switch t.Kind { | ||||
| 	case types.Builtin: | ||||
| 		name = ns.Join(ns.Prefix, []string{t.Name.Name}, ns.Suffix) | ||||
| 	case types.Map: | ||||
| 		name = ns.Join(ns.Prefix, []string{ | ||||
| 			"Map", | ||||
| 			ns.removePrefixAndSuffix(ns.Name(t.Key)), | ||||
| 			"To", | ||||
| 			ns.removePrefixAndSuffix(ns.Name(t.Elem)), | ||||
| 		}, ns.Suffix) | ||||
| 	case types.Slice: | ||||
| 		name = ns.Join(ns.Prefix, []string{ | ||||
| 			"Slice", | ||||
| 			ns.removePrefixAndSuffix(ns.Name(t.Elem)), | ||||
| 		}, ns.Suffix) | ||||
| 	case types.Pointer: | ||||
| 		name = ns.Join(ns.Prefix, []string{ | ||||
| 			"Pointer", | ||||
| 			ns.removePrefixAndSuffix(ns.Name(t.Elem)), | ||||
| 		}, ns.Suffix) | ||||
| 	case types.Struct: | ||||
| 		names := []string{"Struct"} | ||||
| 		for _, m := range t.Members { | ||||
| 			names = append(names, ns.removePrefixAndSuffix(ns.Name(m.Type))) | ||||
| 		} | ||||
| 		name = ns.Join(ns.Prefix, names, ns.Suffix) | ||||
| 	// TODO: add types.Chan | ||||
| 	case types.Interface: | ||||
| 		// TODO: add to name test | ||||
| 		names := []string{"Interface"} | ||||
| 		for _, m := range t.Methods { | ||||
| 			// TODO: include function signature | ||||
| 			names = append(names, m.Name.Name) | ||||
| 		} | ||||
| 		name = ns.Join(ns.Prefix, names, ns.Suffix) | ||||
| 	case types.Func: | ||||
| 		// TODO: add to name test | ||||
| 		parts := []string{"Func"} | ||||
| 		for _, pt := range t.Signature.Parameters { | ||||
| 			parts = append(parts, ns.removePrefixAndSuffix(ns.Name(pt))) | ||||
| 		} | ||||
| 		parts = append(parts, "Returns") | ||||
| 		for _, rt := range t.Signature.Results { | ||||
| 			parts = append(parts, ns.removePrefixAndSuffix(ns.Name(rt))) | ||||
| 		} | ||||
| 		name = ns.Join(ns.Prefix, parts, ns.Suffix) | ||||
| 	default: | ||||
| 		name = "unnameable_" + string(t.Kind) | ||||
| 	} | ||||
| 	ns.Names[t] = name | ||||
| 	return name | ||||
| } | ||||
|  | ||||
| // ImportTracker allows a raw namer to keep track of the packages needed for | ||||
| // import. You can implement yourself or use the one in the generation package. | ||||
| type ImportTracker interface { | ||||
| 	AddType(*types.Type) | ||||
| 	LocalNameOf(packagePath string) string | ||||
| } | ||||
|  | ||||
| type rawNamer struct { | ||||
| 	tracker ImportTracker | ||||
| 	Names | ||||
| } | ||||
|  | ||||
| // Name makes a name the way you'd write it to literally refer to type t, | ||||
| // making ordinary assumptions about how you've imported t's package (or using | ||||
| // r.tracker to specifically track the package imports). | ||||
| func (r *rawNamer) Name(t *types.Type) string { | ||||
| 	if r.Names == nil { | ||||
| 		r.Names = Names{} | ||||
| 	} | ||||
| 	if name, ok := r.Names[t]; ok { | ||||
| 		return name | ||||
| 	} | ||||
| 	if t.Name.Package != "" { | ||||
| 		var name string | ||||
| 		if r.tracker != nil { | ||||
| 			r.tracker.AddType(t) | ||||
| 			name = r.tracker.LocalNameOf(t.Name.Package) + "." + t.Name.Name | ||||
| 		} else { | ||||
| 			name = filepath.Base(t.Name.Package) + "." + t.Name.Name | ||||
| 		} | ||||
| 		r.Names[t] = name | ||||
| 		return name | ||||
| 	} | ||||
| 	var name string | ||||
| 	switch t.Kind { | ||||
| 	case types.Builtin: | ||||
| 		name = t.Name.Name | ||||
| 	case types.Map: | ||||
| 		name = "map[" + r.Name(t.Key) + "]" + r.Name(t.Elem) | ||||
| 	case types.Slice: | ||||
| 		name = "[]" + r.Name(t.Elem) | ||||
| 	case types.Pointer: | ||||
| 		name = "*" + r.Name(t.Elem) | ||||
| 	case types.Struct: | ||||
| 		elems := []string{} | ||||
| 		for _, m := range t.Members { | ||||
| 			elems = append(elems, m.Name+" "+r.Name(m.Type)) | ||||
| 		} | ||||
| 		name = "struct{" + strings.Join(elems, "; ") + "}" | ||||
| 	// TODO: add types.Chan | ||||
| 	case types.Interface: | ||||
| 		// TODO: add to name test | ||||
| 		elems := []string{} | ||||
| 		for _, m := range t.Methods { | ||||
| 			// TODO: include function signature | ||||
| 			elems = append(elems, m.Name.Name) | ||||
| 		} | ||||
| 		name = "interface{" + strings.Join(elems, "; ") + "}" | ||||
| 	case types.Func: | ||||
| 		// TODO: add to name test | ||||
| 		params := []string{} | ||||
| 		for _, pt := range t.Signature.Parameters { | ||||
| 			params = append(params, r.Name(pt)) | ||||
| 		} | ||||
| 		results := []string{} | ||||
| 		for _, rt := range t.Signature.Results { | ||||
| 			results = append(results, r.Name(rt)) | ||||
| 		} | ||||
| 		name = "func(" + strings.Join(params, ",") + ")" | ||||
| 		if len(results) == 1 { | ||||
| 			name += " " + results[0] | ||||
| 		} else if len(results) > 1 { | ||||
| 			name += " (" + strings.Join(results, ",") + ")" | ||||
| 		} | ||||
| 	default: | ||||
| 		name = "unnameable_" + string(t.Kind) | ||||
| 	} | ||||
| 	r.Names[t] = name | ||||
| 	return name | ||||
| } | ||||
							
								
								
									
										84
									
								
								cmd/libs/go2idl/namer/namer_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								cmd/libs/go2idl/namer/namer_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package namer | ||||
|  | ||||
| import ( | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
|  | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/types" | ||||
| ) | ||||
|  | ||||
| func TestNameStrategy(t *testing.T) { | ||||
| 	u := types.Universe{} | ||||
|  | ||||
| 	// Add some types. | ||||
| 	base := u.Get(types.Name{"foo/bar", "Baz"}) | ||||
| 	base.Kind = types.Struct | ||||
|  | ||||
| 	tmp := u.Get(types.Name{"", "[]bar.Baz"}) | ||||
| 	tmp.Kind = types.Slice | ||||
| 	tmp.Elem = base | ||||
|  | ||||
| 	tmp = u.Get(types.Name{"", "map[string]bar.Baz"}) | ||||
| 	tmp.Kind = types.Map | ||||
| 	tmp.Key = types.String | ||||
| 	tmp.Elem = base | ||||
|  | ||||
| 	tmp = u.Get(types.Name{"foo/other", "Baz"}) | ||||
| 	tmp.Kind = types.Struct | ||||
| 	tmp.Members = []types.Member{{ | ||||
| 		Embedded: true, | ||||
| 		Type:     base, | ||||
| 	}} | ||||
|  | ||||
| 	u.Get(types.Name{"", "string"}) | ||||
|  | ||||
| 	o := Orderer{NewPublicNamer(0)} | ||||
| 	order := o.Order(u) | ||||
| 	orderedNames := make([]string, len(order)) | ||||
| 	for i, t := range order { | ||||
| 		orderedNames[i] = o.Name(t) | ||||
| 	} | ||||
| 	expect := []string{"Baz", "Baz", "MapStringToBaz", "SliceBaz", "String"} | ||||
| 	if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { | ||||
| 		t.Errorf("Wanted %#v, got %#v", e, a) | ||||
| 	} | ||||
|  | ||||
| 	o = Orderer{NewRawNamer(nil)} | ||||
| 	order = o.Order(u) | ||||
| 	orderedNames = make([]string, len(order)) | ||||
| 	for i, t := range order { | ||||
| 		orderedNames[i] = o.Name(t) | ||||
| 	} | ||||
|  | ||||
| 	expect = []string{"[]bar.Baz", "bar.Baz", "map[string]bar.Baz", "other.Baz", "string"} | ||||
| 	if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { | ||||
| 		t.Errorf("Wanted %#v, got %#v", e, a) | ||||
| 	} | ||||
|  | ||||
| 	o = Orderer{NewPublicNamer(1)} | ||||
| 	order = o.Order(u) | ||||
| 	orderedNames = make([]string, len(order)) | ||||
| 	for i, t := range order { | ||||
| 		orderedNames[i] = o.Name(t) | ||||
| 	} | ||||
| 	expect = []string{"BarBaz", "MapStringToBarBaz", "OtherBaz", "SliceBarBaz", "String"} | ||||
| 	if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { | ||||
| 		t.Errorf("Wanted %#v, got %#v", e, a) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										52
									
								
								cmd/libs/go2idl/namer/order.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								cmd/libs/go2idl/namer/order.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package namer | ||||
|  | ||||
| import ( | ||||
| 	"sort" | ||||
|  | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/types" | ||||
| ) | ||||
|  | ||||
| // Orderer produces an ordering of types given a Namer. | ||||
| type Orderer struct { | ||||
| 	Namer | ||||
| } | ||||
|  | ||||
| // Order assigns a name to every type, and returns a list sorted by those | ||||
| // names. | ||||
| func (o *Orderer) Order(u types.Universe) []*types.Type { | ||||
| 	list := tList{ | ||||
| 		namer: o.Namer, | ||||
| 	} | ||||
| 	for _, p := range u { | ||||
| 		for _, t := range p.Types { | ||||
| 			list.types = append(list.types, t) | ||||
| 		} | ||||
| 	} | ||||
| 	sort.Sort(list) | ||||
| 	return list.types | ||||
| } | ||||
|  | ||||
| type tList struct { | ||||
| 	namer Namer | ||||
| 	types []*types.Type | ||||
| } | ||||
|  | ||||
| func (t tList) Len() int           { return len(t.types) } | ||||
| func (t tList) Less(i, j int) bool { return t.namer.Name(t.types[i]) < t.namer.Name(t.types[j]) } | ||||
| func (t tList) Swap(i, j int)      { t.types[i], t.types[j] = t.types[j], t.types[i] } | ||||
							
								
								
									
										19
									
								
								cmd/libs/go2idl/parser/doc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								cmd/libs/go2idl/parser/doc.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| // Package parser provides code to parse go files, type-check them, extract the | ||||
| // types. | ||||
| package parser | ||||
							
								
								
									
										497
									
								
								cmd/libs/go2idl/parser/parse.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										497
									
								
								cmd/libs/go2idl/parser/parse.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,497 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package parser | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/types" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/ast" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/build" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/parser" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	tc "k8s.io/kubernetes/third_party/golang/go/types" | ||||
| ) | ||||
|  | ||||
| // Builder lets you add all the go files in all the packages that you care | ||||
| // about, then constructs the type source data. | ||||
| type Builder struct { | ||||
| 	context   *build.Context | ||||
| 	buildInfo map[string]*build.Package | ||||
|  | ||||
| 	fset *token.FileSet | ||||
| 	// map of package id to list of parsed files | ||||
| 	parsed map[string][]*ast.File | ||||
|  | ||||
| 	// Set by makePackages, used by importer() and friends. | ||||
| 	pkgs map[string]*tc.Package | ||||
|  | ||||
| 	// Map of package path to whether the user requested it or it was from | ||||
| 	// an import. | ||||
| 	userRequested map[string]bool | ||||
|  | ||||
| 	// All comments from everywhere in every parsed file. | ||||
| 	endLineToCommentGroup map[fileLine]*ast.CommentGroup | ||||
|  | ||||
| 	// map of package to list of packages it imports. | ||||
| 	importGraph map[string]map[string]struct{} | ||||
| } | ||||
|  | ||||
| // key type for finding comments. | ||||
| type fileLine struct { | ||||
| 	file string | ||||
| 	line int | ||||
| } | ||||
|  | ||||
| // New constructs a new builder. | ||||
| func New() *Builder { | ||||
| 	c := build.Default | ||||
| 	if c.GOROOT == "" { | ||||
| 		if p, err := exec.Command("which", "go").CombinedOutput(); err == nil { | ||||
| 			// The returned string will have some/path/bin/go, so remove the last two elements. | ||||
| 			c.GOROOT = filepath.Dir(filepath.Dir(strings.Trim(string(p), "\n"))) | ||||
| 		} else { | ||||
| 			fmt.Printf("Warning: $GOROOT not set, and unable to run `which go` to find it: %v\n", err) | ||||
| 		} | ||||
| 	} | ||||
| 	return &Builder{ | ||||
| 		context:               &c, | ||||
| 		buildInfo:             map[string]*build.Package{}, | ||||
| 		fset:                  token.NewFileSet(), | ||||
| 		parsed:                map[string][]*ast.File{}, | ||||
| 		userRequested:         map[string]bool{}, | ||||
| 		endLineToCommentGroup: map[fileLine]*ast.CommentGroup{}, | ||||
| 		importGraph:           map[string]map[string]struct{}{}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Get package information from the go/build package. Automatically excludes | ||||
| // e.g. test files and files for other platforms-- there is quite a bit of | ||||
| // logic of that nature in the build package. | ||||
| func (b *Builder) buildPackage(pkgPath string) (*build.Package, error) { | ||||
| 	// First, find it, so we know what path to use. | ||||
| 	pkg, err := b.context.Import(pkgPath, ".", build.FindOnly) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("unable to *find* %q: %v", pkgPath, err) | ||||
| 	} | ||||
|  | ||||
| 	pkgPath = pkg.ImportPath | ||||
|  | ||||
| 	if pkg, ok := b.buildInfo[pkgPath]; ok { | ||||
| 		return pkg, nil | ||||
| 	} | ||||
| 	pkg, err = b.context.Import(pkgPath, ".", build.ImportComment) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("unable to import %q: %v", pkgPath, err) | ||||
| 	} | ||||
| 	b.buildInfo[pkgPath] = pkg | ||||
|  | ||||
| 	if b.importGraph[pkgPath] == nil { | ||||
| 		b.importGraph[pkgPath] = map[string]struct{}{} | ||||
| 	} | ||||
| 	for _, p := range pkg.Imports { | ||||
| 		b.importGraph[pkgPath][p] = struct{}{} | ||||
| 	} | ||||
| 	return pkg, nil | ||||
| } | ||||
|  | ||||
| // AddFile adds a file to the set. The name must be of the form canonical/pkg/path/file.go. | ||||
| func (b *Builder) AddFile(name string, src []byte) error { | ||||
| 	return b.addFile(name, src, true) | ||||
| } | ||||
|  | ||||
| // addFile adds a file to the set. The name must be of the form | ||||
| // canonical/pkg/path/file.go. A flag indicates whether this file was | ||||
| // user-requested or just from following the import graph. | ||||
| func (b *Builder) addFile(name string, src []byte, userRequested bool) error { | ||||
| 	p, err := parser.ParseFile(b.fset, name, src, parser.DeclarationErrors|parser.ParseComments) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pkg := filepath.Dir(name) | ||||
| 	b.parsed[pkg] = append(b.parsed[pkg], p) | ||||
| 	b.userRequested[pkg] = userRequested | ||||
| 	for _, c := range p.Comments { | ||||
| 		position := b.fset.Position(c.End()) | ||||
| 		b.endLineToCommentGroup[fileLine{position.Filename, position.Line}] = c | ||||
| 	} | ||||
|  | ||||
| 	// We have to get the packages from this specific file, in case the | ||||
| 	// user added individual files instead of entire directories. | ||||
| 	if b.importGraph[pkg] == nil { | ||||
| 		b.importGraph[pkg] = map[string]struct{}{} | ||||
| 	} | ||||
| 	for _, im := range p.Imports { | ||||
| 		importedPath := strings.Trim(im.Path.Value, `"`) | ||||
| 		b.importGraph[pkg][importedPath] = struct{}{} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // AddDir adds an entire directory, scanning it for go files. 'dir' should have | ||||
| // a single go package in it. GOPATH, GOROOT, and the location of your go | ||||
| // binary (`which go`) will all be searched if dir doesn't literally resolve. | ||||
| func (b *Builder) AddDir(dir string) error { | ||||
| 	return b.addDir(dir, true) | ||||
| } | ||||
|  | ||||
| // The implementation of AddDir. A flag indicates whether this directory was | ||||
| // user-requested or just from following the import graph. | ||||
| func (b *Builder) addDir(dir string, userRequested bool) error { | ||||
| 	pkg, err := b.buildPackage(dir) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	dir = pkg.Dir | ||||
| 	// Check in case this package was added (maybe dir was not canonical) | ||||
| 	if _, alreadyAdded := b.parsed[dir]; alreadyAdded { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	for _, n := range pkg.GoFiles { | ||||
| 		if !strings.HasSuffix(n, ".go") { | ||||
| 			continue | ||||
| 		} | ||||
| 		absPath := filepath.Join(pkg.Dir, n) | ||||
| 		pkgPath := filepath.Join(pkg.ImportPath, n) | ||||
| 		data, err := ioutil.ReadFile(absPath) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("while loading %q: %v", absPath, err) | ||||
| 		} | ||||
| 		err = b.addFile(pkgPath, data, userRequested) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("while parsing %q: %v", pkgPath, err) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // importer is a function that will be called by the type check package when it | ||||
| // needs to import a go package. 'path' is the import path. go1.5 changes the | ||||
| // interface, and importAdapter below implements the new interface in terms of | ||||
| // the old one. | ||||
| func (b *Builder) importer(imports map[string]*tc.Package, path string) (*tc.Package, error) { | ||||
| 	if pkg, ok := imports[path]; ok { | ||||
| 		return pkg, nil | ||||
| 	} | ||||
| 	ignoreError := false | ||||
| 	if _, ours := b.parsed[path]; !ours { | ||||
| 		// Ignore errors in paths that we're importing solely because | ||||
| 		// they're referenced by other packages. | ||||
| 		ignoreError = true | ||||
| 		// fmt.Printf("trying to import %q\n", path) | ||||
| 		if err := b.addDir(path, false); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	pkg, err := b.typeCheckPackage(path) | ||||
| 	if err != nil { | ||||
| 		if ignoreError && pkg != nil { | ||||
| 			fmt.Printf("type checking encountered some errors in %q, but ignoring.\n", path) | ||||
| 		} else { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	imports[path] = pkg | ||||
| 	return pkg, nil | ||||
| } | ||||
|  | ||||
| type importAdapter struct { | ||||
| 	b *Builder | ||||
| } | ||||
|  | ||||
| func (a importAdapter) Import(path string) (*tc.Package, error) { | ||||
| 	return a.b.importer(a.b.pkgs, path) | ||||
| } | ||||
|  | ||||
| // typeCheckPackage will attempt to return the package even if there are some | ||||
| // errors, so you may check whether the package is nil or not even if you get | ||||
| // an error. | ||||
| func (b *Builder) typeCheckPackage(id string) (*tc.Package, error) { | ||||
| 	if pkg, ok := b.pkgs[id]; ok { | ||||
| 		if pkg != nil { | ||||
| 			return pkg, nil | ||||
| 		} | ||||
| 		// We store a nil right before starting work on a package. So | ||||
| 		// if we get here and it's present and nil, that means there's | ||||
| 		// another invocation of this function on the call stack | ||||
| 		// already processing this package. | ||||
| 		return nil, fmt.Errorf("circular dependency for %q", id) | ||||
| 	} | ||||
| 	files, ok := b.parsed[id] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("No files for pkg %q: %#v", id, b.parsed) | ||||
| 	} | ||||
| 	b.pkgs[id] = nil | ||||
| 	c := tc.Config{ | ||||
| 		IgnoreFuncBodies: true, | ||||
| 		// Note that importAdater can call b.import which calls this | ||||
| 		// method. So there can't be cycles in the import graph. | ||||
| 		Importer: importAdapter{b}, | ||||
| 		Error: func(err error) { | ||||
| 			fmt.Printf("type checker error: %v\n", err) | ||||
| 		}, | ||||
| 	} | ||||
| 	pkg, err := c.Check(id, b.fset, files, nil) | ||||
| 	b.pkgs[id] = pkg // record the result whether or not there was an error | ||||
| 	return pkg, err | ||||
| } | ||||
|  | ||||
| func (b *Builder) makePackages() error { | ||||
| 	b.pkgs = map[string]*tc.Package{} | ||||
| 	for id := range b.parsed { | ||||
| 		// We have to check here even though we made a new one above, | ||||
| 		// because typeCheckPackage follows the import graph, which may | ||||
| 		// cause a package to be filled before we get to it in this | ||||
| 		// loop. | ||||
| 		if _, done := b.pkgs[id]; done { | ||||
| 			continue | ||||
| 		} | ||||
| 		if _, err := b.typeCheckPackage(id); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // FindTypes finalizes the package imports, and searches through all the | ||||
| // packages for types. | ||||
| func (b *Builder) FindTypes() (types.Universe, error) { | ||||
| 	if err := b.makePackages(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	u := types.Universe{} | ||||
|  | ||||
| 	for pkgName, pkg := range b.pkgs { | ||||
| 		if !b.userRequested[pkgName] { | ||||
| 			// Since walkType is recursive, all types that the | ||||
| 			// packages they asked for depend on will be included. | ||||
| 			// But we don't need to include all types in all | ||||
| 			// *packages* they depend on. | ||||
| 			continue | ||||
| 		} | ||||
| 		s := pkg.Scope() | ||||
| 		for _, n := range s.Names() { | ||||
| 			obj := s.Lookup(n) | ||||
| 			tn, ok := obj.(*tc.TypeName) | ||||
| 			if !ok { | ||||
| 				continue | ||||
| 			} | ||||
| 			t := b.walkType(u, nil, tn.Type()) | ||||
| 			t.CommentLines = b.priorCommentLines(obj.Pos()) | ||||
| 		} | ||||
| 		for p := range b.importGraph[pkgName] { | ||||
| 			u.AddImports(pkgName, p) | ||||
| 		} | ||||
| 	} | ||||
| 	return u, nil | ||||
| } | ||||
|  | ||||
| // if there's a comment on the line before pos, return its text, otherwise "". | ||||
| func (b *Builder) priorCommentLines(pos token.Pos) string { | ||||
| 	position := b.fset.Position(pos) | ||||
| 	key := fileLine{position.Filename, position.Line - 1} | ||||
| 	if c, ok := b.endLineToCommentGroup[key]; ok { | ||||
| 		return c.Text() | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func tcNameToName(in string) types.Name { | ||||
| 	// Detect anonymous type names. (These may have '.' characters because | ||||
| 	// embedded types may have packages, so we detect them specially.) | ||||
| 	if strings.HasPrefix(in, "struct{") || | ||||
| 		strings.HasPrefix(in, "*") || | ||||
| 		strings.HasPrefix(in, "map[") || | ||||
| 		strings.HasPrefix(in, "[") { | ||||
| 		return types.Name{Name: in} | ||||
| 	} | ||||
|  | ||||
| 	// Otherwise, if there are '.' characters present, the name has a | ||||
| 	// package path in front. | ||||
| 	nameParts := strings.Split(in, ".") | ||||
| 	name := types.Name{Name: in} | ||||
| 	if n := len(nameParts); n >= 2 { | ||||
| 		// The final "." is the name of the type--previous ones must | ||||
| 		// have been in the package path. | ||||
| 		name.Package, name.Name = strings.Join(nameParts[:n-1], "."), nameParts[n-1] | ||||
| 	} | ||||
| 	return name | ||||
| } | ||||
|  | ||||
| func (b *Builder) convertSignature(u types.Universe, t *tc.Signature) *types.Signature { | ||||
| 	signature := &types.Signature{} | ||||
| 	for i := 0; i < t.Params().Len(); i++ { | ||||
| 		signature.Parameters = append(signature.Parameters, b.walkType(u, nil, t.Params().At(i).Type())) | ||||
| 	} | ||||
| 	for i := 0; i < t.Results().Len(); i++ { | ||||
| 		signature.Results = append(signature.Results, b.walkType(u, nil, t.Results().At(i).Type())) | ||||
| 	} | ||||
| 	if r := t.Recv(); r != nil { | ||||
| 		signature.Receiver = b.walkType(u, nil, r.Type()) | ||||
| 	} | ||||
| 	signature.Variadic = t.Variadic() | ||||
| 	return signature | ||||
| } | ||||
|  | ||||
| // walkType adds the type, and any necessary child types. | ||||
| func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *types.Type { | ||||
| 	// Most of the cases are underlying types of the named type. | ||||
| 	name := tcNameToName(in.String()) | ||||
| 	if useName != nil { | ||||
| 		name = *useName | ||||
| 	} | ||||
|  | ||||
| 	switch t := in.(type) { | ||||
| 	case *tc.Struct: | ||||
| 		out := u.Get(name) | ||||
| 		if out.Kind != types.Unknown { | ||||
| 			return out | ||||
| 		} | ||||
| 		out.Kind = types.Struct | ||||
| 		for i := 0; i < t.NumFields(); i++ { | ||||
| 			f := t.Field(i) | ||||
| 			m := types.Member{ | ||||
| 				Name:         f.Name(), | ||||
| 				Embedded:     f.Anonymous(), | ||||
| 				Tags:         t.Tag(i), | ||||
| 				Type:         b.walkType(u, nil, f.Type()), | ||||
| 				CommentLines: b.priorCommentLines(f.Pos()), | ||||
| 			} | ||||
| 			out.Members = append(out.Members, m) | ||||
| 		} | ||||
| 		return out | ||||
| 	case *tc.Map: | ||||
| 		out := u.Get(name) | ||||
| 		if out.Kind != types.Unknown { | ||||
| 			return out | ||||
| 		} | ||||
| 		out.Kind = types.Map | ||||
| 		out.Elem = b.walkType(u, nil, t.Elem()) | ||||
| 		out.Key = b.walkType(u, nil, t.Key()) | ||||
| 		return out | ||||
| 	case *tc.Pointer: | ||||
| 		out := u.Get(name) | ||||
| 		if out.Kind != types.Unknown { | ||||
| 			return out | ||||
| 		} | ||||
| 		out.Kind = types.Pointer | ||||
| 		out.Elem = b.walkType(u, nil, t.Elem()) | ||||
| 		return out | ||||
| 	case *tc.Slice: | ||||
| 		out := u.Get(name) | ||||
| 		if out.Kind != types.Unknown { | ||||
| 			return out | ||||
| 		} | ||||
| 		out.Kind = types.Slice | ||||
| 		out.Elem = b.walkType(u, nil, t.Elem()) | ||||
| 		return out | ||||
| 	case *tc.Array: | ||||
| 		out := u.Get(name) | ||||
| 		if out.Kind != types.Unknown { | ||||
| 			return out | ||||
| 		} | ||||
| 		out.Kind = types.Array | ||||
| 		out.Elem = b.walkType(u, nil, t.Elem()) | ||||
| 		// TODO: need to store array length, otherwise raw type name | ||||
| 		// cannot be properly written. | ||||
| 		return out | ||||
| 	case *tc.Chan: | ||||
| 		out := u.Get(name) | ||||
| 		if out.Kind != types.Unknown { | ||||
| 			return out | ||||
| 		} | ||||
| 		out.Kind = types.Chan | ||||
| 		out.Elem = b.walkType(u, nil, t.Elem()) | ||||
| 		// TODO: need to store direction, otherwise raw type name | ||||
| 		// cannot be properly written. | ||||
| 		return out | ||||
| 	case *tc.Basic: | ||||
| 		out := u.Get(types.Name{ | ||||
| 			Package: "", | ||||
| 			Name:    t.Name(), | ||||
| 		}) | ||||
| 		if out.Kind != types.Unknown { | ||||
| 			return out | ||||
| 		} | ||||
| 		out.Kind = types.Unsupported | ||||
| 		return out | ||||
| 	case *tc.Signature: | ||||
| 		out := u.Get(name) | ||||
| 		if out.Kind != types.Unknown { | ||||
| 			return out | ||||
| 		} | ||||
| 		out.Kind = types.Func | ||||
| 		out.Signature = b.convertSignature(u, t) | ||||
| 		return out | ||||
| 	case *tc.Interface: | ||||
| 		out := u.Get(name) | ||||
| 		if out.Kind != types.Unknown { | ||||
| 			return out | ||||
| 		} | ||||
| 		out.Kind = types.Interface | ||||
| 		t.Complete() | ||||
| 		for i := 0; i < t.NumMethods(); i++ { | ||||
| 			out.Methods = append(out.Methods, b.walkType(u, nil, t.Method(i).Type())) | ||||
| 		} | ||||
| 		return out | ||||
| 	case *tc.Named: | ||||
| 		switch t.Underlying().(type) { | ||||
| 		case *tc.Named, *tc.Basic: | ||||
| 			name := tcNameToName(t.String()) | ||||
| 			out := u.Get(name) | ||||
| 			if out.Kind != types.Unknown { | ||||
| 				return out | ||||
| 			} | ||||
| 			out.Kind = types.Alias | ||||
| 			out.Underlying = b.walkType(u, nil, t.Underlying()) | ||||
| 			return out | ||||
| 		default: | ||||
| 			// tc package makes everything "named" with an | ||||
| 			// underlying anonymous type--we remove that annoying | ||||
| 			// "feature" for users. This flattens those types | ||||
| 			// together. | ||||
| 			name := tcNameToName(t.String()) | ||||
| 			if out := u.Get(name); out.Kind != types.Unknown { | ||||
| 				return out // short circuit if we've already made this. | ||||
| 			} | ||||
| 			out := b.walkType(u, &name, t.Underlying()) | ||||
| 			if len(out.Methods) == 0 { | ||||
| 				// If the underlying type didn't already add | ||||
| 				// methods, add them. (Interface types will | ||||
| 				// have already added methods.) | ||||
| 				for i := 0; i < t.NumMethods(); i++ { | ||||
| 					out.Methods = append(out.Methods, b.walkType(u, nil, t.Method(i).Type())) | ||||
| 				} | ||||
| 			} | ||||
| 			return out | ||||
| 		} | ||||
| 	default: | ||||
| 		out := u.Get(name) | ||||
| 		if out.Kind != types.Unknown { | ||||
| 			return out | ||||
| 		} | ||||
| 		out.Kind = types.Unsupported | ||||
| 		fmt.Printf("Making unsupported type entry %q for: %#v\n", out, t) | ||||
| 		return out | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										343
									
								
								cmd/libs/go2idl/parser/parse_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								cmd/libs/go2idl/parser/parse_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,343 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package parser_test | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| 	"text/template" | ||||
|  | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/namer" | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/parser" | ||||
| 	"k8s.io/kubernetes/cmd/libs/go2idl/types" | ||||
| ) | ||||
|  | ||||
| func construct(t *testing.T, files map[string]string, testNamer namer.Namer) (*parser.Builder, types.Universe, []*types.Type) { | ||||
| 	b := parser.New() | ||||
| 	for name, src := range files { | ||||
| 		if err := b.AddFile(name, []byte(src)); err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
| 	} | ||||
| 	u, err := b.FindTypes() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	orderer := namer.Orderer{testNamer} | ||||
| 	o := orderer.Order(u) | ||||
| 	return b, u, o | ||||
| } | ||||
|  | ||||
| func TestBuilder(t *testing.T) { | ||||
| 	var testFiles = map[string]string{ | ||||
| 		"base/foo/proto/foo.go": ` | ||||
| package foo | ||||
|  | ||||
| import ( | ||||
| 	"base/common/proto" | ||||
| ) | ||||
|  | ||||
| type Blah struct { | ||||
| 	common.Object | ||||
| 	Count int64 | ||||
| 	Frobbers map[string]*Frobber | ||||
| 	Baz []Object | ||||
| 	Nickname *string | ||||
| 	NumberIsAFavorite map[int]bool | ||||
| } | ||||
|  | ||||
| type Frobber struct { | ||||
| 	Name string | ||||
| 	Amount int64 | ||||
| } | ||||
|  | ||||
| type Object struct { | ||||
| 	common.Object | ||||
| } | ||||
|  | ||||
| `, | ||||
| 		"base/common/proto/common.go": ` | ||||
| package common | ||||
|  | ||||
| type Object struct { | ||||
| 	ID int64 | ||||
| } | ||||
| `, | ||||
| 	} | ||||
|  | ||||
| 	var tmplText = ` | ||||
| package o | ||||
| {{define "Struct"}}type {{Name .}} interface { {{range $m := .Members}}{{$n := Name $m.Type}} | ||||
| 	{{if $m.Embedded}}{{$n}}{{else}}{{$m.Name}}() {{$n}}{{if $m.Type.Elem}}{{else}} | ||||
| 	Set{{$m.Name}}({{$n}}){{end}}{{end}}{{end}} | ||||
| } | ||||
|  | ||||
| {{end}} | ||||
| {{range $t := .}}{{if eq $t.Kind "Struct"}}{{template "Struct" $t}}{{end}}{{end}}` | ||||
|  | ||||
| 	var expect = ` | ||||
| package o | ||||
|  | ||||
| type CommonObject interface {  | ||||
| 	ID() Int64 | ||||
| 	SetID(Int64) | ||||
| } | ||||
|  | ||||
| type FooBlah interface {  | ||||
| 	CommonObject | ||||
| 	Count() Int64 | ||||
| 	SetCount(Int64) | ||||
| 	Frobbers() MapStringToPointerFooFrobber | ||||
| 	Baz() SliceFooObject | ||||
| 	Nickname() PointerString | ||||
| 	NumberIsAFavorite() MapIntToBool | ||||
| } | ||||
|  | ||||
| type FooFrobber interface {  | ||||
| 	Name() String | ||||
| 	SetName(String) | ||||
| 	Amount() Int64 | ||||
| 	SetAmount(Int64) | ||||
| } | ||||
|  | ||||
| type FooObject interface {  | ||||
| 	CommonObject | ||||
| } | ||||
|  | ||||
| ` | ||||
| 	testNamer := namer.NewPublicNamer(1, "proto") | ||||
| 	_, u, o := construct(t, testFiles, testNamer) | ||||
| 	t.Logf("\n%v\n\n", o) | ||||
| 	tmpl := template.Must( | ||||
| 		template.New(""). | ||||
| 			Funcs( | ||||
| 			map[string]interface{}{ | ||||
| 				"Name": testNamer.Name, | ||||
| 			}). | ||||
| 			Parse(tmplText), | ||||
| 	) | ||||
| 	buf := &bytes.Buffer{} | ||||
| 	tmpl.Execute(buf, o) | ||||
| 	if e, a := expect, buf.String(); e != a { | ||||
| 		t.Errorf("Wanted, got:\n%v\n-----\n%v\n", e, a) | ||||
| 	} | ||||
|  | ||||
| 	if p := u.Package("base/foo/proto"); !p.HasImport("base/common/proto") { | ||||
| 		t.Errorf("Unexpected lack of import line: %#s", p.Imports) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestStructParse(t *testing.T) { | ||||
| 	var structTest = map[string]string{ | ||||
| 		"base/foo/proto/foo.go": ` | ||||
| package foo | ||||
|  | ||||
| // Blah is a test. | ||||
| // A test, I tell you. | ||||
| type Blah struct { | ||||
| 	// A is the first field. | ||||
| 	A int64 ` + "`" + `json:"a"` + "`" + ` | ||||
|  | ||||
| 	// B is the second field. | ||||
| 	// Multiline comments work. | ||||
| 	B string ` + "`" + `json:"b"` + "`" + ` | ||||
| } | ||||
| `, | ||||
| 	} | ||||
|  | ||||
| 	_, u, o := construct(t, structTest, namer.NewPublicNamer(0)) | ||||
| 	t.Logf("%#v", o) | ||||
| 	blahT := u.Get(types.Name{"base/foo/proto", "Blah"}) | ||||
| 	if blahT == nil { | ||||
| 		t.Fatal("type not found") | ||||
| 	} | ||||
| 	if e, a := types.Struct, blahT.Kind; e != a { | ||||
| 		t.Errorf("struct kind wrong, wanted %v, got %v", e, a) | ||||
| 	} | ||||
| 	if e, a := "Blah is a test.\nA test, I tell you.\n", blahT.CommentLines; e != a { | ||||
| 		t.Errorf("struct comment wrong, wanted %v, got %v", e, a) | ||||
| 	} | ||||
| 	m := types.Member{ | ||||
| 		Name:         "B", | ||||
| 		Embedded:     false, | ||||
| 		CommentLines: "B is the second field.\nMultiline comments work.\n", | ||||
| 		Tags:         `json:"b"`, | ||||
| 		Type:         types.String, | ||||
| 	} | ||||
| 	if e, a := m, blahT.Members[1]; !reflect.DeepEqual(e, a) { | ||||
| 		t.Errorf("wanted, got:\n%#v\n%#v", e, a) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestTypeKindParse(t *testing.T) { | ||||
| 	var testFiles = map[string]string{ | ||||
| 		"a/foo.go": "package a\ntype Test string\n", | ||||
| 		"b/foo.go": "package b\ntype Test map[int]string\n", | ||||
| 		"c/foo.go": "package c\ntype Test []string\n", | ||||
| 		"d/foo.go": "package d\ntype Test struct{a int; b struct{a int}; c map[int]string; d *string}\n", | ||||
| 		"e/foo.go": "package e\ntype Test *string\n", | ||||
| 		"f/foo.go": ` | ||||
| package f | ||||
| import ( | ||||
| 	"a" | ||||
| 	"b" | ||||
| ) | ||||
| type Test []a.Test | ||||
| type Test2 *a.Test | ||||
| type Test3 map[a.Test]b.Test | ||||
| type Test4 struct { | ||||
| 	a struct {a a.Test; b b.Test} | ||||
| 	b map[a.Test]b.Test | ||||
| 	c *a.Test | ||||
| 	d []a.Test | ||||
| 	e []string | ||||
| } | ||||
| `, | ||||
| 		"g/foo.go": ` | ||||
| package g | ||||
| type Test func(a, b string) (c, d string) | ||||
| func (t Test) Method(a, b string) (c, d string) { return t(a, b) } | ||||
| type Interface interface{Method(a, b string) (c, d string)} | ||||
| `, | ||||
| 	} | ||||
|  | ||||
| 	// Check that the right types are found, and the namers give the expected names. | ||||
|  | ||||
| 	assertions := []struct { | ||||
| 		Package, Name string | ||||
| 		k             types.Kind | ||||
| 		names         []string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			Package: "a", Name: "Test", k: types.Alias, | ||||
| 			names: []string{"Test", "ATest", "test", "aTest", "a.Test"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "b", Name: "Test", k: types.Map, | ||||
| 			names: []string{"Test", "BTest", "test", "bTest", "b.Test"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "c", Name: "Test", k: types.Slice, | ||||
| 			names: []string{"Test", "CTest", "test", "cTest", "c.Test"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "d", Name: "Test", k: types.Struct, | ||||
| 			names: []string{"Test", "DTest", "test", "dTest", "d.Test"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "e", Name: "Test", k: types.Pointer, | ||||
| 			names: []string{"Test", "ETest", "test", "eTest", "e.Test"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "f", Name: "Test", k: types.Slice, | ||||
| 			names: []string{"Test", "FTest", "test", "fTest", "f.Test"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "g", Name: "Test", k: types.Func, | ||||
| 			names: []string{"Test", "GTest", "test", "gTest", "g.Test"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "g", Name: "Interface", k: types.Interface, | ||||
| 			names: []string{"Interface", "GInterface", "interface", "gInterface", "g.Interface"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "", Name: "string", k: types.Builtin, | ||||
| 			names: []string{"String", "String", "string", "string", "string"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "", Name: "int", k: types.Builtin, | ||||
| 			names: []string{"Int", "Int", "int", "int", "int"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "", Name: "struct{a int}", k: types.Struct, | ||||
| 			names: []string{"StructInt", "StructInt", "structInt", "structInt", "struct{a int}"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "", Name: "struct{a a.Test; b b.Test}", k: types.Struct, | ||||
| 			names: []string{"StructTestTest", "StructATestBTest", "structTestTest", "structATestBTest", "struct{a a.Test; b b.Test}"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "", Name: "map[int]string", k: types.Map, | ||||
| 			names: []string{"MapIntToString", "MapIntToString", "mapIntToString", "mapIntToString", "map[int]string"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "", Name: "map[a.Test]b.Test", k: types.Map, | ||||
| 			names: []string{"MapTestToTest", "MapATestToBTest", "mapTestToTest", "mapATestToBTest", "map[a.Test]b.Test"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "", Name: "[]string", k: types.Slice, | ||||
| 			names: []string{"SliceString", "SliceString", "sliceString", "sliceString", "[]string"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "", Name: "[]a.Test", k: types.Slice, | ||||
| 			names: []string{"SliceTest", "SliceATest", "sliceTest", "sliceATest", "[]a.Test"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "", Name: "*string", k: types.Pointer, | ||||
| 			names: []string{"PointerString", "PointerString", "pointerString", "pointerString", "*string"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Package: "", Name: "*a.Test", k: types.Pointer, | ||||
| 			names: []string{"PointerTest", "PointerATest", "pointerTest", "pointerATest", "*a.Test"}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	namers := []namer.Namer{ | ||||
| 		namer.NewPublicNamer(0), | ||||
| 		namer.NewPublicNamer(1), | ||||
| 		namer.NewPrivateNamer(0), | ||||
| 		namer.NewPrivateNamer(1), | ||||
| 		namer.NewRawNamer(nil), | ||||
| 	} | ||||
|  | ||||
| 	for nameIndex, namer := range namers { | ||||
| 		_, u, _ := construct(t, testFiles, namer) | ||||
| 		t.Logf("Found types:\n") | ||||
| 		for pkgName, pkg := range u { | ||||
| 			for typeName, cur := range pkg.Types { | ||||
| 				t.Logf("%q-%q: %s %s", pkgName, typeName, cur.Name, cur.Kind) | ||||
| 			} | ||||
| 		} | ||||
| 		t.Logf("\n\n") | ||||
|  | ||||
| 		for _, item := range assertions { | ||||
| 			n := types.Name{Package: item.Package, Name: item.Name} | ||||
| 			thisType := u.Get(n) | ||||
| 			if thisType == nil { | ||||
| 				t.Errorf("type %s not found", n) | ||||
| 				continue | ||||
| 			} | ||||
| 			if e, a := item.k, thisType.Kind; e != a { | ||||
| 				t.Errorf("%v-%s: type kind wrong, wanted %v, got %v (%#v)", nameIndex, n, e, a, thisType) | ||||
| 			} | ||||
| 			if e, a := item.names[nameIndex], namer.Name(thisType); e != a { | ||||
| 				t.Errorf("%v-%s: Expected %q, got %q", nameIndex, n, e, a) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Also do some one-off checks | ||||
| 		gtest := u.Get(types.Name{"g", "Test"}) | ||||
| 		if e, a := 1, len(gtest.Methods); e != a { | ||||
| 			t.Errorf("expected %v but found %v methods: %#v", e, a, gtest) | ||||
| 		} | ||||
| 		iface := u.Get(types.Name{"g", "Interface"}) | ||||
| 		if e, a := 1, len(iface.Methods); e != a { | ||||
| 			t.Errorf("expected %v but found %v methods: %#v", e, a, iface) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										64
									
								
								cmd/libs/go2idl/types/comments.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								cmd/libs/go2idl/types/comments.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| // Package types contains go type information, packaged in a way that makes | ||||
| // auto-generation convenient, whether by template or straight go functions. | ||||
| package types | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // ExtractCommentTags parses comments for lines of the form: | ||||
| // | ||||
| //   'marker'+"key1=value1,key2=value2". | ||||
| // | ||||
| // Values are optional; 'true' is the default. If a key is set multiple times, | ||||
| // the last one wins. | ||||
| // | ||||
| // Example: if you pass "+" for 'marker', and the following two lines are in | ||||
| // the comments: | ||||
| //   +foo=value1,bar | ||||
| //   +foo=value2,baz="frobber" | ||||
| // Then this function will return: | ||||
| //   map[string]string{"foo":"value2", "bar": "true", "baz": "frobber"} | ||||
| // | ||||
| // TODO: Basically we need to define a standard way of giving instructions to | ||||
| // autogenerators in the comments of a type. This is a first iteration of that. | ||||
| // TODO: allow multiple values per key? | ||||
| func ExtractCommentTags(marker, allLines string) map[string]string { | ||||
| 	lines := strings.Split(allLines, "\n") | ||||
| 	out := map[string]string{} | ||||
| 	for _, line := range lines { | ||||
| 		line = strings.Trim(line, " ") | ||||
| 		if len(line) == 0 { | ||||
| 			continue | ||||
| 		} | ||||
| 		if !strings.HasPrefix(line, marker) { | ||||
| 			continue | ||||
| 		} | ||||
| 		pairs := strings.Split(line[len(marker):], ",") | ||||
| 		for _, p := range pairs { | ||||
| 			kv := strings.Split(p, "=") | ||||
| 			if len(kv) == 2 { | ||||
| 				out[kv[0]] = kv[1] | ||||
| 			} else if len(kv) == 1 { | ||||
| 				out[kv[0]] = "true" | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
							
								
								
									
										35
									
								
								cmd/libs/go2idl/types/comments_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								cmd/libs/go2idl/types/comments_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package types | ||||
|  | ||||
| import ( | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestExtractCommentTags(t *testing.T) { | ||||
| 	commentLines := ` | ||||
| Human comment that is ignored. | ||||
| +foo=value1,bar | ||||
| +foo=value2,baz=frobber | ||||
| ` | ||||
| 	a := ExtractCommentTags("+", commentLines) | ||||
| 	e := map[string]string{"foo": "value2", "bar": "true", "baz": "frobber"} | ||||
| 	if !reflect.DeepEqual(e, a) { | ||||
| 		t.Errorf("Wanted %#v, got %#v", e, a) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										19
									
								
								cmd/libs/go2idl/types/doc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								cmd/libs/go2idl/types/doc.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| // Package types contains go type information, packaged in a way that makes | ||||
| // auto-generation convenient, whether by template or straight go functions. | ||||
| package types | ||||
							
								
								
									
										57
									
								
								cmd/libs/go2idl/types/flatten.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								cmd/libs/go2idl/types/flatten.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package types | ||||
|  | ||||
| // FlattenMembers recursively takes any embedded members and puts them in the | ||||
| // top level, correctly hiding them if the top level hides them. There must not | ||||
| // be a cycle-- that implies infinite members. | ||||
| // | ||||
| // This is useful for e.g. computing all the valid keys in a json struct, | ||||
| // properly considering any configuration of embedded structs. | ||||
| func FlattenMembers(m []Member) []Member { | ||||
| 	embedded := []Member{} | ||||
| 	normal := []Member{} | ||||
| 	type nameInfo struct { | ||||
| 		top bool | ||||
| 		i   int | ||||
| 	} | ||||
| 	names := map[string]nameInfo{} | ||||
| 	for i := range m { | ||||
| 		if m[i].Embedded && m[i].Type.Kind == Struct { | ||||
| 			embedded = append(embedded, m[i]) | ||||
| 		} else { | ||||
| 			normal = append(normal, m[i]) | ||||
| 			names[m[i].Name] = nameInfo{true, len(normal) - 1} | ||||
| 		} | ||||
| 	} | ||||
| 	for i := range embedded { | ||||
| 		for _, e := range FlattenMembers(embedded[i].Type.Members) { | ||||
| 			if info, found := names[e.Name]; found { | ||||
| 				if info.top { | ||||
| 					continue | ||||
| 				} | ||||
| 				if n := normal[info.i]; n.Name == e.Name && n.Type == e.Type { | ||||
| 					continue | ||||
| 				} | ||||
| 				panic("conflicting members") | ||||
| 			} | ||||
| 			normal = append(normal, e) | ||||
| 			names[e.Name] = nameInfo{false, len(normal) - 1} | ||||
| 		} | ||||
| 	} | ||||
| 	return normal | ||||
| } | ||||
							
								
								
									
										68
									
								
								cmd/libs/go2idl/types/flatten_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								cmd/libs/go2idl/types/flatten_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package types | ||||
|  | ||||
| import ( | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestFlatten(t *testing.T) { | ||||
| 	mapType := &Type{ | ||||
| 		Name: Name{"", "map[string]string"}, | ||||
| 		Kind: Map, | ||||
| 		Key:  String, | ||||
| 		Elem: String, | ||||
| 	} | ||||
| 	m := []Member{ | ||||
| 		{ | ||||
| 			Name:     "Baz", | ||||
| 			Embedded: true, | ||||
| 			Type: &Type{ | ||||
| 				Name: Name{"pkg", "Baz"}, | ||||
| 				Kind: Struct, | ||||
| 				Members: []Member{ | ||||
| 					{Name: "Foo", Type: String}, | ||||
| 					{ | ||||
| 						Name:     "Qux", | ||||
| 						Embedded: true, | ||||
| 						Type: &Type{ | ||||
| 							Name:    Name{"pkg", "Qux"}, | ||||
| 							Kind:    Struct, | ||||
| 							Members: []Member{{Name: "Zot", Type: String}}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{Name: "Bar", Type: String}, | ||||
| 		{ | ||||
| 			Name:     "NotSureIfLegal", | ||||
| 			Embedded: true, | ||||
| 			Type:     mapType, | ||||
| 		}, | ||||
| 	} | ||||
| 	e := []Member{ | ||||
| 		{Name: "Bar", Type: String}, | ||||
| 		{Name: "NotSureIfLegal", Type: mapType, Embedded: true}, | ||||
| 		{Name: "Foo", Type: String}, | ||||
| 		{Name: "Zot", Type: String}, | ||||
| 	} | ||||
| 	if a := FlattenMembers(m); !reflect.DeepEqual(e, a) { | ||||
| 		t.Errorf("Expected \n%#v\n, got \n%#v\n", e, a) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										307
									
								
								cmd/libs/go2idl/types/types.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										307
									
								
								cmd/libs/go2idl/types/types.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,307 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package types | ||||
|  | ||||
| // A type name may have a package qualifier. | ||||
| type Name struct { | ||||
| 	// Empty if embedded or builtin. This is the package path. | ||||
| 	Package string | ||||
| 	// The type name. | ||||
| 	Name string | ||||
| } | ||||
|  | ||||
| // String returns the name formatted as a string. | ||||
| func (n Name) String() string { | ||||
| 	if n.Package == "" { | ||||
| 		return n.Name | ||||
| 	} | ||||
| 	return n.Package + "." + n.Name | ||||
| } | ||||
|  | ||||
| // The possible classes of types. | ||||
| type Kind string | ||||
|  | ||||
| const ( | ||||
| 	// Builtin is a primitive, like bool, string, int. | ||||
| 	Builtin Kind = "Builtin" | ||||
| 	Struct  Kind = "Struct" | ||||
| 	Map     Kind = "Map" | ||||
| 	Slice   Kind = "Slice" | ||||
| 	Pointer Kind = "Pointer" | ||||
|  | ||||
| 	// Alias is an alias of another type, e.g. in: | ||||
| 	//   type Foo string | ||||
| 	//   type Bar Foo | ||||
| 	// Bar is an alias of Foo. | ||||
| 	// | ||||
| 	// In the real go type system, Foo is a "Named" string; but to simplify | ||||
| 	// generation, this type system will just say that Foo *is* a builtin. | ||||
| 	// We then need "Alias" as a way for us to say that Bar *is* a Foo. | ||||
| 	Alias Kind = "Alias" | ||||
|  | ||||
| 	// Interface is any type that could have differing types at run time. | ||||
| 	Interface Kind = "Interface" | ||||
|  | ||||
| 	// The remaining types are included for completeness, but are not well | ||||
| 	// supported. | ||||
| 	Array       Kind = "Array" // Array is just like slice, but has a fixed length. | ||||
| 	Chan        Kind = "Chan" | ||||
| 	Func        Kind = "Func" | ||||
| 	Unknown     Kind = "" | ||||
| 	Unsupported Kind = "Unsupported" | ||||
| ) | ||||
|  | ||||
| // Package holds package-level information. | ||||
| // Fields are public, as everything in this package, to enable consumption by | ||||
| // templates (for example). But it is strongly encouraged for code to build by | ||||
| // using the provided functions. | ||||
| type Package struct { | ||||
| 	// Canonical name of this package-- its path. | ||||
| 	Path string | ||||
|  | ||||
| 	// Short name of this package; the name that appears in the | ||||
| 	// 'package x' line. | ||||
| 	Name string | ||||
|  | ||||
| 	// Types within this package, indexed by their name (*not* including | ||||
| 	// package name). | ||||
| 	Types map[string]*Type | ||||
|  | ||||
| 	// Packages imported by this package, indexed by (canonicalized) | ||||
| 	// package path. | ||||
| 	Imports map[string]*Package | ||||
| } | ||||
|  | ||||
| // Has returns true if the given name references a type known to this package. | ||||
| func (p *Package) Has(name string) bool { | ||||
| 	_, has := p.Types[name] | ||||
| 	return has | ||||
| } | ||||
|  | ||||
| // Get (or add) the given type | ||||
| func (p *Package) Get(typeName string) *Type { | ||||
| 	if t, ok := p.Types[typeName]; ok { | ||||
| 		return t | ||||
| 	} | ||||
| 	if p.Path == "" { | ||||
| 		// Import the standard builtin types! | ||||
| 		if t, ok := builtins.Types[typeName]; ok { | ||||
| 			p.Types[typeName] = t | ||||
| 			return t | ||||
| 		} | ||||
| 	} | ||||
| 	t := &Type{Name: Name{p.Path, typeName}} | ||||
| 	p.Types[typeName] = t | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| // HasImport returns true if p imports packageName. Package names include the | ||||
| // package directory. | ||||
| func (p *Package) HasImport(packageName string) bool { | ||||
| 	_, has := p.Imports[packageName] | ||||
| 	return has | ||||
| } | ||||
|  | ||||
| // Universe is a map of all packages. The key is the package name, but you | ||||
| // should use Get() or Package() instead of direct access. | ||||
| type Universe map[string]*Package | ||||
|  | ||||
| // Get returns the canonical type for the given fully-qualified name. Builtin | ||||
| // types will always be found, even if they haven't been explicitly added to | ||||
| // the map. If a non-existing type is requested, u will create (a marker for) | ||||
| // it. | ||||
| func (u Universe) Get(n Name) *Type { | ||||
| 	return u.Package(n.Package).Get(n.Name) | ||||
| } | ||||
|  | ||||
| // AddImports registers import lines for packageName. May be called multiple times. | ||||
| // You are responsible for canonicalizing all package paths. | ||||
| func (u Universe) AddImports(packagePath string, importPaths ...string) { | ||||
| 	p := u.Package(packagePath) | ||||
| 	for _, i := range importPaths { | ||||
| 		p.Imports[i] = u.Package(i) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Get (create if needed) the package. | ||||
| func (u Universe) Package(packagePath string) *Package { | ||||
| 	if p, ok := u[packagePath]; ok { | ||||
| 		return p | ||||
| 	} | ||||
| 	p := &Package{ | ||||
| 		Path:    packagePath, | ||||
| 		Types:   map[string]*Type{}, | ||||
| 		Imports: map[string]*Package{}, | ||||
| 	} | ||||
| 	u[packagePath] = p | ||||
| 	return p | ||||
| } | ||||
|  | ||||
| // Type represents a subset of possible go types. | ||||
| type Type struct { | ||||
| 	// There are two general categories of types, those explicitly named | ||||
| 	// and those anonymous. Named ones will have a non-empty package in the | ||||
| 	// name field. | ||||
| 	Name Name | ||||
|  | ||||
| 	// The general kind of this type. | ||||
| 	Kind Kind | ||||
|  | ||||
| 	// If there are comment lines immediately before the type definition, | ||||
| 	// they will be recorded here. | ||||
| 	CommentLines string | ||||
|  | ||||
| 	// If Kind == Struct | ||||
| 	Members []Member | ||||
|  | ||||
| 	// If Kind == Map, Slice, Pointer, or Chan | ||||
| 	Elem *Type | ||||
|  | ||||
| 	// If Kind == Map, this is the map's key type. | ||||
| 	Key *Type | ||||
|  | ||||
| 	// If Kind == Alias, this is the underlying type. | ||||
| 	Underlying *Type | ||||
|  | ||||
| 	// If Kind == Interface, this is the list of all required functions. | ||||
| 	// Otherwise, if this is a named type, this is the list of methods that | ||||
| 	// type has. (All elements will have Kind=="Func") | ||||
| 	Methods []*Type | ||||
|  | ||||
| 	// If Kind == func, this is the signature of the function. | ||||
| 	Signature *Signature | ||||
|  | ||||
| 	// TODO: Add: | ||||
| 	// * channel direction | ||||
| 	// * array length | ||||
| } | ||||
|  | ||||
| // String returns the name of the type. | ||||
| func (t *Type) String() string { | ||||
| 	return t.Name.String() | ||||
| } | ||||
|  | ||||
| // A single struct member | ||||
| type Member struct { | ||||
| 	// The name of the member. | ||||
| 	Name string | ||||
|  | ||||
| 	// If the member is embedded (anonymous) this will be true, and the | ||||
| 	// Name will be the type name. | ||||
| 	Embedded bool | ||||
|  | ||||
| 	// If there are comment lines immediately before the member in the type | ||||
| 	// definition, they will be recorded here. | ||||
| 	CommentLines string | ||||
|  | ||||
| 	// If there are tags along with this member, they will be saved here. | ||||
| 	Tags string | ||||
|  | ||||
| 	// The type of this member. | ||||
| 	Type *Type | ||||
| } | ||||
|  | ||||
| // String returns the name and type of the member. | ||||
| func (m Member) String() string { | ||||
| 	return m.Name + " " + m.Type.String() | ||||
| } | ||||
|  | ||||
| // Signature is a function's signature. | ||||
| type Signature struct { | ||||
| 	// TODO: store the parameter names, not just types. | ||||
|  | ||||
| 	// If a method of some type, this is the type it's a member of. | ||||
| 	Receiver   *Type | ||||
| 	Parameters []*Type | ||||
| 	Results    []*Type | ||||
|  | ||||
| 	// True if the last in parameter is of the form ...T. | ||||
| 	Variadic bool | ||||
|  | ||||
| 	// If there are comment lines immediately before this | ||||
| 	// signature/method/function declaration, they will be recorded here. | ||||
| 	CommentLines string | ||||
| } | ||||
|  | ||||
| // Built in types. | ||||
| var ( | ||||
| 	String = &Type{ | ||||
| 		Name: Name{Name: "string"}, | ||||
| 		Kind: Builtin, | ||||
| 	} | ||||
| 	Int64 = &Type{ | ||||
| 		Name: Name{Name: "int64"}, | ||||
| 		Kind: Builtin, | ||||
| 	} | ||||
| 	Int32 = &Type{ | ||||
| 		Name: Name{Name: "int32"}, | ||||
| 		Kind: Builtin, | ||||
| 	} | ||||
| 	Int16 = &Type{ | ||||
| 		Name: Name{Name: "int16"}, | ||||
| 		Kind: Builtin, | ||||
| 	} | ||||
| 	Int = &Type{ | ||||
| 		Name: Name{Name: "int"}, | ||||
| 		Kind: Builtin, | ||||
| 	} | ||||
| 	Uint64 = &Type{ | ||||
| 		Name: Name{Name: "uint64"}, | ||||
| 		Kind: Builtin, | ||||
| 	} | ||||
| 	Uint32 = &Type{ | ||||
| 		Name: Name{Name: "uint32"}, | ||||
| 		Kind: Builtin, | ||||
| 	} | ||||
| 	Uint16 = &Type{ | ||||
| 		Name: Name{Name: "uint16"}, | ||||
| 		Kind: Builtin, | ||||
| 	} | ||||
| 	Uint = &Type{ | ||||
| 		Name: Name{Name: "uint"}, | ||||
| 		Kind: Builtin, | ||||
| 	} | ||||
| 	Bool = &Type{ | ||||
| 		Name: Name{Name: "bool"}, | ||||
| 		Kind: Builtin, | ||||
| 	} | ||||
| 	Byte = &Type{ | ||||
| 		Name: Name{Name: "byte"}, | ||||
| 		Kind: Builtin, | ||||
| 	} | ||||
|  | ||||
| 	builtins = &Package{ | ||||
| 		Types: map[string]*Type{ | ||||
| 			"bool":   Bool, | ||||
| 			"string": String, | ||||
| 			"int":    Int, | ||||
| 			"int64":  Int64, | ||||
| 			"int32":  Int32, | ||||
| 			"int16":  Int16, | ||||
| 			"int8":   Byte, | ||||
| 			"uint":   Uint, | ||||
| 			"uint64": Uint64, | ||||
| 			"uint32": Uint32, | ||||
| 			"uint16": Uint16, | ||||
| 			"uint8":  Byte, | ||||
| 			"byte":   Byte, | ||||
| 		}, | ||||
| 		Imports: map[string]*Package{}, | ||||
| 		Path:    "", | ||||
| 		Name:    "", | ||||
| 	} | ||||
| ) | ||||
							
								
								
									
										47
									
								
								cmd/libs/go2idl/types/types_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								cmd/libs/go2idl/types/types_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors All rights reserved. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package types | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestGetBuiltin(t *testing.T) { | ||||
| 	u := Universe{} | ||||
| 	if builtinPkg := u.Package(""); builtinPkg.Has("string") { | ||||
| 		t.Errorf("Expected builtin package to not have builtins until they're asked for explicitly. %#v", builtinPkg) | ||||
| 	} | ||||
| 	s := u.Get(Name{"", "string"}) | ||||
| 	if s != String { | ||||
| 		t.Errorf("Expected canonical string type.") | ||||
| 	} | ||||
| 	if builtinPkg := u.Package(""); !builtinPkg.Has("string") { | ||||
| 		t.Errorf("Expected builtin package to exist and have builtins by default. %#v", builtinPkg) | ||||
| 	} | ||||
| 	if builtinPkg := u.Package(""); len(builtinPkg.Types) != 1 { | ||||
| 		t.Errorf("Expected builtin package to not have builtins until they're asked for explicitly. %#v", builtinPkg) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestGetMarker(t *testing.T) { | ||||
| 	u := Universe{} | ||||
| 	n := Name{"path/to/package", "Foo"} | ||||
| 	f := u.Get(n) | ||||
| 	if f == nil || f.Name != n { | ||||
| 		t.Errorf("Expected marker type.") | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										15
									
								
								third_party/golang/go/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								third_party/golang/go/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| # Vendored copy of go1.5.1's standard library's go/... packages. | ||||
|  | ||||
| Q: Why did you do this awful vendoring? | ||||
|  | ||||
| A: We need to build under go 1.3 and go 1.4 (soon to be go 1.4 and go 1.5.1). A | ||||
| version of the go/types package existed for go 1.4, but it does not have the | ||||
| same interface as the go 1.5 package, and @lavalamp had much better luck with | ||||
| the 1.5.1 package anyway. | ||||
|  | ||||
| We will get rid of this as soon as there's a more standard way to do this, or | ||||
| when we roll over to supporting go 1.5 and go 1.6. | ||||
|  | ||||
| Note that the packages here were not very happy about being transplated like | ||||
| this and if you do a diff you will see the changes made to get everything to | ||||
| compile. | ||||
							
								
								
									
										999
									
								
								third_party/golang/go/ast/ast.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										999
									
								
								third_party/golang/go/ast/ast.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,999 @@ | ||||
| // Copyright 2009 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. | ||||
|  | ||||
| // Package ast declares the types used to represent syntax trees for Go | ||||
| // packages. | ||||
| // | ||||
| package ast | ||||
|  | ||||
| import ( | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Interfaces | ||||
| // | ||||
| // There are 3 main classes of nodes: Expressions and type nodes, | ||||
| // statement nodes, and declaration nodes. The node names usually | ||||
| // match the corresponding Go spec production names to which they | ||||
| // correspond. The node fields correspond to the individual parts | ||||
| // of the respective productions. | ||||
| // | ||||
| // All nodes contain position information marking the beginning of | ||||
| // the corresponding source text segment; it is accessible via the | ||||
| // Pos accessor method. Nodes may contain additional position info | ||||
| // for language constructs where comments may be found between parts | ||||
| // of the construct (typically any larger, parenthesized subpart). | ||||
| // That position information is needed to properly position comments | ||||
| // when printing the construct. | ||||
|  | ||||
| // All node types implement the Node interface. | ||||
| type Node interface { | ||||
| 	Pos() token.Pos // position of first character belonging to the node | ||||
| 	End() token.Pos // position of first character immediately after the node | ||||
| } | ||||
|  | ||||
| // All expression nodes implement the Expr interface. | ||||
| type Expr interface { | ||||
| 	Node | ||||
| 	exprNode() | ||||
| } | ||||
|  | ||||
| // All statement nodes implement the Stmt interface. | ||||
| type Stmt interface { | ||||
| 	Node | ||||
| 	stmtNode() | ||||
| } | ||||
|  | ||||
| // All declaration nodes implement the Decl interface. | ||||
| type Decl interface { | ||||
| 	Node | ||||
| 	declNode() | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Comments | ||||
|  | ||||
| // A Comment node represents a single //-style or /*-style comment. | ||||
| type Comment struct { | ||||
| 	Slash token.Pos // position of "/" starting the comment | ||||
| 	Text  string    // comment text (excluding '\n' for //-style comments) | ||||
| } | ||||
|  | ||||
| func (c *Comment) Pos() token.Pos { return c.Slash } | ||||
| func (c *Comment) End() token.Pos { return token.Pos(int(c.Slash) + len(c.Text)) } | ||||
|  | ||||
| // A CommentGroup represents a sequence of comments | ||||
| // with no other tokens and no empty lines between. | ||||
| // | ||||
| type CommentGroup struct { | ||||
| 	List []*Comment // len(List) > 0 | ||||
| } | ||||
|  | ||||
| func (g *CommentGroup) Pos() token.Pos { return g.List[0].Pos() } | ||||
| func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() } | ||||
|  | ||||
| func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' } | ||||
|  | ||||
| func stripTrailingWhitespace(s string) string { | ||||
| 	i := len(s) | ||||
| 	for i > 0 && isWhitespace(s[i-1]) { | ||||
| 		i-- | ||||
| 	} | ||||
| 	return s[0:i] | ||||
| } | ||||
|  | ||||
| // Text returns the text of the comment. | ||||
| // Comment markers (//, /*, and */), the first space of a line comment, and | ||||
| // leading and trailing empty lines are removed. Multiple empty lines are | ||||
| // reduced to one, and trailing space on lines is trimmed. Unless the result | ||||
| // is empty, it is newline-terminated. | ||||
| // | ||||
| func (g *CommentGroup) Text() string { | ||||
| 	if g == nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 	comments := make([]string, len(g.List)) | ||||
| 	for i, c := range g.List { | ||||
| 		comments[i] = string(c.Text) | ||||
| 	} | ||||
|  | ||||
| 	lines := make([]string, 0, 10) // most comments are less than 10 lines | ||||
| 	for _, c := range comments { | ||||
| 		// Remove comment markers. | ||||
| 		// The parser has given us exactly the comment text. | ||||
| 		switch c[1] { | ||||
| 		case '/': | ||||
| 			//-style comment (no newline at the end) | ||||
| 			c = c[2:] | ||||
| 			// strip first space - required for Example tests | ||||
| 			if len(c) > 0 && c[0] == ' ' { | ||||
| 				c = c[1:] | ||||
| 			} | ||||
| 		case '*': | ||||
| 			/*-style comment */ | ||||
| 			c = c[2 : len(c)-2] | ||||
| 		} | ||||
|  | ||||
| 		// Split on newlines. | ||||
| 		cl := strings.Split(c, "\n") | ||||
|  | ||||
| 		// Walk lines, stripping trailing white space and adding to list. | ||||
| 		for _, l := range cl { | ||||
| 			lines = append(lines, stripTrailingWhitespace(l)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Remove leading blank lines; convert runs of | ||||
| 	// interior blank lines to a single blank line. | ||||
| 	n := 0 | ||||
| 	for _, line := range lines { | ||||
| 		if line != "" || n > 0 && lines[n-1] != "" { | ||||
| 			lines[n] = line | ||||
| 			n++ | ||||
| 		} | ||||
| 	} | ||||
| 	lines = lines[0:n] | ||||
|  | ||||
| 	// Add final "" entry to get trailing newline from Join. | ||||
| 	if n > 0 && lines[n-1] != "" { | ||||
| 		lines = append(lines, "") | ||||
| 	} | ||||
|  | ||||
| 	return strings.Join(lines, "\n") | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Expressions and types | ||||
|  | ||||
| // A Field represents a Field declaration list in a struct type, | ||||
| // a method list in an interface type, or a parameter/result declaration | ||||
| // in a signature. | ||||
| // | ||||
| type Field struct { | ||||
| 	Doc     *CommentGroup // associated documentation; or nil | ||||
| 	Names   []*Ident      // field/method/parameter names; or nil if anonymous field | ||||
| 	Type    Expr          // field/method/parameter type | ||||
| 	Tag     *BasicLit     // field tag; or nil | ||||
| 	Comment *CommentGroup // line comments; or nil | ||||
| } | ||||
|  | ||||
| func (f *Field) Pos() token.Pos { | ||||
| 	if len(f.Names) > 0 { | ||||
| 		return f.Names[0].Pos() | ||||
| 	} | ||||
| 	return f.Type.Pos() | ||||
| } | ||||
|  | ||||
| func (f *Field) End() token.Pos { | ||||
| 	if f.Tag != nil { | ||||
| 		return f.Tag.End() | ||||
| 	} | ||||
| 	return f.Type.End() | ||||
| } | ||||
|  | ||||
| // A FieldList represents a list of Fields, enclosed by parentheses or braces. | ||||
| type FieldList struct { | ||||
| 	Opening token.Pos // position of opening parenthesis/brace, if any | ||||
| 	List    []*Field  // field list; or nil | ||||
| 	Closing token.Pos // position of closing parenthesis/brace, if any | ||||
| } | ||||
|  | ||||
| func (f *FieldList) Pos() token.Pos { | ||||
| 	if f.Opening.IsValid() { | ||||
| 		return f.Opening | ||||
| 	} | ||||
| 	// the list should not be empty in this case; | ||||
| 	// be conservative and guard against bad ASTs | ||||
| 	if len(f.List) > 0 { | ||||
| 		return f.List[0].Pos() | ||||
| 	} | ||||
| 	return token.NoPos | ||||
| } | ||||
|  | ||||
| func (f *FieldList) End() token.Pos { | ||||
| 	if f.Closing.IsValid() { | ||||
| 		return f.Closing + 1 | ||||
| 	} | ||||
| 	// the list should not be empty in this case; | ||||
| 	// be conservative and guard against bad ASTs | ||||
| 	if n := len(f.List); n > 0 { | ||||
| 		return f.List[n-1].End() | ||||
| 	} | ||||
| 	return token.NoPos | ||||
| } | ||||
|  | ||||
| // NumFields returns the number of (named and anonymous fields) in a FieldList. | ||||
| func (f *FieldList) NumFields() int { | ||||
| 	n := 0 | ||||
| 	if f != nil { | ||||
| 		for _, g := range f.List { | ||||
| 			m := len(g.Names) | ||||
| 			if m == 0 { | ||||
| 				m = 1 // anonymous field | ||||
| 			} | ||||
| 			n += m | ||||
| 		} | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| // An expression is represented by a tree consisting of one | ||||
| // or more of the following concrete expression nodes. | ||||
| // | ||||
| type ( | ||||
| 	// A BadExpr node is a placeholder for expressions containing | ||||
| 	// syntax errors for which no correct expression nodes can be | ||||
| 	// created. | ||||
| 	// | ||||
| 	BadExpr struct { | ||||
| 		From, To token.Pos // position range of bad expression | ||||
| 	} | ||||
|  | ||||
| 	// An Ident node represents an identifier. | ||||
| 	Ident struct { | ||||
| 		NamePos token.Pos // identifier position | ||||
| 		Name    string    // identifier name | ||||
| 		Obj     *Object   // denoted object; or nil | ||||
| 	} | ||||
|  | ||||
| 	// An Ellipsis node stands for the "..." type in a | ||||
| 	// parameter list or the "..." length in an array type. | ||||
| 	// | ||||
| 	Ellipsis struct { | ||||
| 		Ellipsis token.Pos // position of "..." | ||||
| 		Elt      Expr      // ellipsis element type (parameter lists only); or nil | ||||
| 	} | ||||
|  | ||||
| 	// A BasicLit node represents a literal of basic type. | ||||
| 	BasicLit struct { | ||||
| 		ValuePos token.Pos   // literal position | ||||
| 		Kind     token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING | ||||
| 		Value    string      // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o` | ||||
| 	} | ||||
|  | ||||
| 	// A FuncLit node represents a function literal. | ||||
| 	FuncLit struct { | ||||
| 		Type *FuncType  // function type | ||||
| 		Body *BlockStmt // function body | ||||
| 	} | ||||
|  | ||||
| 	// A CompositeLit node represents a composite literal. | ||||
| 	CompositeLit struct { | ||||
| 		Type   Expr      // literal type; or nil | ||||
| 		Lbrace token.Pos // position of "{" | ||||
| 		Elts   []Expr    // list of composite elements; or nil | ||||
| 		Rbrace token.Pos // position of "}" | ||||
| 	} | ||||
|  | ||||
| 	// A ParenExpr node represents a parenthesized expression. | ||||
| 	ParenExpr struct { | ||||
| 		Lparen token.Pos // position of "(" | ||||
| 		X      Expr      // parenthesized expression | ||||
| 		Rparen token.Pos // position of ")" | ||||
| 	} | ||||
|  | ||||
| 	// A SelectorExpr node represents an expression followed by a selector. | ||||
| 	SelectorExpr struct { | ||||
| 		X   Expr   // expression | ||||
| 		Sel *Ident // field selector | ||||
| 	} | ||||
|  | ||||
| 	// An IndexExpr node represents an expression followed by an index. | ||||
| 	IndexExpr struct { | ||||
| 		X      Expr      // expression | ||||
| 		Lbrack token.Pos // position of "[" | ||||
| 		Index  Expr      // index expression | ||||
| 		Rbrack token.Pos // position of "]" | ||||
| 	} | ||||
|  | ||||
| 	// An SliceExpr node represents an expression followed by slice indices. | ||||
| 	SliceExpr struct { | ||||
| 		X      Expr      // expression | ||||
| 		Lbrack token.Pos // position of "[" | ||||
| 		Low    Expr      // begin of slice range; or nil | ||||
| 		High   Expr      // end of slice range; or nil | ||||
| 		Max    Expr      // maximum capacity of slice; or nil | ||||
| 		Slice3 bool      // true if 3-index slice (2 colons present) | ||||
| 		Rbrack token.Pos // position of "]" | ||||
| 	} | ||||
|  | ||||
| 	// A TypeAssertExpr node represents an expression followed by a | ||||
| 	// type assertion. | ||||
| 	// | ||||
| 	TypeAssertExpr struct { | ||||
| 		X      Expr      // expression | ||||
| 		Lparen token.Pos // position of "(" | ||||
| 		Type   Expr      // asserted type; nil means type switch X.(type) | ||||
| 		Rparen token.Pos // position of ")" | ||||
| 	} | ||||
|  | ||||
| 	// A CallExpr node represents an expression followed by an argument list. | ||||
| 	CallExpr struct { | ||||
| 		Fun      Expr      // function expression | ||||
| 		Lparen   token.Pos // position of "(" | ||||
| 		Args     []Expr    // function arguments; or nil | ||||
| 		Ellipsis token.Pos // position of "...", if any | ||||
| 		Rparen   token.Pos // position of ")" | ||||
| 	} | ||||
|  | ||||
| 	// A StarExpr node represents an expression of the form "*" Expression. | ||||
| 	// Semantically it could be a unary "*" expression, or a pointer type. | ||||
| 	// | ||||
| 	StarExpr struct { | ||||
| 		Star token.Pos // position of "*" | ||||
| 		X    Expr      // operand | ||||
| 	} | ||||
|  | ||||
| 	// A UnaryExpr node represents a unary expression. | ||||
| 	// Unary "*" expressions are represented via StarExpr nodes. | ||||
| 	// | ||||
| 	UnaryExpr struct { | ||||
| 		OpPos token.Pos   // position of Op | ||||
| 		Op    token.Token // operator | ||||
| 		X     Expr        // operand | ||||
| 	} | ||||
|  | ||||
| 	// A BinaryExpr node represents a binary expression. | ||||
| 	BinaryExpr struct { | ||||
| 		X     Expr        // left operand | ||||
| 		OpPos token.Pos   // position of Op | ||||
| 		Op    token.Token // operator | ||||
| 		Y     Expr        // right operand | ||||
| 	} | ||||
|  | ||||
| 	// A KeyValueExpr node represents (key : value) pairs | ||||
| 	// in composite literals. | ||||
| 	// | ||||
| 	KeyValueExpr struct { | ||||
| 		Key   Expr | ||||
| 		Colon token.Pos // position of ":" | ||||
| 		Value Expr | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| // The direction of a channel type is indicated by one | ||||
| // of the following constants. | ||||
| // | ||||
| type ChanDir int | ||||
|  | ||||
| const ( | ||||
| 	SEND ChanDir = 1 << iota | ||||
| 	RECV | ||||
| ) | ||||
|  | ||||
| // A type is represented by a tree consisting of one | ||||
| // or more of the following type-specific expression | ||||
| // nodes. | ||||
| // | ||||
| type ( | ||||
| 	// An ArrayType node represents an array or slice type. | ||||
| 	ArrayType struct { | ||||
| 		Lbrack token.Pos // position of "[" | ||||
| 		Len    Expr      // Ellipsis node for [...]T array types, nil for slice types | ||||
| 		Elt    Expr      // element type | ||||
| 	} | ||||
|  | ||||
| 	// A StructType node represents a struct type. | ||||
| 	StructType struct { | ||||
| 		Struct     token.Pos  // position of "struct" keyword | ||||
| 		Fields     *FieldList // list of field declarations | ||||
| 		Incomplete bool       // true if (source) fields are missing in the Fields list | ||||
| 	} | ||||
|  | ||||
| 	// Pointer types are represented via StarExpr nodes. | ||||
|  | ||||
| 	// A FuncType node represents a function type. | ||||
| 	FuncType struct { | ||||
| 		Func    token.Pos  // position of "func" keyword (token.NoPos if there is no "func") | ||||
| 		Params  *FieldList // (incoming) parameters; non-nil | ||||
| 		Results *FieldList // (outgoing) results; or nil | ||||
| 	} | ||||
|  | ||||
| 	// An InterfaceType node represents an interface type. | ||||
| 	InterfaceType struct { | ||||
| 		Interface  token.Pos  // position of "interface" keyword | ||||
| 		Methods    *FieldList // list of methods | ||||
| 		Incomplete bool       // true if (source) methods are missing in the Methods list | ||||
| 	} | ||||
|  | ||||
| 	// A MapType node represents a map type. | ||||
| 	MapType struct { | ||||
| 		Map   token.Pos // position of "map" keyword | ||||
| 		Key   Expr | ||||
| 		Value Expr | ||||
| 	} | ||||
|  | ||||
| 	// A ChanType node represents a channel type. | ||||
| 	ChanType struct { | ||||
| 		Begin token.Pos // position of "chan" keyword or "<-" (whichever comes first) | ||||
| 		Arrow token.Pos // position of "<-" (token.NoPos if there is no "<-") | ||||
| 		Dir   ChanDir   // channel direction | ||||
| 		Value Expr      // value type | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| // Pos and End implementations for expression/type nodes. | ||||
| // | ||||
| func (x *BadExpr) Pos() token.Pos  { return x.From } | ||||
| func (x *Ident) Pos() token.Pos    { return x.NamePos } | ||||
| func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis } | ||||
| func (x *BasicLit) Pos() token.Pos { return x.ValuePos } | ||||
| func (x *FuncLit) Pos() token.Pos  { return x.Type.Pos() } | ||||
| func (x *CompositeLit) Pos() token.Pos { | ||||
| 	if x.Type != nil { | ||||
| 		return x.Type.Pos() | ||||
| 	} | ||||
| 	return x.Lbrace | ||||
| } | ||||
| func (x *ParenExpr) Pos() token.Pos      { return x.Lparen } | ||||
| func (x *SelectorExpr) Pos() token.Pos   { return x.X.Pos() } | ||||
| func (x *IndexExpr) Pos() token.Pos      { return x.X.Pos() } | ||||
| func (x *SliceExpr) Pos() token.Pos      { return x.X.Pos() } | ||||
| func (x *TypeAssertExpr) Pos() token.Pos { return x.X.Pos() } | ||||
| func (x *CallExpr) Pos() token.Pos       { return x.Fun.Pos() } | ||||
| func (x *StarExpr) Pos() token.Pos       { return x.Star } | ||||
| func (x *UnaryExpr) Pos() token.Pos      { return x.OpPos } | ||||
| func (x *BinaryExpr) Pos() token.Pos     { return x.X.Pos() } | ||||
| func (x *KeyValueExpr) Pos() token.Pos   { return x.Key.Pos() } | ||||
| func (x *ArrayType) Pos() token.Pos      { return x.Lbrack } | ||||
| func (x *StructType) Pos() token.Pos     { return x.Struct } | ||||
| func (x *FuncType) Pos() token.Pos { | ||||
| 	if x.Func.IsValid() || x.Params == nil { // see issue 3870 | ||||
| 		return x.Func | ||||
| 	} | ||||
| 	return x.Params.Pos() // interface method declarations have no "func" keyword | ||||
| } | ||||
| func (x *InterfaceType) Pos() token.Pos { return x.Interface } | ||||
| func (x *MapType) Pos() token.Pos       { return x.Map } | ||||
| func (x *ChanType) Pos() token.Pos      { return x.Begin } | ||||
|  | ||||
| func (x *BadExpr) End() token.Pos { return x.To } | ||||
| func (x *Ident) End() token.Pos   { return token.Pos(int(x.NamePos) + len(x.Name)) } | ||||
| func (x *Ellipsis) End() token.Pos { | ||||
| 	if x.Elt != nil { | ||||
| 		return x.Elt.End() | ||||
| 	} | ||||
| 	return x.Ellipsis + 3 // len("...") | ||||
| } | ||||
| func (x *BasicLit) End() token.Pos       { return token.Pos(int(x.ValuePos) + len(x.Value)) } | ||||
| func (x *FuncLit) End() token.Pos        { return x.Body.End() } | ||||
| func (x *CompositeLit) End() token.Pos   { return x.Rbrace + 1 } | ||||
| func (x *ParenExpr) End() token.Pos      { return x.Rparen + 1 } | ||||
| func (x *SelectorExpr) End() token.Pos   { return x.Sel.End() } | ||||
| func (x *IndexExpr) End() token.Pos      { return x.Rbrack + 1 } | ||||
| func (x *SliceExpr) End() token.Pos      { return x.Rbrack + 1 } | ||||
| func (x *TypeAssertExpr) End() token.Pos { return x.Rparen + 1 } | ||||
| func (x *CallExpr) End() token.Pos       { return x.Rparen + 1 } | ||||
| func (x *StarExpr) End() token.Pos       { return x.X.End() } | ||||
| func (x *UnaryExpr) End() token.Pos      { return x.X.End() } | ||||
| func (x *BinaryExpr) End() token.Pos     { return x.Y.End() } | ||||
| func (x *KeyValueExpr) End() token.Pos   { return x.Value.End() } | ||||
| func (x *ArrayType) End() token.Pos      { return x.Elt.End() } | ||||
| func (x *StructType) End() token.Pos     { return x.Fields.End() } | ||||
| func (x *FuncType) End() token.Pos { | ||||
| 	if x.Results != nil { | ||||
| 		return x.Results.End() | ||||
| 	} | ||||
| 	return x.Params.End() | ||||
| } | ||||
| func (x *InterfaceType) End() token.Pos { return x.Methods.End() } | ||||
| func (x *MapType) End() token.Pos       { return x.Value.End() } | ||||
| func (x *ChanType) End() token.Pos      { return x.Value.End() } | ||||
|  | ||||
| // exprNode() ensures that only expression/type nodes can be | ||||
| // assigned to an Expr. | ||||
| // | ||||
| func (*BadExpr) exprNode()        {} | ||||
| func (*Ident) exprNode()          {} | ||||
| func (*Ellipsis) exprNode()       {} | ||||
| func (*BasicLit) exprNode()       {} | ||||
| func (*FuncLit) exprNode()        {} | ||||
| func (*CompositeLit) exprNode()   {} | ||||
| func (*ParenExpr) exprNode()      {} | ||||
| func (*SelectorExpr) exprNode()   {} | ||||
| func (*IndexExpr) exprNode()      {} | ||||
| func (*SliceExpr) exprNode()      {} | ||||
| func (*TypeAssertExpr) exprNode() {} | ||||
| func (*CallExpr) exprNode()       {} | ||||
| func (*StarExpr) exprNode()       {} | ||||
| func (*UnaryExpr) exprNode()      {} | ||||
| func (*BinaryExpr) exprNode()     {} | ||||
| func (*KeyValueExpr) exprNode()   {} | ||||
|  | ||||
| func (*ArrayType) exprNode()     {} | ||||
| func (*StructType) exprNode()    {} | ||||
| func (*FuncType) exprNode()      {} | ||||
| func (*InterfaceType) exprNode() {} | ||||
| func (*MapType) exprNode()       {} | ||||
| func (*ChanType) exprNode()      {} | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Convenience functions for Idents | ||||
|  | ||||
| // NewIdent creates a new Ident without position. | ||||
| // Useful for ASTs generated by code other than the Go parser. | ||||
| // | ||||
| func NewIdent(name string) *Ident { return &Ident{token.NoPos, name, nil} } | ||||
|  | ||||
| // IsExported reports whether name is an exported Go symbol | ||||
| // (that is, whether it begins with an upper-case letter). | ||||
| // | ||||
| func IsExported(name string) bool { | ||||
| 	ch, _ := utf8.DecodeRuneInString(name) | ||||
| 	return unicode.IsUpper(ch) | ||||
| } | ||||
|  | ||||
| // IsExported reports whether id is an exported Go symbol | ||||
| // (that is, whether it begins with an uppercase letter). | ||||
| // | ||||
| func (id *Ident) IsExported() bool { return IsExported(id.Name) } | ||||
|  | ||||
| func (id *Ident) String() string { | ||||
| 	if id != nil { | ||||
| 		return id.Name | ||||
| 	} | ||||
| 	return "<nil>" | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Statements | ||||
|  | ||||
| // A statement is represented by a tree consisting of one | ||||
| // or more of the following concrete statement nodes. | ||||
| // | ||||
| type ( | ||||
| 	// A BadStmt node is a placeholder for statements containing | ||||
| 	// syntax errors for which no correct statement nodes can be | ||||
| 	// created. | ||||
| 	// | ||||
| 	BadStmt struct { | ||||
| 		From, To token.Pos // position range of bad statement | ||||
| 	} | ||||
|  | ||||
| 	// A DeclStmt node represents a declaration in a statement list. | ||||
| 	DeclStmt struct { | ||||
| 		Decl Decl // *GenDecl with CONST, TYPE, or VAR token | ||||
| 	} | ||||
|  | ||||
| 	// An EmptyStmt node represents an empty statement. | ||||
| 	// The "position" of the empty statement is the position | ||||
| 	// of the immediately following (explicit or implicit) semicolon. | ||||
| 	// | ||||
| 	EmptyStmt struct { | ||||
| 		Semicolon token.Pos // position of following ";" | ||||
| 		Implicit  bool      // if set, ";" was omitted in the source | ||||
| 	} | ||||
|  | ||||
| 	// A LabeledStmt node represents a labeled statement. | ||||
| 	LabeledStmt struct { | ||||
| 		Label *Ident | ||||
| 		Colon token.Pos // position of ":" | ||||
| 		Stmt  Stmt | ||||
| 	} | ||||
|  | ||||
| 	// An ExprStmt node represents a (stand-alone) expression | ||||
| 	// in a statement list. | ||||
| 	// | ||||
| 	ExprStmt struct { | ||||
| 		X Expr // expression | ||||
| 	} | ||||
|  | ||||
| 	// A SendStmt node represents a send statement. | ||||
| 	SendStmt struct { | ||||
| 		Chan  Expr | ||||
| 		Arrow token.Pos // position of "<-" | ||||
| 		Value Expr | ||||
| 	} | ||||
|  | ||||
| 	// An IncDecStmt node represents an increment or decrement statement. | ||||
| 	IncDecStmt struct { | ||||
| 		X      Expr | ||||
| 		TokPos token.Pos   // position of Tok | ||||
| 		Tok    token.Token // INC or DEC | ||||
| 	} | ||||
|  | ||||
| 	// An AssignStmt node represents an assignment or | ||||
| 	// a short variable declaration. | ||||
| 	// | ||||
| 	AssignStmt struct { | ||||
| 		Lhs    []Expr | ||||
| 		TokPos token.Pos   // position of Tok | ||||
| 		Tok    token.Token // assignment token, DEFINE | ||||
| 		Rhs    []Expr | ||||
| 	} | ||||
|  | ||||
| 	// A GoStmt node represents a go statement. | ||||
| 	GoStmt struct { | ||||
| 		Go   token.Pos // position of "go" keyword | ||||
| 		Call *CallExpr | ||||
| 	} | ||||
|  | ||||
| 	// A DeferStmt node represents a defer statement. | ||||
| 	DeferStmt struct { | ||||
| 		Defer token.Pos // position of "defer" keyword | ||||
| 		Call  *CallExpr | ||||
| 	} | ||||
|  | ||||
| 	// A ReturnStmt node represents a return statement. | ||||
| 	ReturnStmt struct { | ||||
| 		Return  token.Pos // position of "return" keyword | ||||
| 		Results []Expr    // result expressions; or nil | ||||
| 	} | ||||
|  | ||||
| 	// A BranchStmt node represents a break, continue, goto, | ||||
| 	// or fallthrough statement. | ||||
| 	// | ||||
| 	BranchStmt struct { | ||||
| 		TokPos token.Pos   // position of Tok | ||||
| 		Tok    token.Token // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH) | ||||
| 		Label  *Ident      // label name; or nil | ||||
| 	} | ||||
|  | ||||
| 	// A BlockStmt node represents a braced statement list. | ||||
| 	BlockStmt struct { | ||||
| 		Lbrace token.Pos // position of "{" | ||||
| 		List   []Stmt | ||||
| 		Rbrace token.Pos // position of "}" | ||||
| 	} | ||||
|  | ||||
| 	// An IfStmt node represents an if statement. | ||||
| 	IfStmt struct { | ||||
| 		If   token.Pos // position of "if" keyword | ||||
| 		Init Stmt      // initialization statement; or nil | ||||
| 		Cond Expr      // condition | ||||
| 		Body *BlockStmt | ||||
| 		Else Stmt // else branch; or nil | ||||
| 	} | ||||
|  | ||||
| 	// A CaseClause represents a case of an expression or type switch statement. | ||||
| 	CaseClause struct { | ||||
| 		Case  token.Pos // position of "case" or "default" keyword | ||||
| 		List  []Expr    // list of expressions or types; nil means default case | ||||
| 		Colon token.Pos // position of ":" | ||||
| 		Body  []Stmt    // statement list; or nil | ||||
| 	} | ||||
|  | ||||
| 	// A SwitchStmt node represents an expression switch statement. | ||||
| 	SwitchStmt struct { | ||||
| 		Switch token.Pos  // position of "switch" keyword | ||||
| 		Init   Stmt       // initialization statement; or nil | ||||
| 		Tag    Expr       // tag expression; or nil | ||||
| 		Body   *BlockStmt // CaseClauses only | ||||
| 	} | ||||
|  | ||||
| 	// An TypeSwitchStmt node represents a type switch statement. | ||||
| 	TypeSwitchStmt struct { | ||||
| 		Switch token.Pos  // position of "switch" keyword | ||||
| 		Init   Stmt       // initialization statement; or nil | ||||
| 		Assign Stmt       // x := y.(type) or y.(type) | ||||
| 		Body   *BlockStmt // CaseClauses only | ||||
| 	} | ||||
|  | ||||
| 	// A CommClause node represents a case of a select statement. | ||||
| 	CommClause struct { | ||||
| 		Case  token.Pos // position of "case" or "default" keyword | ||||
| 		Comm  Stmt      // send or receive statement; nil means default case | ||||
| 		Colon token.Pos // position of ":" | ||||
| 		Body  []Stmt    // statement list; or nil | ||||
| 	} | ||||
|  | ||||
| 	// An SelectStmt node represents a select statement. | ||||
| 	SelectStmt struct { | ||||
| 		Select token.Pos  // position of "select" keyword | ||||
| 		Body   *BlockStmt // CommClauses only | ||||
| 	} | ||||
|  | ||||
| 	// A ForStmt represents a for statement. | ||||
| 	ForStmt struct { | ||||
| 		For  token.Pos // position of "for" keyword | ||||
| 		Init Stmt      // initialization statement; or nil | ||||
| 		Cond Expr      // condition; or nil | ||||
| 		Post Stmt      // post iteration statement; or nil | ||||
| 		Body *BlockStmt | ||||
| 	} | ||||
|  | ||||
| 	// A RangeStmt represents a for statement with a range clause. | ||||
| 	RangeStmt struct { | ||||
| 		For        token.Pos   // position of "for" keyword | ||||
| 		Key, Value Expr        // Key, Value may be nil | ||||
| 		TokPos     token.Pos   // position of Tok; invalid if Key == nil | ||||
| 		Tok        token.Token // ILLEGAL if Key == nil, ASSIGN, DEFINE | ||||
| 		X          Expr        // value to range over | ||||
| 		Body       *BlockStmt | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| // Pos and End implementations for statement nodes. | ||||
| // | ||||
| func (s *BadStmt) Pos() token.Pos        { return s.From } | ||||
| func (s *DeclStmt) Pos() token.Pos       { return s.Decl.Pos() } | ||||
| func (s *EmptyStmt) Pos() token.Pos      { return s.Semicolon } | ||||
| func (s *LabeledStmt) Pos() token.Pos    { return s.Label.Pos() } | ||||
| func (s *ExprStmt) Pos() token.Pos       { return s.X.Pos() } | ||||
| func (s *SendStmt) Pos() token.Pos       { return s.Chan.Pos() } | ||||
| func (s *IncDecStmt) Pos() token.Pos     { return s.X.Pos() } | ||||
| func (s *AssignStmt) Pos() token.Pos     { return s.Lhs[0].Pos() } | ||||
| func (s *GoStmt) Pos() token.Pos         { return s.Go } | ||||
| func (s *DeferStmt) Pos() token.Pos      { return s.Defer } | ||||
| func (s *ReturnStmt) Pos() token.Pos     { return s.Return } | ||||
| func (s *BranchStmt) Pos() token.Pos     { return s.TokPos } | ||||
| func (s *BlockStmt) Pos() token.Pos      { return s.Lbrace } | ||||
| func (s *IfStmt) Pos() token.Pos         { return s.If } | ||||
| func (s *CaseClause) Pos() token.Pos     { return s.Case } | ||||
| func (s *SwitchStmt) Pos() token.Pos     { return s.Switch } | ||||
| func (s *TypeSwitchStmt) Pos() token.Pos { return s.Switch } | ||||
| func (s *CommClause) Pos() token.Pos     { return s.Case } | ||||
| func (s *SelectStmt) Pos() token.Pos     { return s.Select } | ||||
| func (s *ForStmt) Pos() token.Pos        { return s.For } | ||||
| func (s *RangeStmt) Pos() token.Pos      { return s.For } | ||||
|  | ||||
| func (s *BadStmt) End() token.Pos  { return s.To } | ||||
| func (s *DeclStmt) End() token.Pos { return s.Decl.End() } | ||||
| func (s *EmptyStmt) End() token.Pos { | ||||
| 	if s.Implicit { | ||||
| 		return s.Semicolon | ||||
| 	} | ||||
| 	return s.Semicolon + 1 /* len(";") */ | ||||
| } | ||||
| func (s *LabeledStmt) End() token.Pos { return s.Stmt.End() } | ||||
| func (s *ExprStmt) End() token.Pos    { return s.X.End() } | ||||
| func (s *SendStmt) End() token.Pos    { return s.Value.End() } | ||||
| func (s *IncDecStmt) End() token.Pos { | ||||
| 	return s.TokPos + 2 /* len("++") */ | ||||
| } | ||||
| func (s *AssignStmt) End() token.Pos { return s.Rhs[len(s.Rhs)-1].End() } | ||||
| func (s *GoStmt) End() token.Pos     { return s.Call.End() } | ||||
| func (s *DeferStmt) End() token.Pos  { return s.Call.End() } | ||||
| func (s *ReturnStmt) End() token.Pos { | ||||
| 	if n := len(s.Results); n > 0 { | ||||
| 		return s.Results[n-1].End() | ||||
| 	} | ||||
| 	return s.Return + 6 // len("return") | ||||
| } | ||||
| func (s *BranchStmt) End() token.Pos { | ||||
| 	if s.Label != nil { | ||||
| 		return s.Label.End() | ||||
| 	} | ||||
| 	return token.Pos(int(s.TokPos) + len(s.Tok.String())) | ||||
| } | ||||
| func (s *BlockStmt) End() token.Pos { return s.Rbrace + 1 } | ||||
| func (s *IfStmt) End() token.Pos { | ||||
| 	if s.Else != nil { | ||||
| 		return s.Else.End() | ||||
| 	} | ||||
| 	return s.Body.End() | ||||
| } | ||||
| func (s *CaseClause) End() token.Pos { | ||||
| 	if n := len(s.Body); n > 0 { | ||||
| 		return s.Body[n-1].End() | ||||
| 	} | ||||
| 	return s.Colon + 1 | ||||
| } | ||||
| func (s *SwitchStmt) End() token.Pos     { return s.Body.End() } | ||||
| func (s *TypeSwitchStmt) End() token.Pos { return s.Body.End() } | ||||
| func (s *CommClause) End() token.Pos { | ||||
| 	if n := len(s.Body); n > 0 { | ||||
| 		return s.Body[n-1].End() | ||||
| 	} | ||||
| 	return s.Colon + 1 | ||||
| } | ||||
| func (s *SelectStmt) End() token.Pos { return s.Body.End() } | ||||
| func (s *ForStmt) End() token.Pos    { return s.Body.End() } | ||||
| func (s *RangeStmt) End() token.Pos  { return s.Body.End() } | ||||
|  | ||||
| // stmtNode() ensures that only statement nodes can be | ||||
| // assigned to a Stmt. | ||||
| // | ||||
| func (*BadStmt) stmtNode()        {} | ||||
| func (*DeclStmt) stmtNode()       {} | ||||
| func (*EmptyStmt) stmtNode()      {} | ||||
| func (*LabeledStmt) stmtNode()    {} | ||||
| func (*ExprStmt) stmtNode()       {} | ||||
| func (*SendStmt) stmtNode()       {} | ||||
| func (*IncDecStmt) stmtNode()     {} | ||||
| func (*AssignStmt) stmtNode()     {} | ||||
| func (*GoStmt) stmtNode()         {} | ||||
| func (*DeferStmt) stmtNode()      {} | ||||
| func (*ReturnStmt) stmtNode()     {} | ||||
| func (*BranchStmt) stmtNode()     {} | ||||
| func (*BlockStmt) stmtNode()      {} | ||||
| func (*IfStmt) stmtNode()         {} | ||||
| func (*CaseClause) stmtNode()     {} | ||||
| func (*SwitchStmt) stmtNode()     {} | ||||
| func (*TypeSwitchStmt) stmtNode() {} | ||||
| func (*CommClause) stmtNode()     {} | ||||
| func (*SelectStmt) stmtNode()     {} | ||||
| func (*ForStmt) stmtNode()        {} | ||||
| func (*RangeStmt) stmtNode()      {} | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Declarations | ||||
|  | ||||
| // A Spec node represents a single (non-parenthesized) import, | ||||
| // constant, type, or variable declaration. | ||||
| // | ||||
| type ( | ||||
| 	// The Spec type stands for any of *ImportSpec, *ValueSpec, and *TypeSpec. | ||||
| 	Spec interface { | ||||
| 		Node | ||||
| 		specNode() | ||||
| 	} | ||||
|  | ||||
| 	// An ImportSpec node represents a single package import. | ||||
| 	ImportSpec struct { | ||||
| 		Doc     *CommentGroup // associated documentation; or nil | ||||
| 		Name    *Ident        // local package name (including "."); or nil | ||||
| 		Path    *BasicLit     // import path | ||||
| 		Comment *CommentGroup // line comments; or nil | ||||
| 		EndPos  token.Pos     // end of spec (overrides Path.Pos if nonzero) | ||||
| 	} | ||||
|  | ||||
| 	// A ValueSpec node represents a constant or variable declaration | ||||
| 	// (ConstSpec or VarSpec production). | ||||
| 	// | ||||
| 	ValueSpec struct { | ||||
| 		Doc     *CommentGroup // associated documentation; or nil | ||||
| 		Names   []*Ident      // value names (len(Names) > 0) | ||||
| 		Type    Expr          // value type; or nil | ||||
| 		Values  []Expr        // initial values; or nil | ||||
| 		Comment *CommentGroup // line comments; or nil | ||||
| 	} | ||||
|  | ||||
| 	// A TypeSpec node represents a type declaration (TypeSpec production). | ||||
| 	TypeSpec struct { | ||||
| 		Doc     *CommentGroup // associated documentation; or nil | ||||
| 		Name    *Ident        // type name | ||||
| 		Type    Expr          // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes | ||||
| 		Comment *CommentGroup // line comments; or nil | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| // Pos and End implementations for spec nodes. | ||||
| // | ||||
| func (s *ImportSpec) Pos() token.Pos { | ||||
| 	if s.Name != nil { | ||||
| 		return s.Name.Pos() | ||||
| 	} | ||||
| 	return s.Path.Pos() | ||||
| } | ||||
| func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() } | ||||
| func (s *TypeSpec) Pos() token.Pos  { return s.Name.Pos() } | ||||
|  | ||||
| func (s *ImportSpec) End() token.Pos { | ||||
| 	if s.EndPos != 0 { | ||||
| 		return s.EndPos | ||||
| 	} | ||||
| 	return s.Path.End() | ||||
| } | ||||
|  | ||||
| func (s *ValueSpec) End() token.Pos { | ||||
| 	if n := len(s.Values); n > 0 { | ||||
| 		return s.Values[n-1].End() | ||||
| 	} | ||||
| 	if s.Type != nil { | ||||
| 		return s.Type.End() | ||||
| 	} | ||||
| 	return s.Names[len(s.Names)-1].End() | ||||
| } | ||||
| func (s *TypeSpec) End() token.Pos { return s.Type.End() } | ||||
|  | ||||
| // specNode() ensures that only spec nodes can be | ||||
| // assigned to a Spec. | ||||
| // | ||||
| func (*ImportSpec) specNode() {} | ||||
| func (*ValueSpec) specNode()  {} | ||||
| func (*TypeSpec) specNode()   {} | ||||
|  | ||||
| // A declaration is represented by one of the following declaration nodes. | ||||
| // | ||||
| type ( | ||||
| 	// A BadDecl node is a placeholder for declarations containing | ||||
| 	// syntax errors for which no correct declaration nodes can be | ||||
| 	// created. | ||||
| 	// | ||||
| 	BadDecl struct { | ||||
| 		From, To token.Pos // position range of bad declaration | ||||
| 	} | ||||
|  | ||||
| 	// A GenDecl node (generic declaration node) represents an import, | ||||
| 	// constant, type or variable declaration. A valid Lparen position | ||||
| 	// (Lparen.Line > 0) indicates a parenthesized declaration. | ||||
| 	// | ||||
| 	// Relationship between Tok value and Specs element type: | ||||
| 	// | ||||
| 	//	token.IMPORT  *ImportSpec | ||||
| 	//	token.CONST   *ValueSpec | ||||
| 	//	token.TYPE    *TypeSpec | ||||
| 	//	token.VAR     *ValueSpec | ||||
| 	// | ||||
| 	GenDecl struct { | ||||
| 		Doc    *CommentGroup // associated documentation; or nil | ||||
| 		TokPos token.Pos     // position of Tok | ||||
| 		Tok    token.Token   // IMPORT, CONST, TYPE, VAR | ||||
| 		Lparen token.Pos     // position of '(', if any | ||||
| 		Specs  []Spec | ||||
| 		Rparen token.Pos // position of ')', if any | ||||
| 	} | ||||
|  | ||||
| 	// A FuncDecl node represents a function declaration. | ||||
| 	FuncDecl struct { | ||||
| 		Doc  *CommentGroup // associated documentation; or nil | ||||
| 		Recv *FieldList    // receiver (methods); or nil (functions) | ||||
| 		Name *Ident        // function/method name | ||||
| 		Type *FuncType     // function signature: parameters, results, and position of "func" keyword | ||||
| 		Body *BlockStmt    // function body; or nil (forward declaration) | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| // Pos and End implementations for declaration nodes. | ||||
| // | ||||
| func (d *BadDecl) Pos() token.Pos  { return d.From } | ||||
| func (d *GenDecl) Pos() token.Pos  { return d.TokPos } | ||||
| func (d *FuncDecl) Pos() token.Pos { return d.Type.Pos() } | ||||
|  | ||||
| func (d *BadDecl) End() token.Pos { return d.To } | ||||
| func (d *GenDecl) End() token.Pos { | ||||
| 	if d.Rparen.IsValid() { | ||||
| 		return d.Rparen + 1 | ||||
| 	} | ||||
| 	return d.Specs[0].End() | ||||
| } | ||||
| func (d *FuncDecl) End() token.Pos { | ||||
| 	if d.Body != nil { | ||||
| 		return d.Body.End() | ||||
| 	} | ||||
| 	return d.Type.End() | ||||
| } | ||||
|  | ||||
| // declNode() ensures that only declaration nodes can be | ||||
| // assigned to a Decl. | ||||
| // | ||||
| func (*BadDecl) declNode()  {} | ||||
| func (*GenDecl) declNode()  {} | ||||
| func (*FuncDecl) declNode() {} | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Files and packages | ||||
|  | ||||
| // A File node represents a Go source file. | ||||
| // | ||||
| // The Comments list contains all comments in the source file in order of | ||||
| // appearance, including the comments that are pointed to from other nodes | ||||
| // via Doc and Comment fields. | ||||
| // | ||||
| type File struct { | ||||
| 	Doc        *CommentGroup   // associated documentation; or nil | ||||
| 	Package    token.Pos       // position of "package" keyword | ||||
| 	Name       *Ident          // package name | ||||
| 	Decls      []Decl          // top-level declarations; or nil | ||||
| 	Scope      *Scope          // package scope (this file only) | ||||
| 	Imports    []*ImportSpec   // imports in this file | ||||
| 	Unresolved []*Ident        // unresolved identifiers in this file | ||||
| 	Comments   []*CommentGroup // list of all comments in the source file | ||||
| } | ||||
|  | ||||
| func (f *File) Pos() token.Pos { return f.Package } | ||||
| func (f *File) End() token.Pos { | ||||
| 	if n := len(f.Decls); n > 0 { | ||||
| 		return f.Decls[n-1].End() | ||||
| 	} | ||||
| 	return f.Name.End() | ||||
| } | ||||
|  | ||||
| // A Package node represents a set of source files | ||||
| // collectively building a Go package. | ||||
| // | ||||
| type Package struct { | ||||
| 	Name    string             // package name | ||||
| 	Scope   *Scope             // package scope across all files | ||||
| 	Imports map[string]*Object // map of package id -> package object | ||||
| 	Files   map[string]*File   // Go source files by filename | ||||
| } | ||||
|  | ||||
| func (p *Package) Pos() token.Pos { return token.NoPos } | ||||
| func (p *Package) End() token.Pos { return token.NoPos } | ||||
							
								
								
									
										50
									
								
								third_party/golang/go/ast/ast_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								third_party/golang/go/ast/ast_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| package ast | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| var comments = []struct { | ||||
| 	list []string | ||||
| 	text string | ||||
| }{ | ||||
| 	{[]string{"//"}, ""}, | ||||
| 	{[]string{"//   "}, ""}, | ||||
| 	{[]string{"//", "//", "//   "}, ""}, | ||||
| 	{[]string{"// foo   "}, "foo\n"}, | ||||
| 	{[]string{"//", "//", "// foo"}, "foo\n"}, | ||||
| 	{[]string{"// foo  bar  "}, "foo  bar\n"}, | ||||
| 	{[]string{"// foo", "// bar"}, "foo\nbar\n"}, | ||||
| 	{[]string{"// foo", "//", "//", "//", "// bar"}, "foo\n\nbar\n"}, | ||||
| 	{[]string{"// foo", "/* bar */"}, "foo\n bar\n"}, | ||||
| 	{[]string{"//", "//", "//", "// foo", "//", "//", "//"}, "foo\n"}, | ||||
|  | ||||
| 	{[]string{"/**/"}, ""}, | ||||
| 	{[]string{"/*   */"}, ""}, | ||||
| 	{[]string{"/**/", "/**/", "/*   */"}, ""}, | ||||
| 	{[]string{"/* Foo   */"}, " Foo\n"}, | ||||
| 	{[]string{"/* Foo  Bar  */"}, " Foo  Bar\n"}, | ||||
| 	{[]string{"/* Foo*/", "/* Bar*/"}, " Foo\n Bar\n"}, | ||||
| 	{[]string{"/* Foo*/", "/**/", "/**/", "/**/", "// Bar"}, " Foo\n\nBar\n"}, | ||||
| 	{[]string{"/* Foo*/", "/*\n*/", "//", "/*\n*/", "// Bar"}, " Foo\n\nBar\n"}, | ||||
| 	{[]string{"/* Foo*/", "// Bar"}, " Foo\nBar\n"}, | ||||
| 	{[]string{"/* Foo\n Bar*/"}, " Foo\n Bar\n"}, | ||||
| } | ||||
|  | ||||
| func TestCommentText(t *testing.T) { | ||||
| 	for i, c := range comments { | ||||
| 		list := make([]*Comment, len(c.list)) | ||||
| 		for i, s := range c.list { | ||||
| 			list[i] = &Comment{Text: s} | ||||
| 		} | ||||
|  | ||||
| 		text := (&CommentGroup{list}).Text() | ||||
| 		if text != c.text { | ||||
| 			t.Errorf("case %d: got %q; expected %q", i, text, c.text) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										332
									
								
								third_party/golang/go/ast/commentmap.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								third_party/golang/go/ast/commentmap.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,332 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| package ast | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"sort" | ||||
| ) | ||||
|  | ||||
| type byPos []*CommentGroup | ||||
|  | ||||
| func (a byPos) Len() int           { return len(a) } | ||||
| func (a byPos) Less(i, j int) bool { return a[i].Pos() < a[j].Pos() } | ||||
| func (a byPos) Swap(i, j int)      { a[i], a[j] = a[j], a[i] } | ||||
|  | ||||
| // sortComments sorts the list of comment groups in source order. | ||||
| // | ||||
| func sortComments(list []*CommentGroup) { | ||||
| 	// TODO(gri): Does it make sense to check for sorted-ness | ||||
| 	//            first (because we know that sorted-ness is | ||||
| 	//            very likely)? | ||||
| 	if orderedList := byPos(list); !sort.IsSorted(orderedList) { | ||||
| 		sort.Sort(orderedList) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // A CommentMap maps an AST node to a list of comment groups | ||||
| // associated with it. See NewCommentMap for a description of | ||||
| // the association. | ||||
| // | ||||
| type CommentMap map[Node][]*CommentGroup | ||||
|  | ||||
| func (cmap CommentMap) addComment(n Node, c *CommentGroup) { | ||||
| 	list := cmap[n] | ||||
| 	if len(list) == 0 { | ||||
| 		list = []*CommentGroup{c} | ||||
| 	} else { | ||||
| 		list = append(list, c) | ||||
| 	} | ||||
| 	cmap[n] = list | ||||
| } | ||||
|  | ||||
| type byInterval []Node | ||||
|  | ||||
| func (a byInterval) Len() int { return len(a) } | ||||
| func (a byInterval) Less(i, j int) bool { | ||||
| 	pi, pj := a[i].Pos(), a[j].Pos() | ||||
| 	return pi < pj || pi == pj && a[i].End() > a[j].End() | ||||
| } | ||||
| func (a byInterval) Swap(i, j int) { a[i], a[j] = a[j], a[i] } | ||||
|  | ||||
| // nodeList returns the list of nodes of the AST n in source order. | ||||
| // | ||||
| func nodeList(n Node) []Node { | ||||
| 	var list []Node | ||||
| 	Inspect(n, func(n Node) bool { | ||||
| 		// don't collect comments | ||||
| 		switch n.(type) { | ||||
| 		case nil, *CommentGroup, *Comment: | ||||
| 			return false | ||||
| 		} | ||||
| 		list = append(list, n) | ||||
| 		return true | ||||
| 	}) | ||||
| 	// Note: The current implementation assumes that Inspect traverses the | ||||
| 	//       AST in depth-first and thus _source_ order. If AST traversal | ||||
| 	//       does not follow source order, the sorting call below will be | ||||
| 	//       required. | ||||
| 	// sort.Sort(byInterval(list)) | ||||
| 	return list | ||||
| } | ||||
|  | ||||
| // A commentListReader helps iterating through a list of comment groups. | ||||
| // | ||||
| type commentListReader struct { | ||||
| 	fset     *token.FileSet | ||||
| 	list     []*CommentGroup | ||||
| 	index    int | ||||
| 	comment  *CommentGroup  // comment group at current index | ||||
| 	pos, end token.Position // source interval of comment group at current index | ||||
| } | ||||
|  | ||||
| func (r *commentListReader) eol() bool { | ||||
| 	return r.index >= len(r.list) | ||||
| } | ||||
|  | ||||
| func (r *commentListReader) next() { | ||||
| 	if !r.eol() { | ||||
| 		r.comment = r.list[r.index] | ||||
| 		r.pos = r.fset.Position(r.comment.Pos()) | ||||
| 		r.end = r.fset.Position(r.comment.End()) | ||||
| 		r.index++ | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // A nodeStack keeps track of nested nodes. | ||||
| // A node lower on the stack lexically contains the nodes higher on the stack. | ||||
| // | ||||
| type nodeStack []Node | ||||
|  | ||||
| // push pops all nodes that appear lexically before n | ||||
| // and then pushes n on the stack. | ||||
| // | ||||
| func (s *nodeStack) push(n Node) { | ||||
| 	s.pop(n.Pos()) | ||||
| 	*s = append((*s), n) | ||||
| } | ||||
|  | ||||
| // pop pops all nodes that appear lexically before pos | ||||
| // (i.e., whose lexical extent has ended before or at pos). | ||||
| // It returns the last node popped. | ||||
| // | ||||
| func (s *nodeStack) pop(pos token.Pos) (top Node) { | ||||
| 	i := len(*s) | ||||
| 	for i > 0 && (*s)[i-1].End() <= pos { | ||||
| 		top = (*s)[i-1] | ||||
| 		i-- | ||||
| 	} | ||||
| 	*s = (*s)[0:i] | ||||
| 	return top | ||||
| } | ||||
|  | ||||
| // NewCommentMap creates a new comment map by associating comment groups | ||||
| // of the comments list with the nodes of the AST specified by node. | ||||
| // | ||||
| // A comment group g is associated with a node n if: | ||||
| // | ||||
| //   - g starts on the same line as n ends | ||||
| //   - g starts on the line immediately following n, and there is | ||||
| //     at least one empty line after g and before the next node | ||||
| //   - g starts before n and is not associated to the node before n | ||||
| //     via the previous rules | ||||
| // | ||||
| // NewCommentMap tries to associate a comment group to the "largest" | ||||
| // node possible: For instance, if the comment is a line comment | ||||
| // trailing an assignment, the comment is associated with the entire | ||||
| // assignment rather than just the last operand in the assignment. | ||||
| // | ||||
| func NewCommentMap(fset *token.FileSet, node Node, comments []*CommentGroup) CommentMap { | ||||
| 	if len(comments) == 0 { | ||||
| 		return nil // no comments to map | ||||
| 	} | ||||
|  | ||||
| 	cmap := make(CommentMap) | ||||
|  | ||||
| 	// set up comment reader r | ||||
| 	tmp := make([]*CommentGroup, len(comments)) | ||||
| 	copy(tmp, comments) // don't change incoming comments | ||||
| 	sortComments(tmp) | ||||
| 	r := commentListReader{fset: fset, list: tmp} // !r.eol() because len(comments) > 0 | ||||
| 	r.next() | ||||
|  | ||||
| 	// create node list in lexical order | ||||
| 	nodes := nodeList(node) | ||||
| 	nodes = append(nodes, nil) // append sentinel | ||||
|  | ||||
| 	// set up iteration variables | ||||
| 	var ( | ||||
| 		p     Node           // previous node | ||||
| 		pend  token.Position // end of p | ||||
| 		pg    Node           // previous node group (enclosing nodes of "importance") | ||||
| 		pgend token.Position // end of pg | ||||
| 		stack nodeStack      // stack of node groups | ||||
| 	) | ||||
|  | ||||
| 	for _, q := range nodes { | ||||
| 		var qpos token.Position | ||||
| 		if q != nil { | ||||
| 			qpos = fset.Position(q.Pos()) // current node position | ||||
| 		} else { | ||||
| 			// set fake sentinel position to infinity so that | ||||
| 			// all comments get processed before the sentinel | ||||
| 			const infinity = 1 << 30 | ||||
| 			qpos.Offset = infinity | ||||
| 			qpos.Line = infinity | ||||
| 		} | ||||
|  | ||||
| 		// process comments before current node | ||||
| 		for r.end.Offset <= qpos.Offset { | ||||
| 			// determine recent node group | ||||
| 			if top := stack.pop(r.comment.Pos()); top != nil { | ||||
| 				pg = top | ||||
| 				pgend = fset.Position(pg.End()) | ||||
| 			} | ||||
| 			// Try to associate a comment first with a node group | ||||
| 			// (i.e., a node of "importance" such as a declaration); | ||||
| 			// if that fails, try to associate it with the most recent | ||||
| 			// node. | ||||
| 			// TODO(gri) try to simplify the logic below | ||||
| 			var assoc Node | ||||
| 			switch { | ||||
| 			case pg != nil && | ||||
| 				(pgend.Line == r.pos.Line || | ||||
| 					pgend.Line+1 == r.pos.Line && r.end.Line+1 < qpos.Line): | ||||
| 				// 1) comment starts on same line as previous node group ends, or | ||||
| 				// 2) comment starts on the line immediately after the | ||||
| 				//    previous node group and there is an empty line before | ||||
| 				//    the current node | ||||
| 				// => associate comment with previous node group | ||||
| 				assoc = pg | ||||
| 			case p != nil && | ||||
| 				(pend.Line == r.pos.Line || | ||||
| 					pend.Line+1 == r.pos.Line && r.end.Line+1 < qpos.Line || | ||||
| 					q == nil): | ||||
| 				// same rules apply as above for p rather than pg, | ||||
| 				// but also associate with p if we are at the end (q == nil) | ||||
| 				assoc = p | ||||
| 			default: | ||||
| 				// otherwise, associate comment with current node | ||||
| 				if q == nil { | ||||
| 					// we can only reach here if there was no p | ||||
| 					// which would imply that there were no nodes | ||||
| 					panic("internal error: no comments should be associated with sentinel") | ||||
| 				} | ||||
| 				assoc = q | ||||
| 			} | ||||
| 			cmap.addComment(assoc, r.comment) | ||||
| 			if r.eol() { | ||||
| 				return cmap | ||||
| 			} | ||||
| 			r.next() | ||||
| 		} | ||||
|  | ||||
| 		// update previous node | ||||
| 		p = q | ||||
| 		pend = fset.Position(p.End()) | ||||
|  | ||||
| 		// update previous node group if we see an "important" node | ||||
| 		switch q.(type) { | ||||
| 		case *File, *Field, Decl, Spec, Stmt: | ||||
| 			stack.push(q) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return cmap | ||||
| } | ||||
|  | ||||
| // Update replaces an old node in the comment map with the new node | ||||
| // and returns the new node. Comments that were associated with the | ||||
| // old node are associated with the new node. | ||||
| // | ||||
| func (cmap CommentMap) Update(old, new Node) Node { | ||||
| 	if list := cmap[old]; len(list) > 0 { | ||||
| 		delete(cmap, old) | ||||
| 		cmap[new] = append(cmap[new], list...) | ||||
| 	} | ||||
| 	return new | ||||
| } | ||||
|  | ||||
| // Filter returns a new comment map consisting of only those | ||||
| // entries of cmap for which a corresponding node exists in | ||||
| // the AST specified by node. | ||||
| // | ||||
| func (cmap CommentMap) Filter(node Node) CommentMap { | ||||
| 	umap := make(CommentMap) | ||||
| 	Inspect(node, func(n Node) bool { | ||||
| 		if g := cmap[n]; len(g) > 0 { | ||||
| 			umap[n] = g | ||||
| 		} | ||||
| 		return true | ||||
| 	}) | ||||
| 	return umap | ||||
| } | ||||
|  | ||||
| // Comments returns the list of comment groups in the comment map. | ||||
| // The result is sorted is source order. | ||||
| // | ||||
| func (cmap CommentMap) Comments() []*CommentGroup { | ||||
| 	list := make([]*CommentGroup, 0, len(cmap)) | ||||
| 	for _, e := range cmap { | ||||
| 		list = append(list, e...) | ||||
| 	} | ||||
| 	sortComments(list) | ||||
| 	return list | ||||
| } | ||||
|  | ||||
| func summary(list []*CommentGroup) string { | ||||
| 	const maxLen = 40 | ||||
| 	var buf bytes.Buffer | ||||
|  | ||||
| 	// collect comments text | ||||
| loop: | ||||
| 	for _, group := range list { | ||||
| 		// Note: CommentGroup.Text() does too much work for what we | ||||
| 		//       need and would only replace this innermost loop. | ||||
| 		//       Just do it explicitly. | ||||
| 		for _, comment := range group.List { | ||||
| 			if buf.Len() >= maxLen { | ||||
| 				break loop | ||||
| 			} | ||||
| 			buf.WriteString(comment.Text) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// truncate if too long | ||||
| 	if buf.Len() > maxLen { | ||||
| 		buf.Truncate(maxLen - 3) | ||||
| 		buf.WriteString("...") | ||||
| 	} | ||||
|  | ||||
| 	// replace any invisibles with blanks | ||||
| 	bytes := buf.Bytes() | ||||
| 	for i, b := range bytes { | ||||
| 		switch b { | ||||
| 		case '\t', '\n', '\r': | ||||
| 			bytes[i] = ' ' | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return string(bytes) | ||||
| } | ||||
|  | ||||
| func (cmap CommentMap) String() string { | ||||
| 	var buf bytes.Buffer | ||||
| 	fmt.Fprintln(&buf, "CommentMap {") | ||||
| 	for node, comment := range cmap { | ||||
| 		// print name of identifiers; print node type for other nodes | ||||
| 		var s string | ||||
| 		if ident, ok := node.(*Ident); ok { | ||||
| 			s = ident.Name | ||||
| 		} else { | ||||
| 			s = fmt.Sprintf("%T", node) | ||||
| 		} | ||||
| 		fmt.Fprintf(&buf, "\t%p  %20s:  %s\n", node, s, summary(comment)) | ||||
| 	} | ||||
| 	fmt.Fprintln(&buf, "}") | ||||
| 	return buf.String() | ||||
| } | ||||
							
								
								
									
										143
									
								
								third_party/golang/go/ast/commentmap_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								third_party/golang/go/ast/commentmap_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // To avoid a cyclic dependency with go/parser, this file is in a separate package. | ||||
|  | ||||
| package ast_test | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	. "k8s.io/kubernetes/third_party/golang/go/ast" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/parser" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"sort" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| const src = ` | ||||
| // the very first comment | ||||
|  | ||||
| // package p | ||||
| package p /* the name is p */ | ||||
|  | ||||
| // imports | ||||
| import ( | ||||
| 	"bytes"     // bytes | ||||
| 	"fmt"       // fmt | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/ast" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/parser" | ||||
| ) | ||||
|  | ||||
| // T | ||||
| type T struct { | ||||
| 	a, b, c int // associated with a, b, c | ||||
| 	// associated with x, y | ||||
| 	x, y float64    // float values | ||||
| 	z    complex128 // complex value | ||||
| } | ||||
| // also associated with T | ||||
|  | ||||
| // x | ||||
| var x = 0 // x = 0 | ||||
| // also associated with x | ||||
|  | ||||
| // f1 | ||||
| func f1() { | ||||
| 	/* associated with s1 */ | ||||
| 	s1() | ||||
| 	// also associated with s1 | ||||
| 	 | ||||
| 	// associated with s2 | ||||
| 	 | ||||
| 	// also associated with s2 | ||||
| 	s2() // line comment for s2 | ||||
| } | ||||
| // associated with f1 | ||||
| // also associated with f1 | ||||
|  | ||||
| // associated with f2 | ||||
|  | ||||
| // f2 | ||||
| func f2() { | ||||
| } | ||||
|  | ||||
| func f3() { | ||||
| 	i := 1 /* 1 */ + 2 // addition | ||||
| 	_ = i | ||||
| } | ||||
|  | ||||
| // the very last comment | ||||
| ` | ||||
|  | ||||
| // res maps a key of the form "line number: node type" | ||||
| // to the associated comments' text. | ||||
| // | ||||
| var res = map[string]string{ | ||||
| 	" 5: *ast.File":       "the very first comment\npackage p\n", | ||||
| 	" 5: *ast.Ident":      " the name is p\n", | ||||
| 	" 8: *ast.GenDecl":    "imports\n", | ||||
| 	" 9: *ast.ImportSpec": "bytes\n", | ||||
| 	"10: *ast.ImportSpec": "fmt\n", | ||||
| 	"16: *ast.GenDecl":    "T\nalso associated with T\n", | ||||
| 	"17: *ast.Field":      "associated with a, b, c\n", | ||||
| 	"19: *ast.Field":      "associated with x, y\nfloat values\n", | ||||
| 	"20: *ast.Field":      "complex value\n", | ||||
| 	"25: *ast.GenDecl":    "x\nx = 0\nalso associated with x\n", | ||||
| 	"29: *ast.FuncDecl":   "f1\nassociated with f1\nalso associated with f1\n", | ||||
| 	"31: *ast.ExprStmt":   " associated with s1\nalso associated with s1\n", | ||||
| 	"37: *ast.ExprStmt":   "associated with s2\nalso associated with s2\nline comment for s2\n", | ||||
| 	"45: *ast.FuncDecl":   "associated with f2\nf2\n", | ||||
| 	"49: *ast.AssignStmt": "addition\n", | ||||
| 	"49: *ast.BasicLit":   " 1\n", | ||||
| 	"50: *ast.Ident":      "the very last comment\n", | ||||
| } | ||||
|  | ||||
| func ctext(list []*CommentGroup) string { | ||||
| 	var buf bytes.Buffer | ||||
| 	for _, g := range list { | ||||
| 		buf.WriteString(g.Text()) | ||||
| 	} | ||||
| 	return buf.String() | ||||
| } | ||||
|  | ||||
| func TestCommentMap(t *testing.T) { | ||||
| 	fset := token.NewFileSet() | ||||
| 	f, err := parser.ParseFile(fset, "", src, parser.ParseComments) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	cmap := NewCommentMap(fset, f, f.Comments) | ||||
|  | ||||
| 	// very correct association of comments | ||||
| 	for n, list := range cmap { | ||||
| 		key := fmt.Sprintf("%2d: %T", fset.Position(n.Pos()).Line, n) | ||||
| 		got := ctext(list) | ||||
| 		want := res[key] | ||||
| 		if got != want { | ||||
| 			t.Errorf("%s: got %q; want %q", key, got, want) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// verify that no comments got lost | ||||
| 	if n := len(cmap.Comments()); n != len(f.Comments) { | ||||
| 		t.Errorf("got %d comment groups in map; want %d", n, len(f.Comments)) | ||||
| 	} | ||||
|  | ||||
| 	// support code to update test: | ||||
| 	// set genMap to true to generate res map | ||||
| 	const genMap = false | ||||
| 	if genMap { | ||||
| 		out := make([]string, 0, len(cmap)) | ||||
| 		for n, list := range cmap { | ||||
| 			out = append(out, fmt.Sprintf("\t\"%2d: %T\":\t%q,", fset.Position(n.Pos()).Line, n, ctext(list))) | ||||
| 		} | ||||
| 		sort.Strings(out) | ||||
| 		for _, s := range out { | ||||
| 			fmt.Println(s) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // TODO(gri): add tests for Filter. | ||||
							
								
								
									
										210
									
								
								third_party/golang/go/ast/example_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								third_party/golang/go/ast/example_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,210 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| package ast_test | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/format" | ||||
| 	"go/parser" | ||||
| 	"go/token" | ||||
| ) | ||||
|  | ||||
| // This example demonstrates how to inspect the AST of a Go program. | ||||
| func ExampleInspect() { | ||||
| 	// src is the input for which we want to inspect the AST. | ||||
| 	src := ` | ||||
| package p | ||||
| const c = 1.0 | ||||
| var X = f(3.14)*2 + c | ||||
| ` | ||||
|  | ||||
| 	// Create the AST by parsing src. | ||||
| 	fset := token.NewFileSet() // positions are relative to fset | ||||
| 	f, err := parser.ParseFile(fset, "src.go", src, 0) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	// Inspect the AST and print all identifiers and literals. | ||||
| 	ast.Inspect(f, func(n ast.Node) bool { | ||||
| 		var s string | ||||
| 		switch x := n.(type) { | ||||
| 		case *ast.BasicLit: | ||||
| 			s = x.Value | ||||
| 		case *ast.Ident: | ||||
| 			s = x.Name | ||||
| 		} | ||||
| 		if s != "" { | ||||
| 			fmt.Printf("%s:\t%s\n", fset.Position(n.Pos()), s) | ||||
| 		} | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| 	// output: | ||||
| 	// src.go:2:9:	p | ||||
| 	// src.go:3:7:	c | ||||
| 	// src.go:3:11:	1.0 | ||||
| 	// src.go:4:5:	X | ||||
| 	// src.go:4:9:	f | ||||
| 	// src.go:4:11:	3.14 | ||||
| 	// src.go:4:17:	2 | ||||
| 	// src.go:4:21:	c | ||||
| } | ||||
|  | ||||
| // This example shows what an AST looks like when printed for debugging. | ||||
| func ExamplePrint() { | ||||
| 	// src is the input for which we want to print the AST. | ||||
| 	src := ` | ||||
| package main | ||||
| func main() { | ||||
| 	println("Hello, World!") | ||||
| } | ||||
| ` | ||||
|  | ||||
| 	// Create the AST by parsing src. | ||||
| 	fset := token.NewFileSet() // positions are relative to fset | ||||
| 	f, err := parser.ParseFile(fset, "", src, 0) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	// Print the AST. | ||||
| 	ast.Print(fset, f) | ||||
|  | ||||
| 	// output: | ||||
| 	//      0  *ast.File { | ||||
| 	//      1  .  Package: 2:1 | ||||
| 	//      2  .  Name: *ast.Ident { | ||||
| 	//      3  .  .  NamePos: 2:9 | ||||
| 	//      4  .  .  Name: "main" | ||||
| 	//      5  .  } | ||||
| 	//      6  .  Decls: []ast.Decl (len = 1) { | ||||
| 	//      7  .  .  0: *ast.FuncDecl { | ||||
| 	//      8  .  .  .  Name: *ast.Ident { | ||||
| 	//      9  .  .  .  .  NamePos: 3:6 | ||||
| 	//     10  .  .  .  .  Name: "main" | ||||
| 	//     11  .  .  .  .  Obj: *ast.Object { | ||||
| 	//     12  .  .  .  .  .  Kind: func | ||||
| 	//     13  .  .  .  .  .  Name: "main" | ||||
| 	//     14  .  .  .  .  .  Decl: *(obj @ 7) | ||||
| 	//     15  .  .  .  .  } | ||||
| 	//     16  .  .  .  } | ||||
| 	//     17  .  .  .  Type: *ast.FuncType { | ||||
| 	//     18  .  .  .  .  Func: 3:1 | ||||
| 	//     19  .  .  .  .  Params: *ast.FieldList { | ||||
| 	//     20  .  .  .  .  .  Opening: 3:10 | ||||
| 	//     21  .  .  .  .  .  Closing: 3:11 | ||||
| 	//     22  .  .  .  .  } | ||||
| 	//     23  .  .  .  } | ||||
| 	//     24  .  .  .  Body: *ast.BlockStmt { | ||||
| 	//     25  .  .  .  .  Lbrace: 3:13 | ||||
| 	//     26  .  .  .  .  List: []ast.Stmt (len = 1) { | ||||
| 	//     27  .  .  .  .  .  0: *ast.ExprStmt { | ||||
| 	//     28  .  .  .  .  .  .  X: *ast.CallExpr { | ||||
| 	//     29  .  .  .  .  .  .  .  Fun: *ast.Ident { | ||||
| 	//     30  .  .  .  .  .  .  .  .  NamePos: 4:2 | ||||
| 	//     31  .  .  .  .  .  .  .  .  Name: "println" | ||||
| 	//     32  .  .  .  .  .  .  .  } | ||||
| 	//     33  .  .  .  .  .  .  .  Lparen: 4:9 | ||||
| 	//     34  .  .  .  .  .  .  .  Args: []ast.Expr (len = 1) { | ||||
| 	//     35  .  .  .  .  .  .  .  .  0: *ast.BasicLit { | ||||
| 	//     36  .  .  .  .  .  .  .  .  .  ValuePos: 4:10 | ||||
| 	//     37  .  .  .  .  .  .  .  .  .  Kind: STRING | ||||
| 	//     38  .  .  .  .  .  .  .  .  .  Value: "\"Hello, World!\"" | ||||
| 	//     39  .  .  .  .  .  .  .  .  } | ||||
| 	//     40  .  .  .  .  .  .  .  } | ||||
| 	//     41  .  .  .  .  .  .  .  Ellipsis: - | ||||
| 	//     42  .  .  .  .  .  .  .  Rparen: 4:25 | ||||
| 	//     43  .  .  .  .  .  .  } | ||||
| 	//     44  .  .  .  .  .  } | ||||
| 	//     45  .  .  .  .  } | ||||
| 	//     46  .  .  .  .  Rbrace: 5:1 | ||||
| 	//     47  .  .  .  } | ||||
| 	//     48  .  .  } | ||||
| 	//     49  .  } | ||||
| 	//     50  .  Scope: *ast.Scope { | ||||
| 	//     51  .  .  Objects: map[string]*ast.Object (len = 1) { | ||||
| 	//     52  .  .  .  "main": *(obj @ 11) | ||||
| 	//     53  .  .  } | ||||
| 	//     54  .  } | ||||
| 	//     55  .  Unresolved: []*ast.Ident (len = 1) { | ||||
| 	//     56  .  .  0: *(obj @ 29) | ||||
| 	//     57  .  } | ||||
| 	//     58  } | ||||
| } | ||||
|  | ||||
| // This example illustrates how to remove a variable declaration | ||||
| // in a Go program while maintaining correct comment association | ||||
| // using an ast.CommentMap. | ||||
| func ExampleCommentMap() { | ||||
| 	// src is the input for which we create the AST that we | ||||
| 	// are going to manipulate. | ||||
| 	src := ` | ||||
| // This is the package comment. | ||||
| package main | ||||
|  | ||||
| // This comment is associated with the hello constant. | ||||
| const hello = "Hello, World!" // line comment 1 | ||||
|  | ||||
| // This comment is associated with the foo variable. | ||||
| var foo = hello // line comment 2  | ||||
|  | ||||
| // This comment is associated with the main function. | ||||
| func main() { | ||||
| 	fmt.Println(hello) // line comment 3 | ||||
| } | ||||
| ` | ||||
|  | ||||
| 	// Create the AST by parsing src. | ||||
| 	fset := token.NewFileSet() // positions are relative to fset | ||||
| 	f, err := parser.ParseFile(fset, "src.go", src, parser.ParseComments) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	// Create an ast.CommentMap from the ast.File's comments. | ||||
| 	// This helps keeping the association between comments | ||||
| 	// and AST nodes. | ||||
| 	cmap := ast.NewCommentMap(fset, f, f.Comments) | ||||
|  | ||||
| 	// Remove the first variable declaration from the list of declarations. | ||||
| 	f.Decls = removeFirstVarDecl(f.Decls) | ||||
|  | ||||
| 	// Use the comment map to filter comments that don't belong anymore | ||||
| 	// (the comments associated with the variable declaration), and create | ||||
| 	// the new comments list. | ||||
| 	f.Comments = cmap.Filter(f).Comments() | ||||
|  | ||||
| 	// Print the modified AST. | ||||
| 	var buf bytes.Buffer | ||||
| 	if err := format.Node(&buf, fset, f); err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	fmt.Printf("%s", buf.Bytes()) | ||||
|  | ||||
| 	// output: | ||||
| 	// // This is the package comment. | ||||
| 	// package main | ||||
| 	// | ||||
| 	// // This comment is associated with the hello constant. | ||||
| 	// const hello = "Hello, World!" // line comment 1 | ||||
| 	// | ||||
| 	// // This comment is associated with the main function. | ||||
| 	// func main() { | ||||
| 	// 	fmt.Println(hello) // line comment 3 | ||||
| 	// } | ||||
| } | ||||
|  | ||||
| func removeFirstVarDecl(list []ast.Decl) []ast.Decl { | ||||
| 	for i, decl := range list { | ||||
| 		if gen, ok := decl.(*ast.GenDecl); ok && gen.Tok == token.VAR { | ||||
| 			copy(list[i:], list[i+1:]) | ||||
| 			return list[:len(list)-1] | ||||
| 		} | ||||
| 	} | ||||
| 	panic("variable declaration not found") | ||||
| } | ||||
							
								
								
									
										465
									
								
								third_party/golang/go/ast/filter.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										465
									
								
								third_party/golang/go/ast/filter.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,465 @@ | ||||
| // Copyright 2009 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. | ||||
|  | ||||
| package ast | ||||
|  | ||||
| import ( | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"sort" | ||||
| ) | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Export filtering | ||||
|  | ||||
| // exportFilter is a special filter function to extract exported nodes. | ||||
| func exportFilter(name string) bool { | ||||
| 	return IsExported(name) | ||||
| } | ||||
|  | ||||
| // FileExports trims the AST for a Go source file in place such that | ||||
| // only exported nodes remain: all top-level identifiers which are not exported | ||||
| // and their associated information (such as type, initial value, or function | ||||
| // body) are removed. Non-exported fields and methods of exported types are | ||||
| // stripped. The File.Comments list is not changed. | ||||
| // | ||||
| // FileExports reports whether there are exported declarations. | ||||
| // | ||||
| func FileExports(src *File) bool { | ||||
| 	return filterFile(src, exportFilter, true) | ||||
| } | ||||
|  | ||||
| // PackageExports trims the AST for a Go package in place such that | ||||
| // only exported nodes remain. The pkg.Files list is not changed, so that | ||||
| // file names and top-level package comments don't get lost. | ||||
| // | ||||
| // PackageExports reports whether there are exported declarations; | ||||
| // it returns false otherwise. | ||||
| // | ||||
| func PackageExports(pkg *Package) bool { | ||||
| 	return filterPackage(pkg, exportFilter, true) | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // General filtering | ||||
|  | ||||
| type Filter func(string) bool | ||||
|  | ||||
| func filterIdentList(list []*Ident, f Filter) []*Ident { | ||||
| 	j := 0 | ||||
| 	for _, x := range list { | ||||
| 		if f(x.Name) { | ||||
| 			list[j] = x | ||||
| 			j++ | ||||
| 		} | ||||
| 	} | ||||
| 	return list[0:j] | ||||
| } | ||||
|  | ||||
| // fieldName assumes that x is the type of an anonymous field and | ||||
| // returns the corresponding field name. If x is not an acceptable | ||||
| // anonymous field, the result is nil. | ||||
| // | ||||
| func fieldName(x Expr) *Ident { | ||||
| 	switch t := x.(type) { | ||||
| 	case *Ident: | ||||
| 		return t | ||||
| 	case *SelectorExpr: | ||||
| 		if _, ok := t.X.(*Ident); ok { | ||||
| 			return t.Sel | ||||
| 		} | ||||
| 	case *StarExpr: | ||||
| 		return fieldName(t.X) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func filterFieldList(fields *FieldList, filter Filter, export bool) (removedFields bool) { | ||||
| 	if fields == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	list := fields.List | ||||
| 	j := 0 | ||||
| 	for _, f := range list { | ||||
| 		keepField := false | ||||
| 		if len(f.Names) == 0 { | ||||
| 			// anonymous field | ||||
| 			name := fieldName(f.Type) | ||||
| 			keepField = name != nil && filter(name.Name) | ||||
| 		} else { | ||||
| 			n := len(f.Names) | ||||
| 			f.Names = filterIdentList(f.Names, filter) | ||||
| 			if len(f.Names) < n { | ||||
| 				removedFields = true | ||||
| 			} | ||||
| 			keepField = len(f.Names) > 0 | ||||
| 		} | ||||
| 		if keepField { | ||||
| 			if export { | ||||
| 				filterType(f.Type, filter, export) | ||||
| 			} | ||||
| 			list[j] = f | ||||
| 			j++ | ||||
| 		} | ||||
| 	} | ||||
| 	if j < len(list) { | ||||
| 		removedFields = true | ||||
| 	} | ||||
| 	fields.List = list[0:j] | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func filterParamList(fields *FieldList, filter Filter, export bool) bool { | ||||
| 	if fields == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	var b bool | ||||
| 	for _, f := range fields.List { | ||||
| 		if filterType(f.Type, filter, export) { | ||||
| 			b = true | ||||
| 		} | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func filterType(typ Expr, f Filter, export bool) bool { | ||||
| 	switch t := typ.(type) { | ||||
| 	case *Ident: | ||||
| 		return f(t.Name) | ||||
| 	case *ParenExpr: | ||||
| 		return filterType(t.X, f, export) | ||||
| 	case *ArrayType: | ||||
| 		return filterType(t.Elt, f, export) | ||||
| 	case *StructType: | ||||
| 		if filterFieldList(t.Fields, f, export) { | ||||
| 			t.Incomplete = true | ||||
| 		} | ||||
| 		return len(t.Fields.List) > 0 | ||||
| 	case *FuncType: | ||||
| 		b1 := filterParamList(t.Params, f, export) | ||||
| 		b2 := filterParamList(t.Results, f, export) | ||||
| 		return b1 || b2 | ||||
| 	case *InterfaceType: | ||||
| 		if filterFieldList(t.Methods, f, export) { | ||||
| 			t.Incomplete = true | ||||
| 		} | ||||
| 		return len(t.Methods.List) > 0 | ||||
| 	case *MapType: | ||||
| 		b1 := filterType(t.Key, f, export) | ||||
| 		b2 := filterType(t.Value, f, export) | ||||
| 		return b1 || b2 | ||||
| 	case *ChanType: | ||||
| 		return filterType(t.Value, f, export) | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func filterSpec(spec Spec, f Filter, export bool) bool { | ||||
| 	switch s := spec.(type) { | ||||
| 	case *ValueSpec: | ||||
| 		s.Names = filterIdentList(s.Names, f) | ||||
| 		if len(s.Names) > 0 { | ||||
| 			if export { | ||||
| 				filterType(s.Type, f, export) | ||||
| 			} | ||||
| 			return true | ||||
| 		} | ||||
| 	case *TypeSpec: | ||||
| 		if f(s.Name.Name) { | ||||
| 			if export { | ||||
| 				filterType(s.Type, f, export) | ||||
| 			} | ||||
| 			return true | ||||
| 		} | ||||
| 		if !export { | ||||
| 			// For general filtering (not just exports), | ||||
| 			// filter type even if name is not filtered | ||||
| 			// out. | ||||
| 			// If the type contains filtered elements, | ||||
| 			// keep the declaration. | ||||
| 			return filterType(s.Type, f, export) | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func filterSpecList(list []Spec, f Filter, export bool) []Spec { | ||||
| 	j := 0 | ||||
| 	for _, s := range list { | ||||
| 		if filterSpec(s, f, export) { | ||||
| 			list[j] = s | ||||
| 			j++ | ||||
| 		} | ||||
| 	} | ||||
| 	return list[0:j] | ||||
| } | ||||
|  | ||||
| // FilterDecl trims the AST for a Go declaration in place by removing | ||||
| // all names (including struct field and interface method names, but | ||||
| // not from parameter lists) that don't pass through the filter f. | ||||
| // | ||||
| // FilterDecl reports whether there are any declared names left after | ||||
| // filtering. | ||||
| // | ||||
| func FilterDecl(decl Decl, f Filter) bool { | ||||
| 	return filterDecl(decl, f, false) | ||||
| } | ||||
|  | ||||
| func filterDecl(decl Decl, f Filter, export bool) bool { | ||||
| 	switch d := decl.(type) { | ||||
| 	case *GenDecl: | ||||
| 		d.Specs = filterSpecList(d.Specs, f, export) | ||||
| 		return len(d.Specs) > 0 | ||||
| 	case *FuncDecl: | ||||
| 		return f(d.Name.Name) | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // FilterFile trims the AST for a Go file in place by removing all | ||||
| // names from top-level declarations (including struct field and | ||||
| // interface method names, but not from parameter lists) that don't | ||||
| // pass through the filter f. If the declaration is empty afterwards, | ||||
| // the declaration is removed from the AST. Import declarations are | ||||
| // always removed. The File.Comments list is not changed. | ||||
| // | ||||
| // FilterFile reports whether there are any top-level declarations | ||||
| // left after filtering. | ||||
| // | ||||
| func FilterFile(src *File, f Filter) bool { | ||||
| 	return filterFile(src, f, false) | ||||
| } | ||||
|  | ||||
| func filterFile(src *File, f Filter, export bool) bool { | ||||
| 	j := 0 | ||||
| 	for _, d := range src.Decls { | ||||
| 		if filterDecl(d, f, export) { | ||||
| 			src.Decls[j] = d | ||||
| 			j++ | ||||
| 		} | ||||
| 	} | ||||
| 	src.Decls = src.Decls[0:j] | ||||
| 	return j > 0 | ||||
| } | ||||
|  | ||||
| // FilterPackage trims the AST for a Go package in place by removing | ||||
| // all names from top-level declarations (including struct field and | ||||
| // interface method names, but not from parameter lists) that don't | ||||
| // pass through the filter f. If the declaration is empty afterwards, | ||||
| // the declaration is removed from the AST. The pkg.Files list is not | ||||
| // changed, so that file names and top-level package comments don't get | ||||
| // lost. | ||||
| // | ||||
| // FilterPackage reports whether there are any top-level declarations | ||||
| // left after filtering. | ||||
| // | ||||
| func FilterPackage(pkg *Package, f Filter) bool { | ||||
| 	return filterPackage(pkg, f, false) | ||||
| } | ||||
|  | ||||
| func filterPackage(pkg *Package, f Filter, export bool) bool { | ||||
| 	hasDecls := false | ||||
| 	for _, src := range pkg.Files { | ||||
| 		if filterFile(src, f, export) { | ||||
| 			hasDecls = true | ||||
| 		} | ||||
| 	} | ||||
| 	return hasDecls | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Merging of package files | ||||
|  | ||||
| // The MergeMode flags control the behavior of MergePackageFiles. | ||||
| type MergeMode uint | ||||
|  | ||||
| const ( | ||||
| 	// If set, duplicate function declarations are excluded. | ||||
| 	FilterFuncDuplicates MergeMode = 1 << iota | ||||
| 	// If set, comments that are not associated with a specific | ||||
| 	// AST node (as Doc or Comment) are excluded. | ||||
| 	FilterUnassociatedComments | ||||
| 	// If set, duplicate import declarations are excluded. | ||||
| 	FilterImportDuplicates | ||||
| ) | ||||
|  | ||||
| // nameOf returns the function (foo) or method name (foo.bar) for | ||||
| // the given function declaration. If the AST is incorrect for the | ||||
| // receiver, it assumes a function instead. | ||||
| // | ||||
| func nameOf(f *FuncDecl) string { | ||||
| 	if r := f.Recv; r != nil && len(r.List) == 1 { | ||||
| 		// looks like a correct receiver declaration | ||||
| 		t := r.List[0].Type | ||||
| 		// dereference pointer receiver types | ||||
| 		if p, _ := t.(*StarExpr); p != nil { | ||||
| 			t = p.X | ||||
| 		} | ||||
| 		// the receiver type must be a type name | ||||
| 		if p, _ := t.(*Ident); p != nil { | ||||
| 			return p.Name + "." + f.Name.Name | ||||
| 		} | ||||
| 		// otherwise assume a function instead | ||||
| 	} | ||||
| 	return f.Name.Name | ||||
| } | ||||
|  | ||||
| // separator is an empty //-style comment that is interspersed between | ||||
| // different comment groups when they are concatenated into a single group | ||||
| // | ||||
| var separator = &Comment{token.NoPos, "//"} | ||||
|  | ||||
| // MergePackageFiles creates a file AST by merging the ASTs of the | ||||
| // files belonging to a package. The mode flags control merging behavior. | ||||
| // | ||||
| func MergePackageFiles(pkg *Package, mode MergeMode) *File { | ||||
| 	// Count the number of package docs, comments and declarations across | ||||
| 	// all package files. Also, compute sorted list of filenames, so that | ||||
| 	// subsequent iterations can always iterate in the same order. | ||||
| 	ndocs := 0 | ||||
| 	ncomments := 0 | ||||
| 	ndecls := 0 | ||||
| 	filenames := make([]string, len(pkg.Files)) | ||||
| 	i := 0 | ||||
| 	for filename, f := range pkg.Files { | ||||
| 		filenames[i] = filename | ||||
| 		i++ | ||||
| 		if f.Doc != nil { | ||||
| 			ndocs += len(f.Doc.List) + 1 // +1 for separator | ||||
| 		} | ||||
| 		ncomments += len(f.Comments) | ||||
| 		ndecls += len(f.Decls) | ||||
| 	} | ||||
| 	sort.Strings(filenames) | ||||
|  | ||||
| 	// Collect package comments from all package files into a single | ||||
| 	// CommentGroup - the collected package documentation. In general | ||||
| 	// there should be only one file with a package comment; but it's | ||||
| 	// better to collect extra comments than drop them on the floor. | ||||
| 	var doc *CommentGroup | ||||
| 	var pos token.Pos | ||||
| 	if ndocs > 0 { | ||||
| 		list := make([]*Comment, ndocs-1) // -1: no separator before first group | ||||
| 		i := 0 | ||||
| 		for _, filename := range filenames { | ||||
| 			f := pkg.Files[filename] | ||||
| 			if f.Doc != nil { | ||||
| 				if i > 0 { | ||||
| 					// not the first group - add separator | ||||
| 					list[i] = separator | ||||
| 					i++ | ||||
| 				} | ||||
| 				for _, c := range f.Doc.List { | ||||
| 					list[i] = c | ||||
| 					i++ | ||||
| 				} | ||||
| 				if f.Package > pos { | ||||
| 					// Keep the maximum package clause position as | ||||
| 					// position for the package clause of the merged | ||||
| 					// files. | ||||
| 					pos = f.Package | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		doc = &CommentGroup{list} | ||||
| 	} | ||||
|  | ||||
| 	// Collect declarations from all package files. | ||||
| 	var decls []Decl | ||||
| 	if ndecls > 0 { | ||||
| 		decls = make([]Decl, ndecls) | ||||
| 		funcs := make(map[string]int) // map of func name -> decls index | ||||
| 		i := 0                        // current index | ||||
| 		n := 0                        // number of filtered entries | ||||
| 		for _, filename := range filenames { | ||||
| 			f := pkg.Files[filename] | ||||
| 			for _, d := range f.Decls { | ||||
| 				if mode&FilterFuncDuplicates != 0 { | ||||
| 					// A language entity may be declared multiple | ||||
| 					// times in different package files; only at | ||||
| 					// build time declarations must be unique. | ||||
| 					// For now, exclude multiple declarations of | ||||
| 					// functions - keep the one with documentation. | ||||
| 					// | ||||
| 					// TODO(gri): Expand this filtering to other | ||||
| 					//            entities (const, type, vars) if | ||||
| 					//            multiple declarations are common. | ||||
| 					if f, isFun := d.(*FuncDecl); isFun { | ||||
| 						name := nameOf(f) | ||||
| 						if j, exists := funcs[name]; exists { | ||||
| 							// function declared already | ||||
| 							if decls[j] != nil && decls[j].(*FuncDecl).Doc == nil { | ||||
| 								// existing declaration has no documentation; | ||||
| 								// ignore the existing declaration | ||||
| 								decls[j] = nil | ||||
| 							} else { | ||||
| 								// ignore the new declaration | ||||
| 								d = nil | ||||
| 							} | ||||
| 							n++ // filtered an entry | ||||
| 						} else { | ||||
| 							funcs[name] = i | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				decls[i] = d | ||||
| 				i++ | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Eliminate nil entries from the decls list if entries were | ||||
| 		// filtered. We do this using a 2nd pass in order to not disturb | ||||
| 		// the original declaration order in the source (otherwise, this | ||||
| 		// would also invalidate the monotonically increasing position | ||||
| 		// info within a single file). | ||||
| 		if n > 0 { | ||||
| 			i = 0 | ||||
| 			for _, d := range decls { | ||||
| 				if d != nil { | ||||
| 					decls[i] = d | ||||
| 					i++ | ||||
| 				} | ||||
| 			} | ||||
| 			decls = decls[0:i] | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Collect import specs from all package files. | ||||
| 	var imports []*ImportSpec | ||||
| 	if mode&FilterImportDuplicates != 0 { | ||||
| 		seen := make(map[string]bool) | ||||
| 		for _, filename := range filenames { | ||||
| 			f := pkg.Files[filename] | ||||
| 			for _, imp := range f.Imports { | ||||
| 				if path := imp.Path.Value; !seen[path] { | ||||
| 					// TODO: consider handling cases where: | ||||
| 					// - 2 imports exist with the same import path but | ||||
| 					//   have different local names (one should probably | ||||
| 					//   keep both of them) | ||||
| 					// - 2 imports exist but only one has a comment | ||||
| 					// - 2 imports exist and they both have (possibly | ||||
| 					//   different) comments | ||||
| 					imports = append(imports, imp) | ||||
| 					seen[path] = true | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		for _, f := range pkg.Files { | ||||
| 			imports = append(imports, f.Imports...) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Collect comments from all package files. | ||||
| 	var comments []*CommentGroup | ||||
| 	if mode&FilterUnassociatedComments == 0 { | ||||
| 		comments = make([]*CommentGroup, ncomments) | ||||
| 		i := 0 | ||||
| 		for _, f := range pkg.Files { | ||||
| 			i += copy(comments[i:], f.Comments) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// TODO(gri) need to compute unresolved identifiers! | ||||
| 	return &File{doc, pos, NewIdent(pkg.Name), decls, pkg.Scope, imports, nil, comments} | ||||
| } | ||||
							
								
								
									
										86
									
								
								third_party/golang/go/ast/filter_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								third_party/golang/go/ast/filter_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| // Copyright 2013 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. | ||||
|  | ||||
| // To avoid a cyclic dependency with go/parser, this file is in a separate package. | ||||
|  | ||||
| package ast_test | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"go/ast" | ||||
| 	"go/format" | ||||
| 	"go/parser" | ||||
| 	"go/token" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| const input = `package p | ||||
|  | ||||
| type t1 struct{} | ||||
| type t2 struct{} | ||||
|  | ||||
| func f1() {} | ||||
| func f1() {} | ||||
| func f2() {} | ||||
|  | ||||
| func (*t1) f1() {} | ||||
| func (t1) f1() {} | ||||
| func (t1) f2() {} | ||||
|  | ||||
| func (t2) f1() {} | ||||
| func (t2) f2() {} | ||||
| func (x *t2) f2() {} | ||||
| ` | ||||
|  | ||||
| // Calling ast.MergePackageFiles with ast.FilterFuncDuplicates | ||||
| // keeps a duplicate entry with attached documentation in favor | ||||
| // of one without, and it favors duplicate entries appearing | ||||
| // later in the source over ones appearing earlier. This is why | ||||
| // (*t2).f2 is kept and t2.f2 is eliminated in this test case. | ||||
| // | ||||
| const golden = `package p | ||||
|  | ||||
| type t1 struct{} | ||||
| type t2 struct{} | ||||
|  | ||||
| func f1() {} | ||||
| func f2() {} | ||||
|  | ||||
| func (t1) f1() {} | ||||
| func (t1) f2() {} | ||||
|  | ||||
| func (t2) f1() {} | ||||
|  | ||||
| func (x *t2) f2() {} | ||||
| ` | ||||
|  | ||||
| func TestFilterDuplicates(t *testing.T) { | ||||
| 	// parse input | ||||
| 	fset := token.NewFileSet() | ||||
| 	file, err := parser.ParseFile(fset, "", input, 0) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// create package | ||||
| 	files := map[string]*ast.File{"": file} | ||||
| 	pkg, err := ast.NewPackage(fset, files, nil, nil) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// filter | ||||
| 	merged := ast.MergePackageFiles(pkg, ast.FilterFuncDuplicates) | ||||
|  | ||||
| 	// pretty-print | ||||
| 	var buf bytes.Buffer | ||||
| 	if err := format.Node(&buf, fset, merged); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	output := buf.String() | ||||
|  | ||||
| 	if output != golden { | ||||
| 		t.Errorf("incorrect output:\n%s", output) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										196
									
								
								third_party/golang/go/ast/import.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								third_party/golang/go/ast/import.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,196 @@ | ||||
| // Copyright 2011 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. | ||||
|  | ||||
| package ast | ||||
|  | ||||
| import ( | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // SortImports sorts runs of consecutive import lines in import blocks in f. | ||||
| // It also removes duplicate imports when it is possible to do so without data loss. | ||||
| func SortImports(fset *token.FileSet, f *File) { | ||||
| 	for _, d := range f.Decls { | ||||
| 		d, ok := d.(*GenDecl) | ||||
| 		if !ok || d.Tok != token.IMPORT { | ||||
| 			// Not an import declaration, so we're done. | ||||
| 			// Imports are always first. | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		if !d.Lparen.IsValid() { | ||||
| 			// Not a block: sorted by default. | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Identify and sort runs of specs on successive lines. | ||||
| 		i := 0 | ||||
| 		specs := d.Specs[:0] | ||||
| 		for j, s := range d.Specs { | ||||
| 			if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line { | ||||
| 				// j begins a new run.  End this one. | ||||
| 				specs = append(specs, sortSpecs(fset, f, d.Specs[i:j])...) | ||||
| 				i = j | ||||
| 			} | ||||
| 		} | ||||
| 		specs = append(specs, sortSpecs(fset, f, d.Specs[i:])...) | ||||
| 		d.Specs = specs | ||||
|  | ||||
| 		// Deduping can leave a blank line before the rparen; clean that up. | ||||
| 		if len(d.Specs) > 0 { | ||||
| 			lastSpec := d.Specs[len(d.Specs)-1] | ||||
| 			lastLine := fset.Position(lastSpec.Pos()).Line | ||||
| 			if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 { | ||||
| 				fset.File(d.Rparen).MergeLine(rParenLine - 1) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func importPath(s Spec) string { | ||||
| 	t, err := strconv.Unquote(s.(*ImportSpec).Path.Value) | ||||
| 	if err == nil { | ||||
| 		return t | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func importName(s Spec) string { | ||||
| 	n := s.(*ImportSpec).Name | ||||
| 	if n == nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return n.Name | ||||
| } | ||||
|  | ||||
| func importComment(s Spec) string { | ||||
| 	c := s.(*ImportSpec).Comment | ||||
| 	if c == nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return c.Text() | ||||
| } | ||||
|  | ||||
| // collapse indicates whether prev may be removed, leaving only next. | ||||
| func collapse(prev, next Spec) bool { | ||||
| 	if importPath(next) != importPath(prev) || importName(next) != importName(prev) { | ||||
| 		return false | ||||
| 	} | ||||
| 	return prev.(*ImportSpec).Comment == nil | ||||
| } | ||||
|  | ||||
| type posSpan struct { | ||||
| 	Start token.Pos | ||||
| 	End   token.Pos | ||||
| } | ||||
|  | ||||
| func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec { | ||||
| 	// Can't short-circuit here even if specs are already sorted, | ||||
| 	// since they might yet need deduplication. | ||||
| 	// A lone import, however, may be safely ignored. | ||||
| 	if len(specs) <= 1 { | ||||
| 		return specs | ||||
| 	} | ||||
|  | ||||
| 	// Record positions for specs. | ||||
| 	pos := make([]posSpan, len(specs)) | ||||
| 	for i, s := range specs { | ||||
| 		pos[i] = posSpan{s.Pos(), s.End()} | ||||
| 	} | ||||
|  | ||||
| 	// Identify comments in this range. | ||||
| 	// Any comment from pos[0].Start to the final line counts. | ||||
| 	lastLine := fset.Position(pos[len(pos)-1].End).Line | ||||
| 	cstart := len(f.Comments) | ||||
| 	cend := len(f.Comments) | ||||
| 	for i, g := range f.Comments { | ||||
| 		if g.Pos() < pos[0].Start { | ||||
| 			continue | ||||
| 		} | ||||
| 		if i < cstart { | ||||
| 			cstart = i | ||||
| 		} | ||||
| 		if fset.Position(g.End()).Line > lastLine { | ||||
| 			cend = i | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	comments := f.Comments[cstart:cend] | ||||
|  | ||||
| 	// Assign each comment to the import spec preceding it. | ||||
| 	importComment := map[*ImportSpec][]*CommentGroup{} | ||||
| 	specIndex := 0 | ||||
| 	for _, g := range comments { | ||||
| 		for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() { | ||||
| 			specIndex++ | ||||
| 		} | ||||
| 		s := specs[specIndex].(*ImportSpec) | ||||
| 		importComment[s] = append(importComment[s], g) | ||||
| 	} | ||||
|  | ||||
| 	// Sort the import specs by import path. | ||||
| 	// Remove duplicates, when possible without data loss. | ||||
| 	// Reassign the import paths to have the same position sequence. | ||||
| 	// Reassign each comment to abut the end of its spec. | ||||
| 	// Sort the comments by new position. | ||||
| 	sort.Sort(byImportSpec(specs)) | ||||
|  | ||||
| 	// Dedup. Thanks to our sorting, we can just consider | ||||
| 	// adjacent pairs of imports. | ||||
| 	deduped := specs[:0] | ||||
| 	for i, s := range specs { | ||||
| 		if i == len(specs)-1 || !collapse(s, specs[i+1]) { | ||||
| 			deduped = append(deduped, s) | ||||
| 		} else { | ||||
| 			p := s.Pos() | ||||
| 			fset.File(p).MergeLine(fset.Position(p).Line) | ||||
| 		} | ||||
| 	} | ||||
| 	specs = deduped | ||||
|  | ||||
| 	// Fix up comment positions | ||||
| 	for i, s := range specs { | ||||
| 		s := s.(*ImportSpec) | ||||
| 		if s.Name != nil { | ||||
| 			s.Name.NamePos = pos[i].Start | ||||
| 		} | ||||
| 		s.Path.ValuePos = pos[i].Start | ||||
| 		s.EndPos = pos[i].End | ||||
| 		for _, g := range importComment[s] { | ||||
| 			for _, c := range g.List { | ||||
| 				c.Slash = pos[i].End | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	sort.Sort(byCommentPos(comments)) | ||||
|  | ||||
| 	return specs | ||||
| } | ||||
|  | ||||
| type byImportSpec []Spec // slice of *ImportSpec | ||||
|  | ||||
| func (x byImportSpec) Len() int      { return len(x) } | ||||
| func (x byImportSpec) Swap(i, j int) { x[i], x[j] = x[j], x[i] } | ||||
| func (x byImportSpec) Less(i, j int) bool { | ||||
| 	ipath := importPath(x[i]) | ||||
| 	jpath := importPath(x[j]) | ||||
| 	if ipath != jpath { | ||||
| 		return ipath < jpath | ||||
| 	} | ||||
| 	iname := importName(x[i]) | ||||
| 	jname := importName(x[j]) | ||||
| 	if iname != jname { | ||||
| 		return iname < jname | ||||
| 	} | ||||
| 	return importComment(x[i]) < importComment(x[j]) | ||||
| } | ||||
|  | ||||
| type byCommentPos []*CommentGroup | ||||
|  | ||||
| func (x byCommentPos) Len() int           { return len(x) } | ||||
| func (x byCommentPos) Swap(i, j int)      { x[i], x[j] = x[j], x[i] } | ||||
| func (x byCommentPos) Less(i, j int) bool { return x[i].Pos() < x[j].Pos() } | ||||
							
								
								
									
										251
									
								
								third_party/golang/go/ast/print.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								third_party/golang/go/ast/print.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,251 @@ | ||||
| // Copyright 2010 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. | ||||
|  | ||||
| // This file contains printing support for ASTs. | ||||
|  | ||||
| package ast | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| ) | ||||
|  | ||||
| // A FieldFilter may be provided to Fprint to control the output. | ||||
| type FieldFilter func(name string, value reflect.Value) bool | ||||
|  | ||||
| // NotNilFilter returns true for field values that are not nil; | ||||
| // it returns false otherwise. | ||||
| func NotNilFilter(_ string, v reflect.Value) bool { | ||||
| 	switch v.Kind() { | ||||
| 	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: | ||||
| 		return !v.IsNil() | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // Fprint prints the (sub-)tree starting at AST node x to w. | ||||
| // If fset != nil, position information is interpreted relative | ||||
| // to that file set. Otherwise positions are printed as integer | ||||
| // values (file set specific offsets). | ||||
| // | ||||
| // A non-nil FieldFilter f may be provided to control the output: | ||||
| // struct fields for which f(fieldname, fieldvalue) is true are | ||||
| // printed; all others are filtered from the output. Unexported | ||||
| // struct fields are never printed. | ||||
| // | ||||
| func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (err error) { | ||||
| 	// setup printer | ||||
| 	p := printer{ | ||||
| 		output: w, | ||||
| 		fset:   fset, | ||||
| 		filter: f, | ||||
| 		ptrmap: make(map[interface{}]int), | ||||
| 		last:   '\n', // force printing of line number on first line | ||||
| 	} | ||||
|  | ||||
| 	// install error handler | ||||
| 	defer func() { | ||||
| 		if e := recover(); e != nil { | ||||
| 			err = e.(localError).err // re-panics if it's not a localError | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	// print x | ||||
| 	if x == nil { | ||||
| 		p.printf("nil\n") | ||||
| 		return | ||||
| 	} | ||||
| 	p.print(reflect.ValueOf(x)) | ||||
| 	p.printf("\n") | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Print prints x to standard output, skipping nil fields. | ||||
| // Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter). | ||||
| func Print(fset *token.FileSet, x interface{}) error { | ||||
| 	return Fprint(os.Stdout, fset, x, NotNilFilter) | ||||
| } | ||||
|  | ||||
| type printer struct { | ||||
| 	output io.Writer | ||||
| 	fset   *token.FileSet | ||||
| 	filter FieldFilter | ||||
| 	ptrmap map[interface{}]int // *T -> line number | ||||
| 	indent int                 // current indentation level | ||||
| 	last   byte                // the last byte processed by Write | ||||
| 	line   int                 // current line number | ||||
| } | ||||
|  | ||||
| var indent = []byte(".  ") | ||||
|  | ||||
| func (p *printer) Write(data []byte) (n int, err error) { | ||||
| 	var m int | ||||
| 	for i, b := range data { | ||||
| 		// invariant: data[0:n] has been written | ||||
| 		if b == '\n' { | ||||
| 			m, err = p.output.Write(data[n : i+1]) | ||||
| 			n += m | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 			p.line++ | ||||
| 		} else if p.last == '\n' { | ||||
| 			_, err = fmt.Fprintf(p.output, "%6d  ", p.line) | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 			for j := p.indent; j > 0; j-- { | ||||
| 				_, err = p.output.Write(indent) | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		p.last = b | ||||
| 	} | ||||
| 	if len(data) > n { | ||||
| 		m, err = p.output.Write(data[n:]) | ||||
| 		n += m | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // localError wraps locally caught errors so we can distinguish | ||||
| // them from genuine panics which we don't want to return as errors. | ||||
| type localError struct { | ||||
| 	err error | ||||
| } | ||||
|  | ||||
| // printf is a convenience wrapper that takes care of print errors. | ||||
| func (p *printer) printf(format string, args ...interface{}) { | ||||
| 	if _, err := fmt.Fprintf(p, format, args...); err != nil { | ||||
| 		panic(localError{err}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Implementation note: Print is written for AST nodes but could be | ||||
| // used to print arbitrary data structures; such a version should | ||||
| // probably be in a different package. | ||||
| // | ||||
| // Note: This code detects (some) cycles created via pointers but | ||||
| // not cycles that are created via slices or maps containing the | ||||
| // same slice or map. Code for general data structures probably | ||||
| // should catch those as well. | ||||
|  | ||||
| func (p *printer) print(x reflect.Value) { | ||||
| 	if !NotNilFilter("", x) { | ||||
| 		p.printf("nil") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch x.Kind() { | ||||
| 	case reflect.Interface: | ||||
| 		p.print(x.Elem()) | ||||
|  | ||||
| 	case reflect.Map: | ||||
| 		p.printf("%s (len = %d) {", x.Type(), x.Len()) | ||||
| 		if x.Len() > 0 { | ||||
| 			p.indent++ | ||||
| 			p.printf("\n") | ||||
| 			for _, key := range x.MapKeys() { | ||||
| 				p.print(key) | ||||
| 				p.printf(": ") | ||||
| 				p.print(x.MapIndex(key)) | ||||
| 				p.printf("\n") | ||||
| 			} | ||||
| 			p.indent-- | ||||
| 		} | ||||
| 		p.printf("}") | ||||
|  | ||||
| 	case reflect.Ptr: | ||||
| 		p.printf("*") | ||||
| 		// type-checked ASTs may contain cycles - use ptrmap | ||||
| 		// to keep track of objects that have been printed | ||||
| 		// already and print the respective line number instead | ||||
| 		ptr := x.Interface() | ||||
| 		if line, exists := p.ptrmap[ptr]; exists { | ||||
| 			p.printf("(obj @ %d)", line) | ||||
| 		} else { | ||||
| 			p.ptrmap[ptr] = p.line | ||||
| 			p.print(x.Elem()) | ||||
| 		} | ||||
|  | ||||
| 	case reflect.Array: | ||||
| 		p.printf("%s {", x.Type()) | ||||
| 		if x.Len() > 0 { | ||||
| 			p.indent++ | ||||
| 			p.printf("\n") | ||||
| 			for i, n := 0, x.Len(); i < n; i++ { | ||||
| 				p.printf("%d: ", i) | ||||
| 				p.print(x.Index(i)) | ||||
| 				p.printf("\n") | ||||
| 			} | ||||
| 			p.indent-- | ||||
| 		} | ||||
| 		p.printf("}") | ||||
|  | ||||
| 	case reflect.Slice: | ||||
| 		if s, ok := x.Interface().([]byte); ok { | ||||
| 			p.printf("%#q", s) | ||||
| 			return | ||||
| 		} | ||||
| 		p.printf("%s (len = %d) {", x.Type(), x.Len()) | ||||
| 		if x.Len() > 0 { | ||||
| 			p.indent++ | ||||
| 			p.printf("\n") | ||||
| 			for i, n := 0, x.Len(); i < n; i++ { | ||||
| 				p.printf("%d: ", i) | ||||
| 				p.print(x.Index(i)) | ||||
| 				p.printf("\n") | ||||
| 			} | ||||
| 			p.indent-- | ||||
| 		} | ||||
| 		p.printf("}") | ||||
|  | ||||
| 	case reflect.Struct: | ||||
| 		t := x.Type() | ||||
| 		p.printf("%s {", t) | ||||
| 		p.indent++ | ||||
| 		first := true | ||||
| 		for i, n := 0, t.NumField(); i < n; i++ { | ||||
| 			// exclude non-exported fields because their | ||||
| 			// values cannot be accessed via reflection | ||||
| 			if name := t.Field(i).Name; IsExported(name) { | ||||
| 				value := x.Field(i) | ||||
| 				if p.filter == nil || p.filter(name, value) { | ||||
| 					if first { | ||||
| 						p.printf("\n") | ||||
| 						first = false | ||||
| 					} | ||||
| 					p.printf("%s: ", name) | ||||
| 					p.print(value) | ||||
| 					p.printf("\n") | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		p.indent-- | ||||
| 		p.printf("}") | ||||
|  | ||||
| 	default: | ||||
| 		v := x.Interface() | ||||
| 		switch v := v.(type) { | ||||
| 		case string: | ||||
| 			// print strings in quotes | ||||
| 			p.printf("%q", v) | ||||
| 			return | ||||
| 		case token.Pos: | ||||
| 			// position values can be printed nicely if we have a file set | ||||
| 			if p.fset != nil { | ||||
| 				p.printf("%s", p.fset.Position(v)) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		// default | ||||
| 		p.printf("%v", v) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										97
									
								
								third_party/golang/go/ast/print_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								third_party/golang/go/ast/print_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| // Copyright 2011 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. | ||||
|  | ||||
| package ast | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| var tests = []struct { | ||||
| 	x interface{} // x is printed as s | ||||
| 	s string | ||||
| }{ | ||||
| 	// basic types | ||||
| 	{nil, "0  nil"}, | ||||
| 	{true, "0  true"}, | ||||
| 	{42, "0  42"}, | ||||
| 	{3.14, "0  3.14"}, | ||||
| 	{1 + 2.718i, "0  (1+2.718i)"}, | ||||
| 	{"foobar", "0  \"foobar\""}, | ||||
|  | ||||
| 	// maps | ||||
| 	{map[Expr]string{}, `0  map[ast.Expr]string (len = 0) {}`}, | ||||
| 	{map[string]int{"a": 1}, | ||||
| 		`0  map[string]int (len = 1) { | ||||
| 		1  .  "a": 1 | ||||
| 		2  }`}, | ||||
|  | ||||
| 	// pointers | ||||
| 	{new(int), "0  *0"}, | ||||
|  | ||||
| 	// arrays | ||||
| 	{[0]int{}, `0  [0]int {}`}, | ||||
| 	{[3]int{1, 2, 3}, | ||||
| 		`0  [3]int { | ||||
| 		1  .  0: 1 | ||||
| 		2  .  1: 2 | ||||
| 		3  .  2: 3 | ||||
| 		4  }`}, | ||||
| 	{[...]int{42}, | ||||
| 		`0  [1]int { | ||||
| 		1  .  0: 42 | ||||
| 		2  }`}, | ||||
|  | ||||
| 	// slices | ||||
| 	{[]int{}, `0  []int (len = 0) {}`}, | ||||
| 	{[]int{1, 2, 3}, | ||||
| 		`0  []int (len = 3) { | ||||
| 		1  .  0: 1 | ||||
| 		2  .  1: 2 | ||||
| 		3  .  2: 3 | ||||
| 		4  }`}, | ||||
|  | ||||
| 	// structs | ||||
| 	{struct{}{}, `0  struct {} {}`}, | ||||
| 	{struct{ x int }{007}, `0  struct { x int } {}`}, | ||||
| 	{struct{ X, y int }{42, 991}, | ||||
| 		`0  struct { X int; y int } { | ||||
| 		1  .  X: 42 | ||||
| 		2  }`}, | ||||
| 	{struct{ X, Y int }{42, 991}, | ||||
| 		`0  struct { X int; Y int } { | ||||
| 		1  .  X: 42 | ||||
| 		2  .  Y: 991 | ||||
| 		3  }`}, | ||||
| } | ||||
|  | ||||
| // Split s into lines, trim whitespace from all lines, and return | ||||
| // the concatenated non-empty lines. | ||||
| func trim(s string) string { | ||||
| 	lines := strings.Split(s, "\n") | ||||
| 	i := 0 | ||||
| 	for _, line := range lines { | ||||
| 		line = strings.TrimSpace(line) | ||||
| 		if line != "" { | ||||
| 			lines[i] = line | ||||
| 			i++ | ||||
| 		} | ||||
| 	} | ||||
| 	return strings.Join(lines[0:i], "\n") | ||||
| } | ||||
|  | ||||
| func TestPrint(t *testing.T) { | ||||
| 	var buf bytes.Buffer | ||||
| 	for _, test := range tests { | ||||
| 		buf.Reset() | ||||
| 		if err := Fprint(&buf, nil, test.x, nil); err != nil { | ||||
| 			t.Errorf("Fprint failed: %s", err) | ||||
| 		} | ||||
| 		if s, ts := trim(buf.String()), trim(test.s); s != ts { | ||||
| 			t.Errorf("got:\n%s\nexpected:\n%s\n", s, ts) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										174
									
								
								third_party/golang/go/ast/resolve.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								third_party/golang/go/ast/resolve.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | ||||
| // Copyright 2011 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. | ||||
|  | ||||
| // This file implements NewPackage. | ||||
|  | ||||
| package ast | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/scanner" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| type pkgBuilder struct { | ||||
| 	fset   *token.FileSet | ||||
| 	errors scanner.ErrorList | ||||
| } | ||||
|  | ||||
| func (p *pkgBuilder) error(pos token.Pos, msg string) { | ||||
| 	p.errors.Add(p.fset.Position(pos), msg) | ||||
| } | ||||
|  | ||||
| func (p *pkgBuilder) errorf(pos token.Pos, format string, args ...interface{}) { | ||||
| 	p.error(pos, fmt.Sprintf(format, args...)) | ||||
| } | ||||
|  | ||||
| func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) { | ||||
| 	alt := scope.Insert(obj) | ||||
| 	if alt == nil && altScope != nil { | ||||
| 		// see if there is a conflicting declaration in altScope | ||||
| 		alt = altScope.Lookup(obj.Name) | ||||
| 	} | ||||
| 	if alt != nil { | ||||
| 		prevDecl := "" | ||||
| 		if pos := alt.Pos(); pos.IsValid() { | ||||
| 			prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.fset.Position(pos)) | ||||
| 		} | ||||
| 		p.error(obj.Pos(), fmt.Sprintf("%s redeclared in this block%s", obj.Name, prevDecl)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func resolve(scope *Scope, ident *Ident) bool { | ||||
| 	for ; scope != nil; scope = scope.Outer { | ||||
| 		if obj := scope.Lookup(ident.Name); obj != nil { | ||||
| 			ident.Obj = obj | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // An Importer resolves import paths to package Objects. | ||||
| // The imports map records the packages already imported, | ||||
| // indexed by package id (canonical import path). | ||||
| // An Importer must determine the canonical import path and | ||||
| // check the map to see if it is already present in the imports map. | ||||
| // If so, the Importer can return the map entry.  Otherwise, the | ||||
| // Importer should load the package data for the given path into | ||||
| // a new *Object (pkg), record pkg in the imports map, and then | ||||
| // return pkg. | ||||
| type Importer func(imports map[string]*Object, path string) (pkg *Object, err error) | ||||
|  | ||||
| // NewPackage creates a new Package node from a set of File nodes. It resolves | ||||
| // unresolved identifiers across files and updates each file's Unresolved list | ||||
| // accordingly. If a non-nil importer and universe scope are provided, they are | ||||
| // used to resolve identifiers not declared in any of the package files. Any | ||||
| // remaining unresolved identifiers are reported as undeclared. If the files | ||||
| // belong to different packages, one package name is selected and files with | ||||
| // different package names are reported and then ignored. | ||||
| // The result is a package node and a scanner.ErrorList if there were errors. | ||||
| // | ||||
| func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, error) { | ||||
| 	var p pkgBuilder | ||||
| 	p.fset = fset | ||||
|  | ||||
| 	// complete package scope | ||||
| 	pkgName := "" | ||||
| 	pkgScope := NewScope(universe) | ||||
| 	for _, file := range files { | ||||
| 		// package names must match | ||||
| 		switch name := file.Name.Name; { | ||||
| 		case pkgName == "": | ||||
| 			pkgName = name | ||||
| 		case name != pkgName: | ||||
| 			p.errorf(file.Package, "package %s; expected %s", name, pkgName) | ||||
| 			continue // ignore this file | ||||
| 		} | ||||
|  | ||||
| 		// collect top-level file objects in package scope | ||||
| 		for _, obj := range file.Scope.Objects { | ||||
| 			p.declare(pkgScope, nil, obj) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// package global mapping of imported package ids to package objects | ||||
| 	imports := make(map[string]*Object) | ||||
|  | ||||
| 	// complete file scopes with imports and resolve identifiers | ||||
| 	for _, file := range files { | ||||
| 		// ignore file if it belongs to a different package | ||||
| 		// (error has already been reported) | ||||
| 		if file.Name.Name != pkgName { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// build file scope by processing all imports | ||||
| 		importErrors := false | ||||
| 		fileScope := NewScope(pkgScope) | ||||
| 		for _, spec := range file.Imports { | ||||
| 			if importer == nil { | ||||
| 				importErrors = true | ||||
| 				continue | ||||
| 			} | ||||
| 			path, _ := strconv.Unquote(spec.Path.Value) | ||||
| 			pkg, err := importer(imports, path) | ||||
| 			if err != nil { | ||||
| 				p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err) | ||||
| 				importErrors = true | ||||
| 				continue | ||||
| 			} | ||||
| 			// TODO(gri) If a local package name != "." is provided, | ||||
| 			// global identifier resolution could proceed even if the | ||||
| 			// import failed. Consider adjusting the logic here a bit. | ||||
|  | ||||
| 			// local name overrides imported package name | ||||
| 			name := pkg.Name | ||||
| 			if spec.Name != nil { | ||||
| 				name = spec.Name.Name | ||||
| 			} | ||||
|  | ||||
| 			// add import to file scope | ||||
| 			if name == "." { | ||||
| 				// merge imported scope with file scope | ||||
| 				for _, obj := range pkg.Data.(*Scope).Objects { | ||||
| 					p.declare(fileScope, pkgScope, obj) | ||||
| 				} | ||||
| 			} else if name != "_" { | ||||
| 				// declare imported package object in file scope | ||||
| 				// (do not re-use pkg in the file scope but create | ||||
| 				// a new object instead; the Decl field is different | ||||
| 				// for different files) | ||||
| 				obj := NewObj(Pkg, name) | ||||
| 				obj.Decl = spec | ||||
| 				obj.Data = pkg.Data | ||||
| 				p.declare(fileScope, pkgScope, obj) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// resolve identifiers | ||||
| 		if importErrors { | ||||
| 			// don't use the universe scope without correct imports | ||||
| 			// (objects in the universe may be shadowed by imports; | ||||
| 			// with missing imports, identifiers might get resolved | ||||
| 			// incorrectly to universe objects) | ||||
| 			pkgScope.Outer = nil | ||||
| 		} | ||||
| 		i := 0 | ||||
| 		for _, ident := range file.Unresolved { | ||||
| 			if !resolve(fileScope, ident) { | ||||
| 				p.errorf(ident.Pos(), "undeclared name: %s", ident.Name) | ||||
| 				file.Unresolved[i] = ident | ||||
| 				i++ | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
| 		file.Unresolved = file.Unresolved[0:i] | ||||
| 		pkgScope.Outer = universe // reset universe scope | ||||
| 	} | ||||
|  | ||||
| 	p.errors.Sort() | ||||
| 	return &Package{pkgName, pkgScope, imports, files}, p.errors.Err() | ||||
| } | ||||
							
								
								
									
										162
									
								
								third_party/golang/go/ast/scope.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								third_party/golang/go/ast/scope.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| // Copyright 2009 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. | ||||
|  | ||||
| // This file implements scopes and the objects they contain. | ||||
|  | ||||
| package ast | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| ) | ||||
|  | ||||
| // A Scope maintains the set of named language entities declared | ||||
| // in the scope and a link to the immediately surrounding (outer) | ||||
| // scope. | ||||
| // | ||||
| type Scope struct { | ||||
| 	Outer   *Scope | ||||
| 	Objects map[string]*Object | ||||
| } | ||||
|  | ||||
| // NewScope creates a new scope nested in the outer scope. | ||||
| func NewScope(outer *Scope) *Scope { | ||||
| 	const n = 4 // initial scope capacity | ||||
| 	return &Scope{outer, make(map[string]*Object, n)} | ||||
| } | ||||
|  | ||||
| // Lookup returns the object with the given name if it is | ||||
| // found in scope s, otherwise it returns nil. Outer scopes | ||||
| // are ignored. | ||||
| // | ||||
| func (s *Scope) Lookup(name string) *Object { | ||||
| 	return s.Objects[name] | ||||
| } | ||||
|  | ||||
| // Insert attempts to insert a named object obj into the scope s. | ||||
| // If the scope already contains an object alt with the same name, | ||||
| // Insert leaves the scope unchanged and returns alt. Otherwise | ||||
| // it inserts obj and returns nil. | ||||
| // | ||||
| func (s *Scope) Insert(obj *Object) (alt *Object) { | ||||
| 	if alt = s.Objects[obj.Name]; alt == nil { | ||||
| 		s.Objects[obj.Name] = obj | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Debugging support | ||||
| func (s *Scope) String() string { | ||||
| 	var buf bytes.Buffer | ||||
| 	fmt.Fprintf(&buf, "scope %p {", s) | ||||
| 	if s != nil && len(s.Objects) > 0 { | ||||
| 		fmt.Fprintln(&buf) | ||||
| 		for _, obj := range s.Objects { | ||||
| 			fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name) | ||||
| 		} | ||||
| 	} | ||||
| 	fmt.Fprintf(&buf, "}\n") | ||||
| 	return buf.String() | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Objects | ||||
|  | ||||
| // An Object describes a named language entity such as a package, | ||||
| // constant, type, variable, function (incl. methods), or label. | ||||
| // | ||||
| // The Data fields contains object-specific data: | ||||
| // | ||||
| //	Kind    Data type         Data value | ||||
| //	Pkg	*types.Package    package scope | ||||
| //	Con     int               iota for the respective declaration | ||||
| //	Con     != nil            constant value | ||||
| //	Typ     *Scope            (used as method scope during type checking - transient) | ||||
| // | ||||
| type Object struct { | ||||
| 	Kind ObjKind | ||||
| 	Name string      // declared name | ||||
| 	Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil | ||||
| 	Data interface{} // object-specific data; or nil | ||||
| 	Type interface{} // placeholder for type information; may be nil | ||||
| } | ||||
|  | ||||
| // NewObj creates a new object of a given kind and name. | ||||
| func NewObj(kind ObjKind, name string) *Object { | ||||
| 	return &Object{Kind: kind, Name: name} | ||||
| } | ||||
|  | ||||
| // Pos computes the source position of the declaration of an object name. | ||||
| // The result may be an invalid position if it cannot be computed | ||||
| // (obj.Decl may be nil or not correct). | ||||
| func (obj *Object) Pos() token.Pos { | ||||
| 	name := obj.Name | ||||
| 	switch d := obj.Decl.(type) { | ||||
| 	case *Field: | ||||
| 		for _, n := range d.Names { | ||||
| 			if n.Name == name { | ||||
| 				return n.Pos() | ||||
| 			} | ||||
| 		} | ||||
| 	case *ImportSpec: | ||||
| 		if d.Name != nil && d.Name.Name == name { | ||||
| 			return d.Name.Pos() | ||||
| 		} | ||||
| 		return d.Path.Pos() | ||||
| 	case *ValueSpec: | ||||
| 		for _, n := range d.Names { | ||||
| 			if n.Name == name { | ||||
| 				return n.Pos() | ||||
| 			} | ||||
| 		} | ||||
| 	case *TypeSpec: | ||||
| 		if d.Name.Name == name { | ||||
| 			return d.Name.Pos() | ||||
| 		} | ||||
| 	case *FuncDecl: | ||||
| 		if d.Name.Name == name { | ||||
| 			return d.Name.Pos() | ||||
| 		} | ||||
| 	case *LabeledStmt: | ||||
| 		if d.Label.Name == name { | ||||
| 			return d.Label.Pos() | ||||
| 		} | ||||
| 	case *AssignStmt: | ||||
| 		for _, x := range d.Lhs { | ||||
| 			if ident, isIdent := x.(*Ident); isIdent && ident.Name == name { | ||||
| 				return ident.Pos() | ||||
| 			} | ||||
| 		} | ||||
| 	case *Scope: | ||||
| 		// predeclared object - nothing to do for now | ||||
| 	} | ||||
| 	return token.NoPos | ||||
| } | ||||
|  | ||||
| // ObjKind describes what an object represents. | ||||
| type ObjKind int | ||||
|  | ||||
| // The list of possible Object kinds. | ||||
| const ( | ||||
| 	Bad ObjKind = iota // for error handling | ||||
| 	Pkg                // package | ||||
| 	Con                // constant | ||||
| 	Typ                // type | ||||
| 	Var                // variable | ||||
| 	Fun                // function or method | ||||
| 	Lbl                // label | ||||
| ) | ||||
|  | ||||
| var objKindStrings = [...]string{ | ||||
| 	Bad: "bad", | ||||
| 	Pkg: "package", | ||||
| 	Con: "const", | ||||
| 	Typ: "type", | ||||
| 	Var: "var", | ||||
| 	Fun: "func", | ||||
| 	Lbl: "label", | ||||
| } | ||||
|  | ||||
| func (kind ObjKind) String() string { return objKindStrings[kind] } | ||||
							
								
								
									
										386
									
								
								third_party/golang/go/ast/walk.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										386
									
								
								third_party/golang/go/ast/walk.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,386 @@ | ||||
| // Copyright 2009 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. | ||||
|  | ||||
| package ast | ||||
|  | ||||
| import "fmt" | ||||
|  | ||||
| // A Visitor's Visit method is invoked for each node encountered by Walk. | ||||
| // If the result visitor w is not nil, Walk visits each of the children | ||||
| // of node with the visitor w, followed by a call of w.Visit(nil). | ||||
| type Visitor interface { | ||||
| 	Visit(node Node) (w Visitor) | ||||
| } | ||||
|  | ||||
| // Helper functions for common node lists. They may be empty. | ||||
|  | ||||
| func walkIdentList(v Visitor, list []*Ident) { | ||||
| 	for _, x := range list { | ||||
| 		Walk(v, x) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func walkExprList(v Visitor, list []Expr) { | ||||
| 	for _, x := range list { | ||||
| 		Walk(v, x) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func walkStmtList(v Visitor, list []Stmt) { | ||||
| 	for _, x := range list { | ||||
| 		Walk(v, x) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func walkDeclList(v Visitor, list []Decl) { | ||||
| 	for _, x := range list { | ||||
| 		Walk(v, x) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // TODO(gri): Investigate if providing a closure to Walk leads to | ||||
| //            simpler use (and may help eliminate Inspect in turn). | ||||
|  | ||||
| // Walk traverses an AST in depth-first order: It starts by calling | ||||
| // v.Visit(node); node must not be nil. If the visitor w returned by | ||||
| // v.Visit(node) is not nil, Walk is invoked recursively with visitor | ||||
| // w for each of the non-nil children of node, followed by a call of | ||||
| // w.Visit(nil). | ||||
| // | ||||
| func Walk(v Visitor, node Node) { | ||||
| 	if v = v.Visit(node); v == nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// walk children | ||||
| 	// (the order of the cases matches the order | ||||
| 	// of the corresponding node types in ast.go) | ||||
| 	switch n := node.(type) { | ||||
| 	// Comments and fields | ||||
| 	case *Comment: | ||||
| 		// nothing to do | ||||
|  | ||||
| 	case *CommentGroup: | ||||
| 		for _, c := range n.List { | ||||
| 			Walk(v, c) | ||||
| 		} | ||||
|  | ||||
| 	case *Field: | ||||
| 		if n.Doc != nil { | ||||
| 			Walk(v, n.Doc) | ||||
| 		} | ||||
| 		walkIdentList(v, n.Names) | ||||
| 		Walk(v, n.Type) | ||||
| 		if n.Tag != nil { | ||||
| 			Walk(v, n.Tag) | ||||
| 		} | ||||
| 		if n.Comment != nil { | ||||
| 			Walk(v, n.Comment) | ||||
| 		} | ||||
|  | ||||
| 	case *FieldList: | ||||
| 		for _, f := range n.List { | ||||
| 			Walk(v, f) | ||||
| 		} | ||||
|  | ||||
| 	// Expressions | ||||
| 	case *BadExpr, *Ident, *BasicLit: | ||||
| 		// nothing to do | ||||
|  | ||||
| 	case *Ellipsis: | ||||
| 		if n.Elt != nil { | ||||
| 			Walk(v, n.Elt) | ||||
| 		} | ||||
|  | ||||
| 	case *FuncLit: | ||||
| 		Walk(v, n.Type) | ||||
| 		Walk(v, n.Body) | ||||
|  | ||||
| 	case *CompositeLit: | ||||
| 		if n.Type != nil { | ||||
| 			Walk(v, n.Type) | ||||
| 		} | ||||
| 		walkExprList(v, n.Elts) | ||||
|  | ||||
| 	case *ParenExpr: | ||||
| 		Walk(v, n.X) | ||||
|  | ||||
| 	case *SelectorExpr: | ||||
| 		Walk(v, n.X) | ||||
| 		Walk(v, n.Sel) | ||||
|  | ||||
| 	case *IndexExpr: | ||||
| 		Walk(v, n.X) | ||||
| 		Walk(v, n.Index) | ||||
|  | ||||
| 	case *SliceExpr: | ||||
| 		Walk(v, n.X) | ||||
| 		if n.Low != nil { | ||||
| 			Walk(v, n.Low) | ||||
| 		} | ||||
| 		if n.High != nil { | ||||
| 			Walk(v, n.High) | ||||
| 		} | ||||
| 		if n.Max != nil { | ||||
| 			Walk(v, n.Max) | ||||
| 		} | ||||
|  | ||||
| 	case *TypeAssertExpr: | ||||
| 		Walk(v, n.X) | ||||
| 		if n.Type != nil { | ||||
| 			Walk(v, n.Type) | ||||
| 		} | ||||
|  | ||||
| 	case *CallExpr: | ||||
| 		Walk(v, n.Fun) | ||||
| 		walkExprList(v, n.Args) | ||||
|  | ||||
| 	case *StarExpr: | ||||
| 		Walk(v, n.X) | ||||
|  | ||||
| 	case *UnaryExpr: | ||||
| 		Walk(v, n.X) | ||||
|  | ||||
| 	case *BinaryExpr: | ||||
| 		Walk(v, n.X) | ||||
| 		Walk(v, n.Y) | ||||
|  | ||||
| 	case *KeyValueExpr: | ||||
| 		Walk(v, n.Key) | ||||
| 		Walk(v, n.Value) | ||||
|  | ||||
| 	// Types | ||||
| 	case *ArrayType: | ||||
| 		if n.Len != nil { | ||||
| 			Walk(v, n.Len) | ||||
| 		} | ||||
| 		Walk(v, n.Elt) | ||||
|  | ||||
| 	case *StructType: | ||||
| 		Walk(v, n.Fields) | ||||
|  | ||||
| 	case *FuncType: | ||||
| 		if n.Params != nil { | ||||
| 			Walk(v, n.Params) | ||||
| 		} | ||||
| 		if n.Results != nil { | ||||
| 			Walk(v, n.Results) | ||||
| 		} | ||||
|  | ||||
| 	case *InterfaceType: | ||||
| 		Walk(v, n.Methods) | ||||
|  | ||||
| 	case *MapType: | ||||
| 		Walk(v, n.Key) | ||||
| 		Walk(v, n.Value) | ||||
|  | ||||
| 	case *ChanType: | ||||
| 		Walk(v, n.Value) | ||||
|  | ||||
| 	// Statements | ||||
| 	case *BadStmt: | ||||
| 		// nothing to do | ||||
|  | ||||
| 	case *DeclStmt: | ||||
| 		Walk(v, n.Decl) | ||||
|  | ||||
| 	case *EmptyStmt: | ||||
| 		// nothing to do | ||||
|  | ||||
| 	case *LabeledStmt: | ||||
| 		Walk(v, n.Label) | ||||
| 		Walk(v, n.Stmt) | ||||
|  | ||||
| 	case *ExprStmt: | ||||
| 		Walk(v, n.X) | ||||
|  | ||||
| 	case *SendStmt: | ||||
| 		Walk(v, n.Chan) | ||||
| 		Walk(v, n.Value) | ||||
|  | ||||
| 	case *IncDecStmt: | ||||
| 		Walk(v, n.X) | ||||
|  | ||||
| 	case *AssignStmt: | ||||
| 		walkExprList(v, n.Lhs) | ||||
| 		walkExprList(v, n.Rhs) | ||||
|  | ||||
| 	case *GoStmt: | ||||
| 		Walk(v, n.Call) | ||||
|  | ||||
| 	case *DeferStmt: | ||||
| 		Walk(v, n.Call) | ||||
|  | ||||
| 	case *ReturnStmt: | ||||
| 		walkExprList(v, n.Results) | ||||
|  | ||||
| 	case *BranchStmt: | ||||
| 		if n.Label != nil { | ||||
| 			Walk(v, n.Label) | ||||
| 		} | ||||
|  | ||||
| 	case *BlockStmt: | ||||
| 		walkStmtList(v, n.List) | ||||
|  | ||||
| 	case *IfStmt: | ||||
| 		if n.Init != nil { | ||||
| 			Walk(v, n.Init) | ||||
| 		} | ||||
| 		Walk(v, n.Cond) | ||||
| 		Walk(v, n.Body) | ||||
| 		if n.Else != nil { | ||||
| 			Walk(v, n.Else) | ||||
| 		} | ||||
|  | ||||
| 	case *CaseClause: | ||||
| 		walkExprList(v, n.List) | ||||
| 		walkStmtList(v, n.Body) | ||||
|  | ||||
| 	case *SwitchStmt: | ||||
| 		if n.Init != nil { | ||||
| 			Walk(v, n.Init) | ||||
| 		} | ||||
| 		if n.Tag != nil { | ||||
| 			Walk(v, n.Tag) | ||||
| 		} | ||||
| 		Walk(v, n.Body) | ||||
|  | ||||
| 	case *TypeSwitchStmt: | ||||
| 		if n.Init != nil { | ||||
| 			Walk(v, n.Init) | ||||
| 		} | ||||
| 		Walk(v, n.Assign) | ||||
| 		Walk(v, n.Body) | ||||
|  | ||||
| 	case *CommClause: | ||||
| 		if n.Comm != nil { | ||||
| 			Walk(v, n.Comm) | ||||
| 		} | ||||
| 		walkStmtList(v, n.Body) | ||||
|  | ||||
| 	case *SelectStmt: | ||||
| 		Walk(v, n.Body) | ||||
|  | ||||
| 	case *ForStmt: | ||||
| 		if n.Init != nil { | ||||
| 			Walk(v, n.Init) | ||||
| 		} | ||||
| 		if n.Cond != nil { | ||||
| 			Walk(v, n.Cond) | ||||
| 		} | ||||
| 		if n.Post != nil { | ||||
| 			Walk(v, n.Post) | ||||
| 		} | ||||
| 		Walk(v, n.Body) | ||||
|  | ||||
| 	case *RangeStmt: | ||||
| 		if n.Key != nil { | ||||
| 			Walk(v, n.Key) | ||||
| 		} | ||||
| 		if n.Value != nil { | ||||
| 			Walk(v, n.Value) | ||||
| 		} | ||||
| 		Walk(v, n.X) | ||||
| 		Walk(v, n.Body) | ||||
|  | ||||
| 	// Declarations | ||||
| 	case *ImportSpec: | ||||
| 		if n.Doc != nil { | ||||
| 			Walk(v, n.Doc) | ||||
| 		} | ||||
| 		if n.Name != nil { | ||||
| 			Walk(v, n.Name) | ||||
| 		} | ||||
| 		Walk(v, n.Path) | ||||
| 		if n.Comment != nil { | ||||
| 			Walk(v, n.Comment) | ||||
| 		} | ||||
|  | ||||
| 	case *ValueSpec: | ||||
| 		if n.Doc != nil { | ||||
| 			Walk(v, n.Doc) | ||||
| 		} | ||||
| 		walkIdentList(v, n.Names) | ||||
| 		if n.Type != nil { | ||||
| 			Walk(v, n.Type) | ||||
| 		} | ||||
| 		walkExprList(v, n.Values) | ||||
| 		if n.Comment != nil { | ||||
| 			Walk(v, n.Comment) | ||||
| 		} | ||||
|  | ||||
| 	case *TypeSpec: | ||||
| 		if n.Doc != nil { | ||||
| 			Walk(v, n.Doc) | ||||
| 		} | ||||
| 		Walk(v, n.Name) | ||||
| 		Walk(v, n.Type) | ||||
| 		if n.Comment != nil { | ||||
| 			Walk(v, n.Comment) | ||||
| 		} | ||||
|  | ||||
| 	case *BadDecl: | ||||
| 		// nothing to do | ||||
|  | ||||
| 	case *GenDecl: | ||||
| 		if n.Doc != nil { | ||||
| 			Walk(v, n.Doc) | ||||
| 		} | ||||
| 		for _, s := range n.Specs { | ||||
| 			Walk(v, s) | ||||
| 		} | ||||
|  | ||||
| 	case *FuncDecl: | ||||
| 		if n.Doc != nil { | ||||
| 			Walk(v, n.Doc) | ||||
| 		} | ||||
| 		if n.Recv != nil { | ||||
| 			Walk(v, n.Recv) | ||||
| 		} | ||||
| 		Walk(v, n.Name) | ||||
| 		Walk(v, n.Type) | ||||
| 		if n.Body != nil { | ||||
| 			Walk(v, n.Body) | ||||
| 		} | ||||
|  | ||||
| 	// Files and packages | ||||
| 	case *File: | ||||
| 		if n.Doc != nil { | ||||
| 			Walk(v, n.Doc) | ||||
| 		} | ||||
| 		Walk(v, n.Name) | ||||
| 		walkDeclList(v, n.Decls) | ||||
| 		// don't walk n.Comments - they have been | ||||
| 		// visited already through the individual | ||||
| 		// nodes | ||||
|  | ||||
| 	case *Package: | ||||
| 		for _, f := range n.Files { | ||||
| 			Walk(v, f) | ||||
| 		} | ||||
|  | ||||
| 	default: | ||||
| 		panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n)) | ||||
| 	} | ||||
|  | ||||
| 	v.Visit(nil) | ||||
| } | ||||
|  | ||||
| type inspector func(Node) bool | ||||
|  | ||||
| func (f inspector) Visit(node Node) Visitor { | ||||
| 	if f(node) { | ||||
| 		return f | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Inspect traverses an AST in depth-first order: It starts by calling | ||||
| // f(node); node must not be nil. If f returns true, Inspect invokes f | ||||
| // recursively for each of the non-nil children of node, followed by a | ||||
| // call of f(nil). | ||||
| // | ||||
| func Inspect(node Node, f func(Node) bool) { | ||||
| 	Walk(inspector(f), node) | ||||
| } | ||||
							
								
								
									
										1407
									
								
								third_party/golang/go/build/build.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1407
									
								
								third_party/golang/go/build/build.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										279
									
								
								third_party/golang/go/build/build_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								third_party/golang/go/build/build_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,279 @@ | ||||
| // Copyright 2011 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. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestMatch(t *testing.T) { | ||||
| 	ctxt := Default | ||||
| 	what := "default" | ||||
| 	match := func(tag string, want map[string]bool) { | ||||
| 		m := make(map[string]bool) | ||||
| 		if !ctxt.match(tag, m) { | ||||
| 			t.Errorf("%s context should match %s, does not", what, tag) | ||||
| 		} | ||||
| 		if !reflect.DeepEqual(m, want) { | ||||
| 			t.Errorf("%s tags = %v, want %v", tag, m, want) | ||||
| 		} | ||||
| 	} | ||||
| 	nomatch := func(tag string, want map[string]bool) { | ||||
| 		m := make(map[string]bool) | ||||
| 		if ctxt.match(tag, m) { | ||||
| 			t.Errorf("%s context should NOT match %s, does", what, tag) | ||||
| 		} | ||||
| 		if !reflect.DeepEqual(m, want) { | ||||
| 			t.Errorf("%s tags = %v, want %v", tag, m, want) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	match(runtime.GOOS+","+runtime.GOARCH, map[string]bool{runtime.GOOS: true, runtime.GOARCH: true}) | ||||
| 	match(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true}) | ||||
| 	nomatch(runtime.GOOS+","+runtime.GOARCH+",foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true}) | ||||
|  | ||||
| 	what = "modified" | ||||
| 	ctxt.BuildTags = []string{"foo"} | ||||
| 	match(runtime.GOOS+","+runtime.GOARCH, map[string]bool{runtime.GOOS: true, runtime.GOARCH: true}) | ||||
| 	match(runtime.GOOS+","+runtime.GOARCH+",foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true}) | ||||
| 	nomatch(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true}) | ||||
| 	match(runtime.GOOS+","+runtime.GOARCH+",!bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true}) | ||||
| 	nomatch(runtime.GOOS+","+runtime.GOARCH+",bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true}) | ||||
| 	nomatch("!", map[string]bool{}) | ||||
| } | ||||
|  | ||||
| func TestDotSlashImport(t *testing.T) { | ||||
| 	p, err := ImportDir("testdata/other", 0) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if len(p.Imports) != 1 || p.Imports[0] != "./file" { | ||||
| 		t.Fatalf("testdata/other: Imports=%v, want [./file]", p.Imports) | ||||
| 	} | ||||
|  | ||||
| 	p1, err := Import("./file", "testdata/other", 0) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if p1.Name != "file" { | ||||
| 		t.Fatalf("./file: Name=%q, want %q", p1.Name, "file") | ||||
| 	} | ||||
| 	dir := filepath.Clean("testdata/other/file") // Clean to use \ on Windows | ||||
| 	if p1.Dir != dir { | ||||
| 		t.Fatalf("./file: Dir=%q, want %q", p1.Name, dir) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestEmptyImport(t *testing.T) { | ||||
| 	p, err := Import("", Default.GOROOT, FindOnly) | ||||
| 	if err == nil { | ||||
| 		t.Fatal(`Import("") returned nil error.`) | ||||
| 	} | ||||
| 	if p == nil { | ||||
| 		t.Fatal(`Import("") returned nil package.`) | ||||
| 	} | ||||
| 	if p.ImportPath != "" { | ||||
| 		t.Fatalf("ImportPath=%q, want %q.", p.ImportPath, "") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestEmptyFolderImport(t *testing.T) { | ||||
| 	_, err := Import(".", "testdata/empty", 0) | ||||
| 	if _, ok := err.(*NoGoError); !ok { | ||||
| 		t.Fatal(`Import("testdata/empty") did not return NoGoError.`) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMultiplePackageImport(t *testing.T) { | ||||
| 	_, err := Import(".", "testdata/multi", 0) | ||||
| 	mpe, ok := err.(*MultiplePackageError) | ||||
| 	if !ok { | ||||
| 		t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`) | ||||
| 	} | ||||
| 	want := &MultiplePackageError{ | ||||
| 		Dir:      filepath.FromSlash("testdata/multi"), | ||||
| 		Packages: []string{"main", "test_package"}, | ||||
| 		Files:    []string{"file.go", "file_appengine.go"}, | ||||
| 	} | ||||
| 	if !reflect.DeepEqual(mpe, want) { | ||||
| 		t.Errorf("got %#v; want %#v", mpe, want) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestLocalDirectory(t *testing.T) { | ||||
| 	return // go1.3 not happy with this test. | ||||
| 	if runtime.GOOS == "darwin" { | ||||
| 		switch runtime.GOARCH { | ||||
| 		case "arm", "arm64": | ||||
| 			t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	cwd, err := os.Getwd() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	p, err := ImportDir(cwd, 0) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if p.ImportPath != "k8s.io/kubernetes/third_party/golang/go/build" { | ||||
| 		t.Fatalf("ImportPath=%q, want %q", p.ImportPath, "k8s.io/kubernetes/third_party/golang/go/build") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestShouldBuild(t *testing.T) { | ||||
| 	const file1 = "// +build tag1\n\n" + | ||||
| 		"package main\n" | ||||
| 	want1 := map[string]bool{"tag1": true} | ||||
|  | ||||
| 	const file2 = "// +build cgo\n\n" + | ||||
| 		"// This package implements parsing of tags like\n" + | ||||
| 		"// +build tag1\n" + | ||||
| 		"package build" | ||||
| 	want2 := map[string]bool{"cgo": true} | ||||
|  | ||||
| 	const file3 = "// Copyright The Go Authors.\n\n" + | ||||
| 		"package build\n\n" + | ||||
| 		"// shouldBuild checks tags given by lines of the form\n" + | ||||
| 		"// +build tag\n" + | ||||
| 		"func shouldBuild(content []byte)\n" | ||||
| 	want3 := map[string]bool{} | ||||
|  | ||||
| 	ctx := &Context{BuildTags: []string{"tag1"}} | ||||
| 	m := map[string]bool{} | ||||
| 	if !ctx.shouldBuild([]byte(file1), m) { | ||||
| 		t.Errorf("shouldBuild(file1) = false, want true") | ||||
| 	} | ||||
| 	if !reflect.DeepEqual(m, want1) { | ||||
| 		t.Errorf("shoudBuild(file1) tags = %v, want %v", m, want1) | ||||
| 	} | ||||
|  | ||||
| 	m = map[string]bool{} | ||||
| 	if ctx.shouldBuild([]byte(file2), m) { | ||||
| 		t.Errorf("shouldBuild(file2) = true, want fakse") | ||||
| 	} | ||||
| 	if !reflect.DeepEqual(m, want2) { | ||||
| 		t.Errorf("shoudBuild(file2) tags = %v, want %v", m, want2) | ||||
| 	} | ||||
|  | ||||
| 	m = map[string]bool{} | ||||
| 	ctx = &Context{BuildTags: nil} | ||||
| 	if !ctx.shouldBuild([]byte(file3), m) { | ||||
| 		t.Errorf("shouldBuild(file3) = false, want true") | ||||
| 	} | ||||
| 	if !reflect.DeepEqual(m, want3) { | ||||
| 		t.Errorf("shoudBuild(file3) tags = %v, want %v", m, want3) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type readNopCloser struct { | ||||
| 	io.Reader | ||||
| } | ||||
|  | ||||
| func (r readNopCloser) Close() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	ctxtP9      = Context{GOARCH: "arm", GOOS: "plan9"} | ||||
| 	ctxtAndroid = Context{GOARCH: "arm", GOOS: "android"} | ||||
| ) | ||||
|  | ||||
| var matchFileTests = []struct { | ||||
| 	ctxt  Context | ||||
| 	name  string | ||||
| 	data  string | ||||
| 	match bool | ||||
| }{ | ||||
| 	{ctxtP9, "foo_arm.go", "", true}, | ||||
| 	{ctxtP9, "foo1_arm.go", "// +build linux\n\npackage main\n", false}, | ||||
| 	{ctxtP9, "foo_darwin.go", "", false}, | ||||
| 	{ctxtP9, "foo.go", "", true}, | ||||
| 	{ctxtP9, "foo1.go", "// +build linux\n\npackage main\n", false}, | ||||
| 	{ctxtP9, "foo.badsuffix", "", false}, | ||||
| 	{ctxtAndroid, "foo_linux.go", "", true}, | ||||
| 	{ctxtAndroid, "foo_android.go", "", true}, | ||||
| 	{ctxtAndroid, "foo_plan9.go", "", false}, | ||||
| 	{ctxtAndroid, "android.go", "", true}, | ||||
| 	{ctxtAndroid, "plan9.go", "", true}, | ||||
| 	{ctxtAndroid, "plan9_test.go", "", true}, | ||||
| 	{ctxtAndroid, "arm.s", "", true}, | ||||
| 	{ctxtAndroid, "amd64.s", "", true}, | ||||
| } | ||||
|  | ||||
| func TestMatchFile(t *testing.T) { | ||||
| 	for _, tt := range matchFileTests { | ||||
| 		ctxt := tt.ctxt | ||||
| 		ctxt.OpenFile = func(path string) (r io.ReadCloser, err error) { | ||||
| 			if path != "x+"+tt.name { | ||||
| 				t.Fatalf("OpenFile asked for %q, expected %q", path, "x+"+tt.name) | ||||
| 			} | ||||
| 			return &readNopCloser{strings.NewReader(tt.data)}, nil | ||||
| 		} | ||||
| 		ctxt.JoinPath = func(elem ...string) string { | ||||
| 			return strings.Join(elem, "+") | ||||
| 		} | ||||
| 		match, err := ctxt.MatchFile("x", tt.name) | ||||
| 		if match != tt.match || err != nil { | ||||
| 			t.Fatalf("MatchFile(%q) = %v, %v, want %v, nil", tt.name, match, err, tt.match) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestImportCmd(t *testing.T) { | ||||
| 	return // go1.3 not happy with this test | ||||
| 	if runtime.GOOS == "darwin" { | ||||
| 		switch runtime.GOARCH { | ||||
| 		case "arm", "arm64": | ||||
| 			t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	p, err := Import("cmd/internal/objfile", "", 0) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if !strings.HasSuffix(filepath.ToSlash(p.Dir), "src/cmd/internal/objfile") { | ||||
| 		t.Fatalf("Import cmd/internal/objfile returned Dir=%q, want %q", filepath.ToSlash(p.Dir), ".../src/cmd/internal/objfile") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	expandSrcDirPath = filepath.Join(string(filepath.Separator)+"projects", "src", "add") | ||||
| ) | ||||
|  | ||||
| var expandSrcDirTests = []struct { | ||||
| 	input, expected string | ||||
| }{ | ||||
| 	{"-L ${SRCDIR}/libs -ladd", "-L /projects/src/add/libs -ladd"}, | ||||
| 	{"${SRCDIR}/add_linux_386.a -pthread -lstdc++", "/projects/src/add/add_linux_386.a -pthread -lstdc++"}, | ||||
| 	{"Nothing to expand here!", "Nothing to expand here!"}, | ||||
| 	{"$", "$"}, | ||||
| 	{"$$", "$$"}, | ||||
| 	{"${", "${"}, | ||||
| 	{"$}", "$}"}, | ||||
| 	{"$FOO ${BAR}", "$FOO ${BAR}"}, | ||||
| 	{"Find me the $SRCDIRECTORY.", "Find me the $SRCDIRECTORY."}, | ||||
| 	{"$SRCDIR is missing braces", "$SRCDIR is missing braces"}, | ||||
| } | ||||
|  | ||||
| func TestExpandSrcDir(t *testing.T) { | ||||
| 	for _, test := range expandSrcDirTests { | ||||
| 		output := expandSrcDir(test.input, expandSrcDirPath) | ||||
| 		if output != test.expected { | ||||
| 			t.Errorf("%q expands to %q with SRCDIR=%q when %q is expected", test.input, output, expandSrcDirPath, test.expected) | ||||
| 		} else { | ||||
| 			t.Logf("%q expands to %q with SRCDIR=%q", test.input, output, expandSrcDirPath) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										522
									
								
								third_party/golang/go/build/deps_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										522
									
								
								third_party/golang/go/build/deps_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,522 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // This file exercises the import parser but also checks that | ||||
| // some low-level packages do not have new dependencies added. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| // pkgDeps defines the expected dependencies between packages in | ||||
| // the Go source tree.  It is a statement of policy. | ||||
| // Changes should not be made to this map without prior discussion. | ||||
| // | ||||
| // The map contains two kinds of entries: | ||||
| // 1) Lower-case keys are standard import paths and list the | ||||
| // allowed imports in that package. | ||||
| // 2) Upper-case keys define aliases for package sets, which can then | ||||
| // be used as dependencies by other rules. | ||||
| // | ||||
| // DO NOT CHANGE THIS DATA TO FIX BUILDS. | ||||
| // | ||||
| var pkgDeps = map[string][]string{ | ||||
| 	// L0 is the lowest level, core, nearly unavoidable packages. | ||||
| 	"errors":      {}, | ||||
| 	"io":          {"errors", "sync"}, | ||||
| 	"runtime":     {"unsafe"}, | ||||
| 	"sync":        {"runtime", "sync/atomic", "unsafe"}, | ||||
| 	"sync/atomic": {"unsafe"}, | ||||
| 	"unsafe":      {}, | ||||
|  | ||||
| 	"L0": { | ||||
| 		"errors", | ||||
| 		"io", | ||||
| 		"runtime", | ||||
| 		"sync", | ||||
| 		"sync/atomic", | ||||
| 		"unsafe", | ||||
| 	}, | ||||
|  | ||||
| 	// L1 adds simple functions and strings processing, | ||||
| 	// but not Unicode tables. | ||||
| 	"math":          {"unsafe"}, | ||||
| 	"math/cmplx":    {"math"}, | ||||
| 	"math/rand":     {"L0", "math"}, | ||||
| 	"sort":          {}, | ||||
| 	"strconv":       {"L0", "unicode/utf8", "math"}, | ||||
| 	"unicode/utf16": {}, | ||||
| 	"unicode/utf8":  {}, | ||||
|  | ||||
| 	"L1": { | ||||
| 		"L0", | ||||
| 		"math", | ||||
| 		"math/cmplx", | ||||
| 		"math/rand", | ||||
| 		"sort", | ||||
| 		"strconv", | ||||
| 		"unicode/utf16", | ||||
| 		"unicode/utf8", | ||||
| 	}, | ||||
|  | ||||
| 	// L2 adds Unicode and strings processing. | ||||
| 	"bufio":   {"L0", "unicode/utf8", "bytes"}, | ||||
| 	"bytes":   {"L0", "unicode", "unicode/utf8"}, | ||||
| 	"path":    {"L0", "unicode/utf8", "strings"}, | ||||
| 	"strings": {"L0", "unicode", "unicode/utf8"}, | ||||
| 	"unicode": {}, | ||||
|  | ||||
| 	"L2": { | ||||
| 		"L1", | ||||
| 		"bufio", | ||||
| 		"bytes", | ||||
| 		"path", | ||||
| 		"strings", | ||||
| 		"unicode", | ||||
| 	}, | ||||
|  | ||||
| 	// L3 adds reflection and some basic utility packages | ||||
| 	// and interface definitions, but nothing that makes | ||||
| 	// system calls. | ||||
| 	"crypto":              {"L2", "hash"},          // interfaces | ||||
| 	"crypto/cipher":       {"L2", "crypto/subtle"}, // interfaces | ||||
| 	"crypto/subtle":       {}, | ||||
| 	"encoding/base32":     {"L2"}, | ||||
| 	"encoding/base64":     {"L2"}, | ||||
| 	"encoding/binary":     {"L2", "reflect"}, | ||||
| 	"hash":                {"L2"}, // interfaces | ||||
| 	"hash/adler32":        {"L2", "hash"}, | ||||
| 	"hash/crc32":          {"L2", "hash"}, | ||||
| 	"hash/crc64":          {"L2", "hash"}, | ||||
| 	"hash/fnv":            {"L2", "hash"}, | ||||
| 	"image":               {"L2", "image/color"}, // interfaces | ||||
| 	"image/color":         {"L2"},                // interfaces | ||||
| 	"image/color/palette": {"L2", "image/color"}, | ||||
| 	"reflect":             {"L2"}, | ||||
|  | ||||
| 	"L3": { | ||||
| 		"L2", | ||||
| 		"crypto", | ||||
| 		"crypto/cipher", | ||||
| 		"crypto/subtle", | ||||
| 		"encoding/base32", | ||||
| 		"encoding/base64", | ||||
| 		"encoding/binary", | ||||
| 		"hash", | ||||
| 		"hash/adler32", | ||||
| 		"hash/crc32", | ||||
| 		"hash/crc64", | ||||
| 		"hash/fnv", | ||||
| 		"image", | ||||
| 		"image/color", | ||||
| 		"image/color/palette", | ||||
| 		"reflect", | ||||
| 	}, | ||||
|  | ||||
| 	// End of linear dependency definitions. | ||||
|  | ||||
| 	// Operating system access. | ||||
| 	"syscall":                           {"L0", "unicode/utf16"}, | ||||
| 	"internal/syscall/unix":             {"L0", "syscall"}, | ||||
| 	"internal/syscall/windows":          {"L0", "syscall"}, | ||||
| 	"internal/syscall/windows/registry": {"L0", "syscall", "unicode/utf16"}, | ||||
| 	"time":             {"L0", "syscall", "internal/syscall/windows/registry"}, | ||||
| 	"os":               {"L1", "os", "syscall", "time", "internal/syscall/windows"}, | ||||
| 	"path/filepath":    {"L2", "os", "syscall"}, | ||||
| 	"io/ioutil":        {"L2", "os", "path/filepath", "time"}, | ||||
| 	"os/exec":          {"L2", "os", "path/filepath", "syscall"}, | ||||
| 	"os/signal":        {"L2", "os", "syscall"}, | ||||
| 	"internal/syscall": {"L2", "runtime", "syscall", "sync/atomic", "unsafe"}, | ||||
|  | ||||
| 	// OS enables basic operating system functionality, | ||||
| 	// but not direct use of package syscall, nor os/signal. | ||||
| 	"OS": { | ||||
| 		"io/ioutil", | ||||
| 		"os", | ||||
| 		"os/exec", | ||||
| 		"path/filepath", | ||||
| 		"time", | ||||
| 	}, | ||||
|  | ||||
| 	// Formatted I/O: few dependencies (L1) but we must add reflect. | ||||
| 	"fmt": {"L1", "os", "reflect"}, | ||||
| 	"log": {"L1", "os", "fmt", "time"}, | ||||
|  | ||||
| 	// Packages used by testing must be low-level (L2+fmt). | ||||
| 	"regexp":         {"L2", "regexp/syntax"}, | ||||
| 	"regexp/syntax":  {"L2"}, | ||||
| 	"runtime/debug":  {"L2", "fmt", "io/ioutil", "os", "time"}, | ||||
| 	"runtime/pprof":  {"L2", "fmt", "text/tabwriter"}, | ||||
| 	"runtime/trace":  {"L0"}, | ||||
| 	"text/tabwriter": {"L2"}, | ||||
|  | ||||
| 	"testing":          {"L2", "flag", "fmt", "os", "runtime/pprof", "runtime/trace", "time"}, | ||||
| 	"testing/iotest":   {"L2", "log"}, | ||||
| 	"testing/quick":    {"L2", "flag", "fmt", "reflect"}, | ||||
| 	"internal/testenv": {"L2", "os", "testing"}, | ||||
|  | ||||
| 	// L4 is defined as L3+fmt+log+time, because in general once | ||||
| 	// you're using L3 packages, use of fmt, log, or time is not a big deal. | ||||
| 	"L4": { | ||||
| 		"L3", | ||||
| 		"fmt", | ||||
| 		"log", | ||||
| 		"time", | ||||
| 	}, | ||||
|  | ||||
| 	// Go parser. | ||||
| 	"go/ast":     {"L4", "OS", "go/scanner", "go/token"}, | ||||
| 	"go/doc":     {"L4", "go/ast", "go/token", "regexp", "text/template"}, | ||||
| 	"go/parser":  {"L4", "OS", "go/ast", "go/scanner", "go/token"}, | ||||
| 	"go/printer": {"L4", "OS", "go/ast", "go/scanner", "go/token", "text/tabwriter"}, | ||||
| 	"go/scanner": {"L4", "OS", "go/token"}, | ||||
| 	"go/token":   {"L4"}, | ||||
|  | ||||
| 	"GOPARSER": { | ||||
| 		"go/ast", | ||||
| 		"go/doc", | ||||
| 		"go/parser", | ||||
| 		"go/printer", | ||||
| 		"go/scanner", | ||||
| 		"go/token", | ||||
| 	}, | ||||
|  | ||||
| 	"go/format":       {"L4", "GOPARSER", "internal/format"}, | ||||
| 	"internal/format": {"L4", "GOPARSER"}, | ||||
|  | ||||
| 	// Go type checking. | ||||
| 	"go/constant":               {"L4", "go/token", "math/big"}, | ||||
| 	"go/importer":               {"L4", "go/internal/gcimporter", "go/internal/gccgoimporter", "go/types"}, | ||||
| 	"go/internal/gcimporter":    {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"}, | ||||
| 	"go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "text/scanner"}, | ||||
| 	"go/types":                  {"L4", "GOPARSER", "container/heap", "go/constant"}, | ||||
|  | ||||
| 	// One of a kind. | ||||
| 	"archive/tar":              {"L4", "OS", "syscall"}, | ||||
| 	"archive/zip":              {"L4", "OS", "compress/flate"}, | ||||
| 	"container/heap":           {"sort"}, | ||||
| 	"compress/bzip2":           {"L4"}, | ||||
| 	"compress/flate":           {"L4"}, | ||||
| 	"compress/gzip":            {"L4", "compress/flate"}, | ||||
| 	"compress/lzw":             {"L4"}, | ||||
| 	"compress/zlib":            {"L4", "compress/flate"}, | ||||
| 	"database/sql":             {"L4", "container/list", "database/sql/driver"}, | ||||
| 	"database/sql/driver":      {"L4", "time"}, | ||||
| 	"debug/dwarf":              {"L4"}, | ||||
| 	"debug/elf":                {"L4", "OS", "debug/dwarf"}, | ||||
| 	"debug/gosym":              {"L4"}, | ||||
| 	"debug/macho":              {"L4", "OS", "debug/dwarf"}, | ||||
| 	"debug/pe":                 {"L4", "OS", "debug/dwarf"}, | ||||
| 	"debug/plan9obj":           {"L4", "OS"}, | ||||
| 	"encoding":                 {"L4"}, | ||||
| 	"encoding/ascii85":         {"L4"}, | ||||
| 	"encoding/asn1":            {"L4", "math/big"}, | ||||
| 	"encoding/csv":             {"L4"}, | ||||
| 	"encoding/gob":             {"L4", "OS", "encoding"}, | ||||
| 	"encoding/hex":             {"L4"}, | ||||
| 	"encoding/json":            {"L4", "encoding"}, | ||||
| 	"encoding/pem":             {"L4"}, | ||||
| 	"encoding/xml":             {"L4", "encoding"}, | ||||
| 	"flag":                     {"L4", "OS"}, | ||||
| 	"go/build":                 {"L4", "OS", "GOPARSER"}, | ||||
| 	"html":                     {"L4"}, | ||||
| 	"image/draw":               {"L4", "image/internal/imageutil"}, | ||||
| 	"image/gif":                {"L4", "compress/lzw", "image/color/palette", "image/draw"}, | ||||
| 	"image/internal/imageutil": {"L4"}, | ||||
| 	"image/jpeg":               {"L4", "image/internal/imageutil"}, | ||||
| 	"image/png":                {"L4", "compress/zlib"}, | ||||
| 	"index/suffixarray":        {"L4", "regexp"}, | ||||
| 	"internal/singleflight":    {"sync"}, | ||||
| 	"internal/trace":           {"L4", "OS"}, | ||||
| 	"math/big":                 {"L4"}, | ||||
| 	"mime":                     {"L4", "OS", "syscall", "internal/syscall/windows/registry"}, | ||||
| 	"mime/quotedprintable":     {"L4"}, | ||||
| 	"net/internal/socktest":    {"L4", "OS", "syscall"}, | ||||
| 	"net/url":                  {"L4"}, | ||||
| 	"text/scanner":             {"L4", "OS"}, | ||||
| 	"text/template/parse":      {"L4"}, | ||||
|  | ||||
| 	"html/template": { | ||||
| 		"L4", "OS", "encoding/json", "html", "text/template", | ||||
| 		"text/template/parse", | ||||
| 	}, | ||||
| 	"text/template": { | ||||
| 		"L4", "OS", "net/url", "text/template/parse", | ||||
| 	}, | ||||
|  | ||||
| 	// Cgo. | ||||
| 	"runtime/cgo": {"L0", "C"}, | ||||
| 	"CGO":         {"C", "runtime/cgo"}, | ||||
|  | ||||
| 	// Fake entry to satisfy the pseudo-import "C" | ||||
| 	// that shows up in programs that use cgo. | ||||
| 	"C": {}, | ||||
|  | ||||
| 	// Race detector uses cgo. | ||||
| 	"runtime/race": {"C"}, | ||||
|  | ||||
| 	// Plan 9 alone needs io/ioutil and os. | ||||
| 	"os/user": {"L4", "CGO", "io/ioutil", "os", "syscall"}, | ||||
|  | ||||
| 	// Basic networking. | ||||
| 	// Because net must be used by any package that wants to | ||||
| 	// do networking portably, it must have a small dependency set: just L1+basic os. | ||||
| 	"net": {"L1", "CGO", "os", "syscall", "time", "internal/syscall/windows", "internal/singleflight"}, | ||||
|  | ||||
| 	// NET enables use of basic network-related packages. | ||||
| 	"NET": { | ||||
| 		"net", | ||||
| 		"mime", | ||||
| 		"net/textproto", | ||||
| 		"net/url", | ||||
| 	}, | ||||
|  | ||||
| 	// Uses of networking. | ||||
| 	"log/syslog":    {"L4", "OS", "net"}, | ||||
| 	"net/mail":      {"L4", "NET", "OS", "mime"}, | ||||
| 	"net/textproto": {"L4", "OS", "net"}, | ||||
|  | ||||
| 	// Core crypto. | ||||
| 	"crypto/aes":    {"L3"}, | ||||
| 	"crypto/des":    {"L3"}, | ||||
| 	"crypto/hmac":   {"L3"}, | ||||
| 	"crypto/md5":    {"L3"}, | ||||
| 	"crypto/rc4":    {"L3"}, | ||||
| 	"crypto/sha1":   {"L3"}, | ||||
| 	"crypto/sha256": {"L3"}, | ||||
| 	"crypto/sha512": {"L3"}, | ||||
|  | ||||
| 	"CRYPTO": { | ||||
| 		"crypto/aes", | ||||
| 		"crypto/des", | ||||
| 		"crypto/hmac", | ||||
| 		"crypto/md5", | ||||
| 		"crypto/rc4", | ||||
| 		"crypto/sha1", | ||||
| 		"crypto/sha256", | ||||
| 		"crypto/sha512", | ||||
| 	}, | ||||
|  | ||||
| 	// Random byte, number generation. | ||||
| 	// This would be part of core crypto except that it imports | ||||
| 	// math/big, which imports fmt. | ||||
| 	"crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall/unix", "internal/syscall"}, | ||||
|  | ||||
| 	// Mathematical crypto: dependencies on fmt (L4) and math/big. | ||||
| 	// We could avoid some of the fmt, but math/big imports fmt anyway. | ||||
| 	"crypto/dsa":      {"L4", "CRYPTO", "math/big"}, | ||||
| 	"crypto/ecdsa":    {"L4", "CRYPTO", "crypto/elliptic", "math/big", "encoding/asn1"}, | ||||
| 	"crypto/elliptic": {"L4", "CRYPTO", "math/big"}, | ||||
| 	"crypto/rsa":      {"L4", "CRYPTO", "crypto/rand", "math/big"}, | ||||
|  | ||||
| 	"CRYPTO-MATH": { | ||||
| 		"CRYPTO", | ||||
| 		"crypto/dsa", | ||||
| 		"crypto/ecdsa", | ||||
| 		"crypto/elliptic", | ||||
| 		"crypto/rand", | ||||
| 		"crypto/rsa", | ||||
| 		"encoding/asn1", | ||||
| 		"math/big", | ||||
| 	}, | ||||
|  | ||||
| 	// SSL/TLS. | ||||
| 	"crypto/tls": { | ||||
| 		"L4", "CRYPTO-MATH", "CGO", "OS", | ||||
| 		"container/list", "crypto/x509", "encoding/pem", "net", "syscall", | ||||
| 	}, | ||||
| 	"crypto/x509": { | ||||
| 		"L4", "CRYPTO-MATH", "OS", "CGO", | ||||
| 		"crypto/x509/pkix", "encoding/pem", "encoding/hex", "net", "syscall", | ||||
| 	}, | ||||
| 	"crypto/x509/pkix": {"L4", "CRYPTO-MATH"}, | ||||
|  | ||||
| 	// Simple net+crypto-aware packages. | ||||
| 	"mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto", "mime/quotedprintable"}, | ||||
| 	"net/smtp":       {"L4", "CRYPTO", "NET", "crypto/tls"}, | ||||
|  | ||||
| 	// HTTP, kingpin of dependencies. | ||||
| 	"net/http": { | ||||
| 		"L4", "NET", "OS", | ||||
| 		"compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug", | ||||
| 		"net/http/internal", | ||||
| 	}, | ||||
| 	"net/http/internal": {"L4"}, | ||||
|  | ||||
| 	// HTTP-using packages. | ||||
| 	"expvar":             {"L4", "OS", "encoding/json", "net/http"}, | ||||
| 	"net/http/cgi":       {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"}, | ||||
| 	"net/http/cookiejar": {"L4", "NET", "net/http"}, | ||||
| 	"net/http/fcgi":      {"L4", "NET", "OS", "net/http", "net/http/cgi"}, | ||||
| 	"net/http/httptest":  {"L4", "NET", "OS", "crypto/tls", "flag", "net/http"}, | ||||
| 	"net/http/httputil":  {"L4", "NET", "OS", "net/http", "net/http/internal"}, | ||||
| 	"net/http/pprof":     {"L4", "OS", "html/template", "net/http", "runtime/pprof", "runtime/trace"}, | ||||
| 	"net/rpc":            {"L4", "NET", "encoding/gob", "html/template", "net/http"}, | ||||
| 	"net/rpc/jsonrpc":    {"L4", "NET", "encoding/json", "net/rpc"}, | ||||
| } | ||||
|  | ||||
| // isMacro reports whether p is a package dependency macro | ||||
| // (uppercase name). | ||||
| func isMacro(p string) bool { | ||||
| 	return 'A' <= p[0] && p[0] <= 'Z' | ||||
| } | ||||
|  | ||||
| func allowed(pkg string) map[string]bool { | ||||
| 	m := map[string]bool{} | ||||
| 	var allow func(string) | ||||
| 	allow = func(p string) { | ||||
| 		if m[p] { | ||||
| 			return | ||||
| 		} | ||||
| 		m[p] = true // set even for macros, to avoid loop on cycle | ||||
|  | ||||
| 		// Upper-case names are macro-expanded. | ||||
| 		if isMacro(p) { | ||||
| 			for _, pp := range pkgDeps[p] { | ||||
| 				allow(pp) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	for _, pp := range pkgDeps[pkg] { | ||||
| 		allow(pp) | ||||
| 	} | ||||
| 	return m | ||||
| } | ||||
|  | ||||
| var bools = []bool{false, true} | ||||
| var geese = []string{"android", "darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows"} | ||||
| var goarches = []string{"386", "amd64", "arm"} | ||||
|  | ||||
| type osPkg struct { | ||||
| 	goos, pkg string | ||||
| } | ||||
|  | ||||
| // allowedErrors are the operating systems and packages known to contain errors | ||||
| // (currently just "no Go source files") | ||||
| var allowedErrors = map[osPkg]bool{ | ||||
| 	osPkg{"windows", "log/syslog"}: true, | ||||
| 	osPkg{"plan9", "log/syslog"}:   true, | ||||
| } | ||||
|  | ||||
| // listStdPkgs returns the same list of packages as "go list std". | ||||
| func listStdPkgs(goroot string) ([]string, error) { | ||||
| 	// Based on cmd/go's matchPackages function. | ||||
| 	var pkgs []string | ||||
|  | ||||
| 	src := filepath.Join(goroot, "src") + string(filepath.Separator) | ||||
| 	walkFn := func(path string, fi os.FileInfo, err error) error { | ||||
| 		if err != nil || !fi.IsDir() || path == src { | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		base := filepath.Base(path) | ||||
| 		if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" { | ||||
| 			return filepath.SkipDir | ||||
| 		} | ||||
|  | ||||
| 		name := filepath.ToSlash(path[len(src):]) | ||||
| 		if name == "builtin" || name == "cmd" || strings.Contains(name, ".") { | ||||
| 			return filepath.SkipDir | ||||
| 		} | ||||
|  | ||||
| 		pkgs = append(pkgs, name) | ||||
| 		return nil | ||||
| 	} | ||||
| 	if err := filepath.Walk(src, walkFn); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return pkgs, nil | ||||
| } | ||||
|  | ||||
| func TestDependencies(t *testing.T) { | ||||
| 	return // go1.3 is really not happy with this test | ||||
| 	iOS := runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") | ||||
| 	if runtime.GOOS == "nacl" || iOS { | ||||
| 		// Tests run in a limited file system and we do not | ||||
| 		// provide access to every source file. | ||||
| 		t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH) | ||||
| 	} | ||||
|  | ||||
| 	ctxt := Default | ||||
| 	all, err := listStdPkgs(ctxt.GOROOT) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	sort.Strings(all) | ||||
|  | ||||
| 	test := func(mustImport bool) { | ||||
| 		for _, pkg := range all { | ||||
| 			imports, err := findImports(pkg) | ||||
| 			if err != nil { | ||||
| 				t.Error(err) | ||||
| 				continue | ||||
| 			} | ||||
| 			ok := allowed(pkg) | ||||
| 			var bad []string | ||||
| 			for _, imp := range imports { | ||||
| 				if !ok[imp] { | ||||
| 					bad = append(bad, imp) | ||||
| 				} | ||||
| 			} | ||||
| 			if bad != nil { | ||||
| 				t.Errorf("unexpected dependency: %s imports %v", pkg, bad) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	test(true) | ||||
| } | ||||
|  | ||||
| var buildIgnore = []byte("\n// +build ignore") | ||||
|  | ||||
| func findImports(pkg string) ([]string, error) { | ||||
| 	dir := filepath.Join(Default.GOROOT, "src", pkg) | ||||
| 	files, err := ioutil.ReadDir(dir) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var imports []string | ||||
| 	var haveImport = map[string]bool{} | ||||
| 	for _, file := range files { | ||||
| 		name := file.Name() | ||||
| 		if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") { | ||||
| 			continue | ||||
| 		} | ||||
| 		f, err := os.Open(filepath.Join(dir, name)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		var imp []string | ||||
| 		data, err := readImports(f, false, &imp) | ||||
| 		f.Close() | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("reading %v: %v", name, err) | ||||
| 		} | ||||
| 		if bytes.Contains(data, buildIgnore) { | ||||
| 			continue | ||||
| 		} | ||||
| 		for _, quoted := range imp { | ||||
| 			path, err := strconv.Unquote(quoted) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			if !haveImport[path] { | ||||
| 				haveImport[path] = true | ||||
| 				imports = append(imports, path) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	sort.Strings(imports) | ||||
| 	return imports, nil | ||||
| } | ||||
							
								
								
									
										140
									
								
								third_party/golang/go/build/doc.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								third_party/golang/go/build/doc.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,140 @@ | ||||
| // Copyright 2011 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. | ||||
|  | ||||
| // Package build gathers information about Go packages. | ||||
| // | ||||
| // Go Path | ||||
| // | ||||
| // The Go path is a list of directory trees containing Go source code. | ||||
| // It is consulted to resolve imports that cannot be found in the standard | ||||
| // Go tree.  The default path is the value of the GOPATH environment | ||||
| // variable, interpreted as a path list appropriate to the operating system | ||||
| // (on Unix, the variable is a colon-separated string; | ||||
| // on Windows, a semicolon-separated string; | ||||
| // on Plan 9, a list). | ||||
| // | ||||
| // Each directory listed in the Go path must have a prescribed structure: | ||||
| // | ||||
| // The src/ directory holds source code.  The path below 'src' determines | ||||
| // the import path or executable name. | ||||
| // | ||||
| // The pkg/ directory holds installed package objects. | ||||
| // As in the Go tree, each target operating system and | ||||
| // architecture pair has its own subdirectory of pkg | ||||
| // (pkg/GOOS_GOARCH). | ||||
| // | ||||
| // If DIR is a directory listed in the Go path, a package with | ||||
| // source in DIR/src/foo/bar can be imported as "foo/bar" and | ||||
| // has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a" | ||||
| // (or, for gccgo, "DIR/pkg/gccgo/foo/libbar.a"). | ||||
| // | ||||
| // The bin/ directory holds compiled commands. | ||||
| // Each command is named for its source directory, but only | ||||
| // using the final element, not the entire path.  That is, the | ||||
| // command with source in DIR/src/foo/quux is installed into | ||||
| // DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped | ||||
| // so that you can add DIR/bin to your PATH to get at the | ||||
| // installed commands. | ||||
| // | ||||
| // Here's an example directory layout: | ||||
| // | ||||
| //	GOPATH=/home/user/gocode | ||||
| // | ||||
| //	/home/user/gocode/ | ||||
| //	    src/ | ||||
| //	        foo/ | ||||
| //	            bar/               (go code in package bar) | ||||
| //	                x.go | ||||
| //	            quux/              (go code in package main) | ||||
| //	                y.go | ||||
| //	    bin/ | ||||
| //	        quux                   (installed command) | ||||
| //	    pkg/ | ||||
| //	        linux_amd64/ | ||||
| //	            foo/ | ||||
| //	                bar.a          (installed package object) | ||||
| // | ||||
| // Build Constraints | ||||
| // | ||||
| // A build constraint, also known as a build tag, is a line comment that begins | ||||
| // | ||||
| //	// +build | ||||
| // | ||||
| // that lists the conditions under which a file should be included in the package. | ||||
| // Constraints may appear in any kind of source file (not just Go), but | ||||
| // they must appear near the top of the file, preceded | ||||
| // only by blank lines and other line comments. These rules mean that in Go | ||||
| // files a build constraint must appear before the package clause. | ||||
| // | ||||
| // To distinguish build constraints from package documentation, a series of | ||||
| // build constraints must be followed by a blank line. | ||||
| // | ||||
| // A build constraint is evaluated as the OR of space-separated options; | ||||
| // each option evaluates as the AND of its comma-separated terms; | ||||
| // and each term is an alphanumeric word or, preceded by !, its negation. | ||||
| // That is, the build constraint: | ||||
| // | ||||
| //	// +build linux,386 darwin,!cgo | ||||
| // | ||||
| // corresponds to the boolean formula: | ||||
| // | ||||
| //	(linux AND 386) OR (darwin AND (NOT cgo)) | ||||
| // | ||||
| // A file may have multiple build constraints. The overall constraint is the AND | ||||
| // of the individual constraints. That is, the build constraints: | ||||
| // | ||||
| //	// +build linux darwin | ||||
| //	// +build 386 | ||||
| // | ||||
| // corresponds to the boolean formula: | ||||
| // | ||||
| //	(linux OR darwin) AND 386 | ||||
| // | ||||
| // During a particular build, the following words are satisfied: | ||||
| // | ||||
| //	- the target operating system, as spelled by runtime.GOOS | ||||
| //	- the target architecture, as spelled by runtime.GOARCH | ||||
| //	- the compiler being used, either "gc" or "gccgo" | ||||
| //	- "cgo", if ctxt.CgoEnabled is true | ||||
| //	- "go1.1", from Go version 1.1 onward | ||||
| //	- "go1.2", from Go version 1.2 onward | ||||
| //	- "go1.3", from Go version 1.3 onward | ||||
| //	- "go1.4", from Go version 1.4 onward | ||||
| //	- "go1.5", from Go version 1.5 onward | ||||
| //	- any additional words listed in ctxt.BuildTags | ||||
| // | ||||
| // If a file's name, after stripping the extension and a possible _test suffix, | ||||
| // matches any of the following patterns: | ||||
| //	*_GOOS | ||||
| // 	*_GOARCH | ||||
| // 	*_GOOS_GOARCH | ||||
| // (example: source_windows_amd64.go) where GOOS and GOARCH represent | ||||
| // any known operating system and architecture values respectively, then | ||||
| // the file is considered to have an implicit build constraint requiring | ||||
| // those terms (in addition to any explicit constraints in the file). | ||||
| // | ||||
| // To keep a file from being considered for the build: | ||||
| // | ||||
| //	// +build ignore | ||||
| // | ||||
| // (any other unsatisfied word will work as well, but ``ignore'' is conventional.) | ||||
| // | ||||
| // To build a file only when using cgo, and only on Linux and OS X: | ||||
| // | ||||
| //	// +build linux,cgo darwin,cgo | ||||
| // | ||||
| // Such a file is usually paired with another file implementing the | ||||
| // default functionality for other systems, which in this case would | ||||
| // carry the constraint: | ||||
| // | ||||
| //	// +build !linux,!darwin !cgo | ||||
| // | ||||
| // Naming a file dns_windows.go will cause it to be included only when | ||||
| // building the package for Windows; similarly, math_386.s will be included | ||||
| // only when building the package for 32-bit x86. | ||||
| // | ||||
| // Using GOOS=android matches build tags and files as for GOOS=linux | ||||
| // in addition to android tags and files. | ||||
| // | ||||
| package build | ||||
							
								
								
									
										246
									
								
								third_party/golang/go/build/read.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								third_party/golang/go/build/read.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,246 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| type importReader struct { | ||||
| 	b    *bufio.Reader | ||||
| 	buf  []byte | ||||
| 	peek byte | ||||
| 	err  error | ||||
| 	eof  bool | ||||
| 	nerr int | ||||
| } | ||||
|  | ||||
| func isIdent(c byte) bool { | ||||
| 	return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= 0x80 | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	errSyntax = errors.New("syntax error") | ||||
| 	errNUL    = errors.New("unexpected NUL in input") | ||||
| ) | ||||
|  | ||||
| // syntaxError records a syntax error, but only if an I/O error has not already been recorded. | ||||
| func (r *importReader) syntaxError() { | ||||
| 	if r.err == nil { | ||||
| 		r.err = errSyntax | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readByte reads the next byte from the input, saves it in buf, and returns it. | ||||
| // If an error occurs, readByte records the error in r.err and returns 0. | ||||
| func (r *importReader) readByte() byte { | ||||
| 	c, err := r.b.ReadByte() | ||||
| 	if err == nil { | ||||
| 		r.buf = append(r.buf, c) | ||||
| 		if c == 0 { | ||||
| 			err = errNUL | ||||
| 		} | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		if err == io.EOF { | ||||
| 			r.eof = true | ||||
| 		} else if r.err == nil { | ||||
| 			r.err = err | ||||
| 		} | ||||
| 		c = 0 | ||||
| 	} | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| // peekByte returns the next byte from the input reader but does not advance beyond it. | ||||
| // If skipSpace is set, peekByte skips leading spaces and comments. | ||||
| func (r *importReader) peekByte(skipSpace bool) byte { | ||||
| 	if r.err != nil { | ||||
| 		if r.nerr++; r.nerr > 10000 { | ||||
| 			panic("go/build: import reader looping") | ||||
| 		} | ||||
| 		return 0 | ||||
| 	} | ||||
|  | ||||
| 	// Use r.peek as first input byte. | ||||
| 	// Don't just return r.peek here: it might have been left by peekByte(false) | ||||
| 	// and this might be peekByte(true). | ||||
| 	c := r.peek | ||||
| 	if c == 0 { | ||||
| 		c = r.readByte() | ||||
| 	} | ||||
| 	for r.err == nil && !r.eof { | ||||
| 		if skipSpace { | ||||
| 			// For the purposes of this reader, semicolons are never necessary to | ||||
| 			// understand the input and are treated as spaces. | ||||
| 			switch c { | ||||
| 			case ' ', '\f', '\t', '\r', '\n', ';': | ||||
| 				c = r.readByte() | ||||
| 				continue | ||||
|  | ||||
| 			case '/': | ||||
| 				c = r.readByte() | ||||
| 				if c == '/' { | ||||
| 					for c != '\n' && r.err == nil && !r.eof { | ||||
| 						c = r.readByte() | ||||
| 					} | ||||
| 				} else if c == '*' { | ||||
| 					var c1 byte | ||||
| 					for (c != '*' || c1 != '/') && r.err == nil { | ||||
| 						if r.eof { | ||||
| 							r.syntaxError() | ||||
| 						} | ||||
| 						c, c1 = c1, r.readByte() | ||||
| 					} | ||||
| 				} else { | ||||
| 					r.syntaxError() | ||||
| 				} | ||||
| 				c = r.readByte() | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 		break | ||||
| 	} | ||||
| 	r.peek = c | ||||
| 	return r.peek | ||||
| } | ||||
|  | ||||
| // nextByte is like peekByte but advances beyond the returned byte. | ||||
| func (r *importReader) nextByte(skipSpace bool) byte { | ||||
| 	c := r.peekByte(skipSpace) | ||||
| 	r.peek = 0 | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| // readKeyword reads the given keyword from the input. | ||||
| // If the keyword is not present, readKeyword records a syntax error. | ||||
| func (r *importReader) readKeyword(kw string) { | ||||
| 	r.peekByte(true) | ||||
| 	for i := 0; i < len(kw); i++ { | ||||
| 		if r.nextByte(false) != kw[i] { | ||||
| 			r.syntaxError() | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	if isIdent(r.peekByte(false)) { | ||||
| 		r.syntaxError() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readIdent reads an identifier from the input. | ||||
| // If an identifier is not present, readIdent records a syntax error. | ||||
| func (r *importReader) readIdent() { | ||||
| 	c := r.peekByte(true) | ||||
| 	if !isIdent(c) { | ||||
| 		r.syntaxError() | ||||
| 		return | ||||
| 	} | ||||
| 	for isIdent(r.peekByte(false)) { | ||||
| 		r.peek = 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readString reads a quoted string literal from the input. | ||||
| // If an identifier is not present, readString records a syntax error. | ||||
| func (r *importReader) readString(save *[]string) { | ||||
| 	switch r.nextByte(true) { | ||||
| 	case '`': | ||||
| 		start := len(r.buf) - 1 | ||||
| 		for r.err == nil { | ||||
| 			if r.nextByte(false) == '`' { | ||||
| 				if save != nil { | ||||
| 					*save = append(*save, string(r.buf[start:])) | ||||
| 				} | ||||
| 				break | ||||
| 			} | ||||
| 			if r.eof { | ||||
| 				r.syntaxError() | ||||
| 			} | ||||
| 		} | ||||
| 	case '"': | ||||
| 		start := len(r.buf) - 1 | ||||
| 		for r.err == nil { | ||||
| 			c := r.nextByte(false) | ||||
| 			if c == '"' { | ||||
| 				if save != nil { | ||||
| 					*save = append(*save, string(r.buf[start:])) | ||||
| 				} | ||||
| 				break | ||||
| 			} | ||||
| 			if r.eof || c == '\n' { | ||||
| 				r.syntaxError() | ||||
| 			} | ||||
| 			if c == '\\' { | ||||
| 				r.nextByte(false) | ||||
| 			} | ||||
| 		} | ||||
| 	default: | ||||
| 		r.syntaxError() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readImport reads an import clause - optional identifier followed by quoted string - | ||||
| // from the input. | ||||
| func (r *importReader) readImport(imports *[]string) { | ||||
| 	c := r.peekByte(true) | ||||
| 	if c == '.' { | ||||
| 		r.peek = 0 | ||||
| 	} else if isIdent(c) { | ||||
| 		r.readIdent() | ||||
| 	} | ||||
| 	r.readString(imports) | ||||
| } | ||||
|  | ||||
| // readComments is like ioutil.ReadAll, except that it only reads the leading | ||||
| // block of comments in the file. | ||||
| func readComments(f io.Reader) ([]byte, error) { | ||||
| 	r := &importReader{b: bufio.NewReader(f)} | ||||
| 	r.peekByte(true) | ||||
| 	if r.err == nil && !r.eof { | ||||
| 		// Didn't reach EOF, so must have found a non-space byte. Remove it. | ||||
| 		r.buf = r.buf[:len(r.buf)-1] | ||||
| 	} | ||||
| 	return r.buf, r.err | ||||
| } | ||||
|  | ||||
| // readImports is like ioutil.ReadAll, except that it expects a Go file as input | ||||
| // and stops reading the input once the imports have completed. | ||||
| func readImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) { | ||||
| 	r := &importReader{b: bufio.NewReader(f)} | ||||
|  | ||||
| 	r.readKeyword("package") | ||||
| 	r.readIdent() | ||||
| 	for r.peekByte(true) == 'i' { | ||||
| 		r.readKeyword("import") | ||||
| 		if r.peekByte(true) == '(' { | ||||
| 			r.nextByte(false) | ||||
| 			for r.peekByte(true) != ')' && r.err == nil { | ||||
| 				r.readImport(imports) | ||||
| 			} | ||||
| 			r.nextByte(false) | ||||
| 		} else { | ||||
| 			r.readImport(imports) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// If we stopped successfully before EOF, we read a byte that told us we were done. | ||||
| 	// Return all but that last byte, which would cause a syntax error if we let it through. | ||||
| 	if r.err == nil && !r.eof { | ||||
| 		return r.buf[:len(r.buf)-1], nil | ||||
| 	} | ||||
|  | ||||
| 	// If we stopped for a syntax error, consume the whole file so that | ||||
| 	// we are sure we don't change the errors that go/parser returns. | ||||
| 	if r.err == errSyntax && !reportSyntaxError { | ||||
| 		r.err = nil | ||||
| 		for r.err == nil && !r.eof { | ||||
| 			r.readByte() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return r.buf, r.err | ||||
| } | ||||
							
								
								
									
										226
									
								
								third_party/golang/go/build/read_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								third_party/golang/go/build/read_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| const quote = "`" | ||||
|  | ||||
| type readTest struct { | ||||
| 	// Test input contains ℙ where readImports should stop. | ||||
| 	in  string | ||||
| 	err string | ||||
| } | ||||
|  | ||||
| var readImportsTests = []readTest{ | ||||
| 	{ | ||||
| 		`package p`, | ||||
| 		"", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import "x"`, | ||||
| 		"", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import . "x"`, | ||||
| 		"", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import "x";ℙvar x = 1`, | ||||
| 		"", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p | ||||
| 		 | ||||
| 		// comment | ||||
| 		 | ||||
| 		import "x" | ||||
| 		import _ "x" | ||||
| 		import a "x" | ||||
| 		 | ||||
| 		/* comment */ | ||||
| 		 | ||||
| 		import ( | ||||
| 			"x" /* comment */ | ||||
| 			_ "x" | ||||
| 			a "x" // comment | ||||
| 			` + quote + `x` + quote + ` | ||||
| 			_ /*comment*/ ` + quote + `x` + quote + ` | ||||
| 			a ` + quote + `x` + quote + ` | ||||
| 		) | ||||
| 		import ( | ||||
| 		) | ||||
| 		import () | ||||
| 		import()import()import() | ||||
| 		import();import();import() | ||||
| 		 | ||||
| 		ℙvar x = 1 | ||||
| 		`, | ||||
| 		"", | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| var readCommentsTests = []readTest{ | ||||
| 	{ | ||||
| 		`ℙpackage p`, | ||||
| 		"", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`ℙpackage p; import "x"`, | ||||
| 		"", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`ℙpackage p; import . "x"`, | ||||
| 		"", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`// foo | ||||
|  | ||||
| 		/* bar */ | ||||
|  | ||||
| 		/* quux */ // baz | ||||
| 		 | ||||
| 		/*/ zot */ | ||||
|  | ||||
| 		// asdf | ||||
| 		ℙHello, world`, | ||||
| 		"", | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, error)) { | ||||
| 	for i, tt := range tests { | ||||
| 		var in, testOut string | ||||
| 		j := strings.Index(tt.in, "ℙ") | ||||
| 		if j < 0 { | ||||
| 			in = tt.in | ||||
| 			testOut = tt.in | ||||
| 		} else { | ||||
| 			in = tt.in[:j] + tt.in[j+len("ℙ"):] | ||||
| 			testOut = tt.in[:j] | ||||
| 		} | ||||
| 		r := strings.NewReader(in) | ||||
| 		buf, err := read(r) | ||||
| 		if err != nil { | ||||
| 			if tt.err == "" { | ||||
| 				t.Errorf("#%d: err=%q, expected success (%q)", i, err, string(buf)) | ||||
| 				continue | ||||
| 			} | ||||
| 			if !strings.Contains(err.Error(), tt.err) { | ||||
| 				t.Errorf("#%d: err=%q, expected %q", i, err, tt.err) | ||||
| 				continue | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if err == nil && tt.err != "" { | ||||
| 			t.Errorf("#%d: success, expected %q", i, tt.err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		out := string(buf) | ||||
| 		if out != testOut { | ||||
| 			t.Errorf("#%d: wrong output:\nhave %q\nwant %q\n", i, out, testOut) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestReadImports(t *testing.T) { | ||||
| 	testRead(t, readImportsTests, func(r io.Reader) ([]byte, error) { return readImports(r, true, nil) }) | ||||
| } | ||||
|  | ||||
| func TestReadComments(t *testing.T) { | ||||
| 	testRead(t, readCommentsTests, readComments) | ||||
| } | ||||
|  | ||||
| var readFailuresTests = []readTest{ | ||||
| 	{ | ||||
| 		`package`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		"package p\n\x00\nimport `math`\n", | ||||
| 		"unexpected NUL in input", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import "`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		"package p; import ` \n\n", | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import "x`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import _`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import _ "`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import _ "x`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import .`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import . "`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import . "x`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import (`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import ("`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import ("x`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| 	{ | ||||
| 		`package p; import ("x"`, | ||||
| 		"syntax error", | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func TestReadFailures(t *testing.T) { | ||||
| 	// Errors should be reported (true arg to readImports). | ||||
| 	testRead(t, readFailuresTests, func(r io.Reader) ([]byte, error) { return readImports(r, true, nil) }) | ||||
| } | ||||
|  | ||||
| func TestReadFailuresIgnored(t *testing.T) { | ||||
| 	// Syntax errors should not be reported (false arg to readImports). | ||||
| 	// Instead, entire file should be the output and no error. | ||||
| 	// Convert tests not to return syntax errors. | ||||
| 	tests := make([]readTest, len(readFailuresTests)) | ||||
| 	copy(tests, readFailuresTests) | ||||
| 	for i := range tests { | ||||
| 		tt := &tests[i] | ||||
| 		if !strings.Contains(tt.err, "NUL") { | ||||
| 			tt.err = "" | ||||
| 		} | ||||
| 	} | ||||
| 	testRead(t, tests, func(r io.Reader) ([]byte, error) { return readImports(r, false, nil) }) | ||||
| } | ||||
							
								
								
									
										8
									
								
								third_party/golang/go/build/syslist.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								third_party/golang/go/build/syslist.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| // Copyright 2011 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. | ||||
|  | ||||
| package build | ||||
|  | ||||
| const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows " | ||||
| const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc s390 s390x sparc sparc64 " | ||||
							
								
								
									
										62
									
								
								third_party/golang/go/build/syslist_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								third_party/golang/go/build/syslist_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| // Copyright 2011 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. | ||||
|  | ||||
| package build | ||||
|  | ||||
| import ( | ||||
| 	"runtime" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	thisOS    = runtime.GOOS | ||||
| 	thisArch  = runtime.GOARCH | ||||
| 	otherOS   = anotherOS() | ||||
| 	otherArch = anotherArch() | ||||
| ) | ||||
|  | ||||
| func anotherOS() string { | ||||
| 	if thisOS != "darwin" { | ||||
| 		return "darwin" | ||||
| 	} | ||||
| 	return "linux" | ||||
| } | ||||
|  | ||||
| func anotherArch() string { | ||||
| 	if thisArch != "amd64" { | ||||
| 		return "amd64" | ||||
| 	} | ||||
| 	return "386" | ||||
| } | ||||
|  | ||||
| type GoodFileTest struct { | ||||
| 	name   string | ||||
| 	result bool | ||||
| } | ||||
|  | ||||
| var tests = []GoodFileTest{ | ||||
| 	{"file.go", true}, | ||||
| 	{"file.c", true}, | ||||
| 	{"file_foo.go", true}, | ||||
| 	{"file_" + thisArch + ".go", true}, | ||||
| 	{"file_" + otherArch + ".go", false}, | ||||
| 	{"file_" + thisOS + ".go", true}, | ||||
| 	{"file_" + otherOS + ".go", false}, | ||||
| 	{"file_" + thisOS + "_" + thisArch + ".go", true}, | ||||
| 	{"file_" + otherOS + "_" + thisArch + ".go", false}, | ||||
| 	{"file_" + thisOS + "_" + otherArch + ".go", false}, | ||||
| 	{"file_" + otherOS + "_" + otherArch + ".go", false}, | ||||
| 	{"file_foo_" + thisArch + ".go", true}, | ||||
| 	{"file_foo_" + otherArch + ".go", false}, | ||||
| 	{"file_" + thisOS + ".c", true}, | ||||
| 	{"file_" + otherOS + ".c", false}, | ||||
| } | ||||
|  | ||||
| func TestGoodOSArch(t *testing.T) { | ||||
| 	for _, test := range tests { | ||||
| 		if Default.goodOSArchFile(test.name, make(map[string]bool)) != test.result { | ||||
| 			t.Fatalf("goodOSArchFile(%q) != %v", test.name, test.result) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										0
									
								
								third_party/golang/go/build/testdata/empty/dummy
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								third_party/golang/go/build/testdata/empty/dummy
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
									
										5
									
								
								third_party/golang/go/build/testdata/multi/file.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								third_party/golang/go/build/testdata/multi/file.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| // Test data - not compiled. | ||||
|  | ||||
| package main | ||||
|  | ||||
| func main() {} | ||||
							
								
								
									
										5
									
								
								third_party/golang/go/build/testdata/multi/file_appengine.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								third_party/golang/go/build/testdata/multi/file_appengine.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| // Test data - not compiled. | ||||
|  | ||||
| package test_package | ||||
|  | ||||
| func init() {} | ||||
							
								
								
									
										5
									
								
								third_party/golang/go/build/testdata/other/file/file.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								third_party/golang/go/build/testdata/other/file/file.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| // Test data - not compiled. | ||||
|  | ||||
| package file | ||||
|  | ||||
| func F() {} | ||||
							
								
								
									
										11
									
								
								third_party/golang/go/build/testdata/other/main.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								third_party/golang/go/build/testdata/other/main.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| // Test data - not compiled. | ||||
|  | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"./file" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	file.F() | ||||
| } | ||||
							
								
								
									
										24
									
								
								third_party/golang/go/constant/go13.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								third_party/golang/go/constant/go13.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| // Copyright 2014 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. | ||||
|  | ||||
| // +build !go1.4 | ||||
|  | ||||
| package constant | ||||
|  | ||||
| import ( | ||||
| 	"math" | ||||
| 	"math/big" | ||||
| ) | ||||
|  | ||||
| func ratToFloat32(x *big.Rat) (float32, bool) { | ||||
| 	// Before 1.4, there's no Rat.Float32. | ||||
| 	// Emulate it, albeit at the cost of | ||||
| 	// imprecision in corner cases. | ||||
| 	x64, exact := x.Float64() | ||||
| 	x32 := float32(x64) | ||||
| 	if math.IsInf(float64(x32), 0) { | ||||
| 		exact = false | ||||
| 	} | ||||
| 	return x32, exact | ||||
| } | ||||
							
								
								
									
										13
									
								
								third_party/golang/go/constant/go14.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								third_party/golang/go/constant/go14.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| // Copyright 2014 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. | ||||
|  | ||||
| // +build go1.4 | ||||
|  | ||||
| package constant | ||||
|  | ||||
| import "math/big" | ||||
|  | ||||
| func ratToFloat32(x *big.Rat) (float32, bool) { | ||||
| 	return x.Float32() | ||||
| } | ||||
							
								
								
									
										925
									
								
								third_party/golang/go/constant/value.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										925
									
								
								third_party/golang/go/constant/value.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,925 @@ | ||||
| // Copyright 2013 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. | ||||
|  | ||||
| // Package constant implements Values representing untyped | ||||
| // Go constants and the corresponding operations. Values | ||||
| // and operations may have arbitrary or unlimited precision. | ||||
| // | ||||
| // A special Unknown value may be used when a value | ||||
| // is unknown due to an error. Operations on unknown | ||||
| // values produce unknown values unless specified | ||||
| // otherwise. | ||||
| // | ||||
| package constant | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"math/big" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // Kind specifies the kind of value represented by a Value. | ||||
| type Kind int | ||||
|  | ||||
| // Implementation note: Kinds must be enumerated in | ||||
| // order of increasing "complexity" (used by match). | ||||
|  | ||||
| const ( | ||||
| 	// unknown values | ||||
| 	Unknown Kind = iota | ||||
|  | ||||
| 	// non-numeric values | ||||
| 	Bool | ||||
| 	String | ||||
|  | ||||
| 	// numeric values | ||||
| 	Int | ||||
| 	Float | ||||
| 	Complex | ||||
| ) | ||||
|  | ||||
| // A Value represents a mathematically exact value of a given Kind. | ||||
| type Value interface { | ||||
| 	// Kind returns the value kind; it is always the smallest | ||||
| 	// kind in which the value can be represented exactly. | ||||
| 	Kind() Kind | ||||
|  | ||||
| 	// String returns a human-readable form of the value. | ||||
| 	String() string | ||||
|  | ||||
| 	// Prevent external implementations. | ||||
| 	implementsValue() | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Implementations | ||||
|  | ||||
| type ( | ||||
| 	unknownVal struct{} | ||||
| 	boolVal    bool | ||||
| 	stringVal  string | ||||
| 	int64Val   int64 | ||||
| 	intVal     struct{ val *big.Int } | ||||
| 	floatVal   struct{ val *big.Rat } | ||||
| 	complexVal struct{ re, im *big.Rat } | ||||
| ) | ||||
|  | ||||
| func (unknownVal) Kind() Kind { return Unknown } | ||||
| func (boolVal) Kind() Kind    { return Bool } | ||||
| func (stringVal) Kind() Kind  { return String } | ||||
| func (int64Val) Kind() Kind   { return Int } | ||||
| func (intVal) Kind() Kind     { return Int } | ||||
| func (floatVal) Kind() Kind   { return Float } | ||||
| func (complexVal) Kind() Kind { return Complex } | ||||
|  | ||||
| func (unknownVal) String() string   { return "unknown" } | ||||
| func (x boolVal) String() string    { return fmt.Sprintf("%v", bool(x)) } | ||||
| func (x stringVal) String() string  { return strconv.Quote(string(x)) } | ||||
| func (x int64Val) String() string   { return strconv.FormatInt(int64(x), 10) } | ||||
| func (x intVal) String() string     { return x.val.String() } | ||||
| func (x floatVal) String() string   { return x.val.String() } | ||||
| func (x complexVal) String() string { return fmt.Sprintf("(%s + %si)", x.re, x.im) } | ||||
|  | ||||
| func (unknownVal) implementsValue() {} | ||||
| func (boolVal) implementsValue()    {} | ||||
| func (stringVal) implementsValue()  {} | ||||
| func (int64Val) implementsValue()   {} | ||||
| func (intVal) implementsValue()     {} | ||||
| func (floatVal) implementsValue()   {} | ||||
| func (complexVal) implementsValue() {} | ||||
|  | ||||
| // int64 bounds | ||||
| var ( | ||||
| 	minInt64 = big.NewInt(-1 << 63) | ||||
| 	maxInt64 = big.NewInt(1<<63 - 1) | ||||
| ) | ||||
|  | ||||
| func normInt(x *big.Int) Value { | ||||
| 	if minInt64.Cmp(x) <= 0 && x.Cmp(maxInt64) <= 0 { | ||||
| 		return int64Val(x.Int64()) | ||||
| 	} | ||||
| 	return intVal{x} | ||||
| } | ||||
|  | ||||
| func normFloat(x *big.Rat) Value { | ||||
| 	if x.IsInt() { | ||||
| 		return normInt(x.Num()) | ||||
| 	} | ||||
| 	return floatVal{x} | ||||
| } | ||||
|  | ||||
| func normComplex(re, im *big.Rat) Value { | ||||
| 	if im.Sign() == 0 { | ||||
| 		return normFloat(re) | ||||
| 	} | ||||
| 	return complexVal{re, im} | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Factories | ||||
|  | ||||
| // MakeUnknown returns the Unknown value. | ||||
| func MakeUnknown() Value { return unknownVal{} } | ||||
|  | ||||
| // MakeBool returns the Bool value for x. | ||||
| func MakeBool(b bool) Value { return boolVal(b) } | ||||
|  | ||||
| // MakeString returns the String value for x. | ||||
| func MakeString(s string) Value { return stringVal(s) } | ||||
|  | ||||
| // MakeInt64 returns the Int value for x. | ||||
| func MakeInt64(x int64) Value { return int64Val(x) } | ||||
|  | ||||
| // MakeUint64 returns the Int value for x. | ||||
| func MakeUint64(x uint64) Value { return normInt(new(big.Int).SetUint64(x)) } | ||||
|  | ||||
| // MakeFloat64 returns the numeric value for x. | ||||
| // If x is not finite, the result is unknown. | ||||
| func MakeFloat64(x float64) Value { | ||||
| 	if f := new(big.Rat).SetFloat64(x); f != nil { | ||||
| 		return normFloat(f) | ||||
| 	} | ||||
| 	return unknownVal{} | ||||
| } | ||||
|  | ||||
| // MakeFromLiteral returns the corresponding integer, floating-point, | ||||
| // imaginary, character, or string value for a Go literal string. | ||||
| // If prec > 0, prec specifies an upper limit for the precision of | ||||
| // a numeric value. If the literal string is invalid, the result is | ||||
| // nil. | ||||
| // BUG(gri) Only prec == 0 is supported at the moment. | ||||
| func MakeFromLiteral(lit string, tok token.Token, prec uint) Value { | ||||
| 	if prec != 0 { | ||||
| 		panic("limited precision not supported") | ||||
| 	} | ||||
| 	switch tok { | ||||
| 	case token.INT: | ||||
| 		if x, err := strconv.ParseInt(lit, 0, 64); err == nil { | ||||
| 			return int64Val(x) | ||||
| 		} | ||||
| 		if x, ok := new(big.Int).SetString(lit, 0); ok { | ||||
| 			return intVal{x} | ||||
| 		} | ||||
|  | ||||
| 	case token.FLOAT: | ||||
| 		if x, ok := new(big.Rat).SetString(lit); ok { | ||||
| 			return normFloat(x) | ||||
| 		} | ||||
|  | ||||
| 	case token.IMAG: | ||||
| 		if n := len(lit); n > 0 && lit[n-1] == 'i' { | ||||
| 			if im, ok := new(big.Rat).SetString(lit[0 : n-1]); ok { | ||||
| 				return normComplex(big.NewRat(0, 1), im) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 	case token.CHAR: | ||||
| 		if n := len(lit); n >= 2 { | ||||
| 			if code, _, _, err := strconv.UnquoteChar(lit[1:n-1], '\''); err == nil { | ||||
| 				return int64Val(code) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 	case token.STRING: | ||||
| 		if s, err := strconv.Unquote(lit); err == nil { | ||||
| 			return stringVal(s) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Accessors | ||||
| // | ||||
| // For unknown arguments the result is the zero value for the respective | ||||
| // accessor type, except for Sign, where the result is 1. | ||||
|  | ||||
| // BoolVal returns the Go boolean value of x, which must be a Bool or an Unknown. | ||||
| // If x is Unknown, the result is false. | ||||
| func BoolVal(x Value) bool { | ||||
| 	switch x := x.(type) { | ||||
| 	case boolVal: | ||||
| 		return bool(x) | ||||
| 	case unknownVal: | ||||
| 		return false | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not a Bool", x)) | ||||
| } | ||||
|  | ||||
| // StringVal returns the Go string value of x, which must be a String or an Unknown. | ||||
| // If x is Unknown, the result is "". | ||||
| func StringVal(x Value) string { | ||||
| 	switch x := x.(type) { | ||||
| 	case stringVal: | ||||
| 		return string(x) | ||||
| 	case unknownVal: | ||||
| 		return "" | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not a String", x)) | ||||
| } | ||||
|  | ||||
| // Int64Val returns the Go int64 value of x and whether the result is exact; | ||||
| // x must be an Int or an Unknown. If the result is not exact, its value is undefined. | ||||
| // If x is Unknown, the result is (0, false). | ||||
| func Int64Val(x Value) (int64, bool) { | ||||
| 	switch x := x.(type) { | ||||
| 	case int64Val: | ||||
| 		return int64(x), true | ||||
| 	case intVal: | ||||
| 		return x.val.Int64(), x.val.BitLen() <= 63 | ||||
| 	case unknownVal: | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not an Int", x)) | ||||
| } | ||||
|  | ||||
| // Uint64Val returns the Go uint64 value of x and whether the result is exact; | ||||
| // x must be an Int or an Unknown. If the result is not exact, its value is undefined. | ||||
| // If x is Unknown, the result is (0, false). | ||||
| func Uint64Val(x Value) (uint64, bool) { | ||||
| 	switch x := x.(type) { | ||||
| 	case int64Val: | ||||
| 		return uint64(x), x >= 0 | ||||
| 	case intVal: | ||||
| 		return x.val.Uint64(), x.val.Sign() >= 0 && x.val.BitLen() <= 64 | ||||
| 	case unknownVal: | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not an Int", x)) | ||||
| } | ||||
|  | ||||
| // Float32Val is like Float64Val but for float32 instead of float64. | ||||
| func Float32Val(x Value) (float32, bool) { | ||||
| 	switch x := x.(type) { | ||||
| 	case int64Val: | ||||
| 		f := float32(x) | ||||
| 		return f, int64Val(f) == x | ||||
| 	case intVal: | ||||
| 		return ratToFloat32(new(big.Rat).SetFrac(x.val, int1)) | ||||
| 	case floatVal: | ||||
| 		return ratToFloat32(x.val) | ||||
| 	case unknownVal: | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not a Float", x)) | ||||
| } | ||||
|  | ||||
| // Float64Val returns the nearest Go float64 value of x and whether the result is exact; | ||||
| // x must be numeric but not Complex, or Unknown. For values too small (too close to 0) | ||||
| // to represent as float64, Float64Val silently underflows to 0. The result sign always | ||||
| // matches the sign of x, even for 0. | ||||
| // If x is Unknown, the result is (0, false). | ||||
| func Float64Val(x Value) (float64, bool) { | ||||
| 	switch x := x.(type) { | ||||
| 	case int64Val: | ||||
| 		f := float64(int64(x)) | ||||
| 		return f, int64Val(f) == x | ||||
| 	case intVal: | ||||
| 		return new(big.Rat).SetFrac(x.val, int1).Float64() | ||||
| 	case floatVal: | ||||
| 		return x.val.Float64() | ||||
| 	case unknownVal: | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not a Float", x)) | ||||
| } | ||||
|  | ||||
| // BitLen returns the number of bits required to represent | ||||
| // the absolute value x in binary representation; x must be an Int or an Unknown. | ||||
| // If x is Unknown, the result is 0. | ||||
| func BitLen(x Value) int { | ||||
| 	switch x := x.(type) { | ||||
| 	case int64Val: | ||||
| 		return new(big.Int).SetInt64(int64(x)).BitLen() | ||||
| 	case intVal: | ||||
| 		return x.val.BitLen() | ||||
| 	case unknownVal: | ||||
| 		return 0 | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not an Int", x)) | ||||
| } | ||||
|  | ||||
| // Sign returns -1, 0, or 1 depending on whether x < 0, x == 0, or x > 0; | ||||
| // x must be numeric or Unknown. For complex values x, the sign is 0 if x == 0, | ||||
| // otherwise it is != 0. If x is Unknown, the result is 1. | ||||
| func Sign(x Value) int { | ||||
| 	switch x := x.(type) { | ||||
| 	case int64Val: | ||||
| 		switch { | ||||
| 		case x < 0: | ||||
| 			return -1 | ||||
| 		case x > 0: | ||||
| 			return 1 | ||||
| 		} | ||||
| 		return 0 | ||||
| 	case intVal: | ||||
| 		return x.val.Sign() | ||||
| 	case floatVal: | ||||
| 		return x.val.Sign() | ||||
| 	case complexVal: | ||||
| 		return x.re.Sign() | x.im.Sign() | ||||
| 	case unknownVal: | ||||
| 		return 1 // avoid spurious division by zero errors | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not numeric", x)) | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Support for serializing/deserializing integers | ||||
|  | ||||
| const ( | ||||
| 	// Compute the size of a Word in bytes. | ||||
| 	_m       = ^big.Word(0) | ||||
| 	_log     = _m>>8&1 + _m>>16&1 + _m>>32&1 | ||||
| 	wordSize = 1 << _log | ||||
| ) | ||||
|  | ||||
| // Bytes returns the bytes for the absolute value of x in little- | ||||
| // endian binary representation; x must be an Int. | ||||
| func Bytes(x Value) []byte { | ||||
| 	var val *big.Int | ||||
| 	switch x := x.(type) { | ||||
| 	case int64Val: | ||||
| 		val = new(big.Int).SetInt64(int64(x)) | ||||
| 	case intVal: | ||||
| 		val = x.val | ||||
| 	default: | ||||
| 		panic(fmt.Sprintf("%v not an Int", x)) | ||||
| 	} | ||||
|  | ||||
| 	words := val.Bits() | ||||
| 	bytes := make([]byte, len(words)*wordSize) | ||||
|  | ||||
| 	i := 0 | ||||
| 	for _, w := range words { | ||||
| 		for j := 0; j < wordSize; j++ { | ||||
| 			bytes[i] = byte(w) | ||||
| 			w >>= 8 | ||||
| 			i++ | ||||
| 		} | ||||
| 	} | ||||
| 	// remove leading 0's | ||||
| 	for i > 0 && bytes[i-1] == 0 { | ||||
| 		i-- | ||||
| 	} | ||||
|  | ||||
| 	return bytes[:i] | ||||
| } | ||||
|  | ||||
| // MakeFromBytes returns the Int value given the bytes of its little-endian | ||||
| // binary representation. An empty byte slice argument represents 0. | ||||
| func MakeFromBytes(bytes []byte) Value { | ||||
| 	words := make([]big.Word, (len(bytes)+(wordSize-1))/wordSize) | ||||
|  | ||||
| 	i := 0 | ||||
| 	var w big.Word | ||||
| 	var s uint | ||||
| 	for _, b := range bytes { | ||||
| 		w |= big.Word(b) << s | ||||
| 		if s += 8; s == wordSize*8 { | ||||
| 			words[i] = w | ||||
| 			i++ | ||||
| 			w = 0 | ||||
| 			s = 0 | ||||
| 		} | ||||
| 	} | ||||
| 	// store last word | ||||
| 	if i < len(words) { | ||||
| 		words[i] = w | ||||
| 		i++ | ||||
| 	} | ||||
| 	// remove leading 0's | ||||
| 	for i > 0 && words[i-1] == 0 { | ||||
| 		i-- | ||||
| 	} | ||||
|  | ||||
| 	return normInt(new(big.Int).SetBits(words[:i])) | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Support for disassembling fractions | ||||
|  | ||||
| // Num returns the numerator of x; x must be Int, Float, or Unknown. | ||||
| // If x is Unknown, the result is Unknown, otherwise it is an Int | ||||
| // with the same sign as x. | ||||
| func Num(x Value) Value { | ||||
| 	switch x := x.(type) { | ||||
| 	case unknownVal, int64Val, intVal: | ||||
| 		return x | ||||
| 	case floatVal: | ||||
| 		return normInt(x.val.Num()) | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not Int or Float", x)) | ||||
| } | ||||
|  | ||||
| // Denom returns the denominator of x; x must be Int, Float, or Unknown. | ||||
| // If x is Unknown, the result is Unknown, otherwise it is an Int >= 1. | ||||
| func Denom(x Value) Value { | ||||
| 	switch x := x.(type) { | ||||
| 	case unknownVal: | ||||
| 		return x | ||||
| 	case int64Val, intVal: | ||||
| 		return int64Val(1) | ||||
| 	case floatVal: | ||||
| 		return normInt(x.val.Denom()) | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not Int or Float", x)) | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Support for assembling/disassembling complex numbers | ||||
|  | ||||
| // MakeImag returns the numeric value x*i (possibly 0); | ||||
| // x must be Int, Float, or Unknown. | ||||
| // If x is Unknown, the result is Unknown. | ||||
| func MakeImag(x Value) Value { | ||||
| 	var im *big.Rat | ||||
| 	switch x := x.(type) { | ||||
| 	case unknownVal: | ||||
| 		return x | ||||
| 	case int64Val: | ||||
| 		im = big.NewRat(int64(x), 1) | ||||
| 	case intVal: | ||||
| 		im = new(big.Rat).SetFrac(x.val, int1) | ||||
| 	case floatVal: | ||||
| 		im = x.val | ||||
| 	default: | ||||
| 		panic(fmt.Sprintf("%v not Int or Float", x)) | ||||
| 	} | ||||
| 	return normComplex(rat0, im) | ||||
| } | ||||
|  | ||||
| // Real returns the real part of x, which must be a numeric or unknown value. | ||||
| // If x is Unknown, the result is Unknown. | ||||
| func Real(x Value) Value { | ||||
| 	switch x := x.(type) { | ||||
| 	case unknownVal, int64Val, intVal, floatVal: | ||||
| 		return x | ||||
| 	case complexVal: | ||||
| 		return normFloat(x.re) | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not numeric", x)) | ||||
| } | ||||
|  | ||||
| // Imag returns the imaginary part of x, which must be a numeric or unknown value. | ||||
| // If x is Unknown, the result is Unknown. | ||||
| func Imag(x Value) Value { | ||||
| 	switch x := x.(type) { | ||||
| 	case unknownVal: | ||||
| 		return x | ||||
| 	case int64Val, intVal, floatVal: | ||||
| 		return int64Val(0) | ||||
| 	case complexVal: | ||||
| 		return normFloat(x.im) | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("%v not numeric", x)) | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Operations | ||||
|  | ||||
| // is32bit reports whether x can be represented using 32 bits. | ||||
| func is32bit(x int64) bool { | ||||
| 	const s = 32 | ||||
| 	return -1<<(s-1) <= x && x <= 1<<(s-1)-1 | ||||
| } | ||||
|  | ||||
| // is63bit reports whether x can be represented using 63 bits. | ||||
| func is63bit(x int64) bool { | ||||
| 	const s = 63 | ||||
| 	return -1<<(s-1) <= x && x <= 1<<(s-1)-1 | ||||
| } | ||||
|  | ||||
| // UnaryOp returns the result of the unary expression op y. | ||||
| // The operation must be defined for the operand. | ||||
| // If prec > 0 it specifies the ^ (xor) result size in bits. | ||||
| // If y is Unknown, the result is Unknown. | ||||
| // | ||||
| func UnaryOp(op token.Token, y Value, prec uint) Value { | ||||
| 	switch op { | ||||
| 	case token.ADD: | ||||
| 		switch y.(type) { | ||||
| 		case unknownVal, int64Val, intVal, floatVal, complexVal: | ||||
| 			return y | ||||
| 		} | ||||
|  | ||||
| 	case token.SUB: | ||||
| 		switch y := y.(type) { | ||||
| 		case unknownVal: | ||||
| 			return y | ||||
| 		case int64Val: | ||||
| 			if z := -y; z != y { | ||||
| 				return z // no overflow | ||||
| 			} | ||||
| 			return normInt(new(big.Int).Neg(big.NewInt(int64(y)))) | ||||
| 		case intVal: | ||||
| 			return normInt(new(big.Int).Neg(y.val)) | ||||
| 		case floatVal: | ||||
| 			return normFloat(new(big.Rat).Neg(y.val)) | ||||
| 		case complexVal: | ||||
| 			return normComplex(new(big.Rat).Neg(y.re), new(big.Rat).Neg(y.im)) | ||||
| 		} | ||||
|  | ||||
| 	case token.XOR: | ||||
| 		var z big.Int | ||||
| 		switch y := y.(type) { | ||||
| 		case unknownVal: | ||||
| 			return y | ||||
| 		case int64Val: | ||||
| 			z.Not(big.NewInt(int64(y))) | ||||
| 		case intVal: | ||||
| 			z.Not(y.val) | ||||
| 		default: | ||||
| 			goto Error | ||||
| 		} | ||||
| 		// For unsigned types, the result will be negative and | ||||
| 		// thus "too large": We must limit the result precision | ||||
| 		// to the type's precision. | ||||
| 		if prec > 0 { | ||||
| 			z.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), prec)) // z &^= (-1)<<prec | ||||
| 		} | ||||
| 		return normInt(&z) | ||||
|  | ||||
| 	case token.NOT: | ||||
| 		switch y := y.(type) { | ||||
| 		case unknownVal: | ||||
| 			return y | ||||
| 		case boolVal: | ||||
| 			return !y | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| Error: | ||||
| 	panic(fmt.Sprintf("invalid unary operation %s%v", op, y)) | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	int1 = big.NewInt(1) | ||||
| 	rat0 = big.NewRat(0, 1) | ||||
| ) | ||||
|  | ||||
| func ord(x Value) int { | ||||
| 	switch x.(type) { | ||||
| 	default: | ||||
| 		return 0 | ||||
| 	case boolVal, stringVal: | ||||
| 		return 1 | ||||
| 	case int64Val: | ||||
| 		return 2 | ||||
| 	case intVal: | ||||
| 		return 3 | ||||
| 	case floatVal: | ||||
| 		return 4 | ||||
| 	case complexVal: | ||||
| 		return 5 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // match returns the matching representation (same type) with the | ||||
| // smallest complexity for two values x and y. If one of them is | ||||
| // numeric, both of them must be numeric. If one of them is Unknown, | ||||
| // both results are Unknown. | ||||
| // | ||||
| func match(x, y Value) (_, _ Value) { | ||||
| 	if ord(x) > ord(y) { | ||||
| 		y, x = match(y, x) | ||||
| 		return x, y | ||||
| 	} | ||||
| 	// ord(x) <= ord(y) | ||||
|  | ||||
| 	switch x := x.(type) { | ||||
| 	case unknownVal: | ||||
| 		return x, x | ||||
|  | ||||
| 	case boolVal, stringVal, complexVal: | ||||
| 		return x, y | ||||
|  | ||||
| 	case int64Val: | ||||
| 		switch y := y.(type) { | ||||
| 		case int64Val: | ||||
| 			return x, y | ||||
| 		case intVal: | ||||
| 			return intVal{big.NewInt(int64(x))}, y | ||||
| 		case floatVal: | ||||
| 			return floatVal{big.NewRat(int64(x), 1)}, y | ||||
| 		case complexVal: | ||||
| 			return complexVal{big.NewRat(int64(x), 1), rat0}, y | ||||
| 		} | ||||
|  | ||||
| 	case intVal: | ||||
| 		switch y := y.(type) { | ||||
| 		case intVal: | ||||
| 			return x, y | ||||
| 		case floatVal: | ||||
| 			return floatVal{new(big.Rat).SetFrac(x.val, int1)}, y | ||||
| 		case complexVal: | ||||
| 			return complexVal{new(big.Rat).SetFrac(x.val, int1), rat0}, y | ||||
| 		} | ||||
|  | ||||
| 	case floatVal: | ||||
| 		switch y := y.(type) { | ||||
| 		case floatVal: | ||||
| 			return x, y | ||||
| 		case complexVal: | ||||
| 			return complexVal{x.val, rat0}, y | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	panic("unreachable") | ||||
| } | ||||
|  | ||||
| // BinaryOp returns the result of the binary expression x op y. | ||||
| // The operation must be defined for the operands. If one of the | ||||
| // operands is Unknown, the result is Unknown. | ||||
| // To force integer division of Int operands, use op == token.QUO_ASSIGN | ||||
| // instead of token.QUO; the result is guaranteed to be Int in this case. | ||||
| // Division by zero leads to a run-time panic. | ||||
| // | ||||
| func BinaryOp(x Value, op token.Token, y Value) Value { | ||||
| 	x, y = match(x, y) | ||||
|  | ||||
| 	switch x := x.(type) { | ||||
| 	case unknownVal: | ||||
| 		return x | ||||
|  | ||||
| 	case boolVal: | ||||
| 		y := y.(boolVal) | ||||
| 		switch op { | ||||
| 		case token.LAND: | ||||
| 			return x && y | ||||
| 		case token.LOR: | ||||
| 			return x || y | ||||
| 		} | ||||
|  | ||||
| 	case int64Val: | ||||
| 		a := int64(x) | ||||
| 		b := int64(y.(int64Val)) | ||||
| 		var c int64 | ||||
| 		switch op { | ||||
| 		case token.ADD: | ||||
| 			if !is63bit(a) || !is63bit(b) { | ||||
| 				return normInt(new(big.Int).Add(big.NewInt(a), big.NewInt(b))) | ||||
| 			} | ||||
| 			c = a + b | ||||
| 		case token.SUB: | ||||
| 			if !is63bit(a) || !is63bit(b) { | ||||
| 				return normInt(new(big.Int).Sub(big.NewInt(a), big.NewInt(b))) | ||||
| 			} | ||||
| 			c = a - b | ||||
| 		case token.MUL: | ||||
| 			if !is32bit(a) || !is32bit(b) { | ||||
| 				return normInt(new(big.Int).Mul(big.NewInt(a), big.NewInt(b))) | ||||
| 			} | ||||
| 			c = a * b | ||||
| 		case token.QUO: | ||||
| 			return normFloat(new(big.Rat).SetFrac(big.NewInt(a), big.NewInt(b))) | ||||
| 		case token.QUO_ASSIGN: // force integer division | ||||
| 			c = a / b | ||||
| 		case token.REM: | ||||
| 			c = a % b | ||||
| 		case token.AND: | ||||
| 			c = a & b | ||||
| 		case token.OR: | ||||
| 			c = a | b | ||||
| 		case token.XOR: | ||||
| 			c = a ^ b | ||||
| 		case token.AND_NOT: | ||||
| 			c = a &^ b | ||||
| 		default: | ||||
| 			goto Error | ||||
| 		} | ||||
| 		return int64Val(c) | ||||
|  | ||||
| 	case intVal: | ||||
| 		a := x.val | ||||
| 		b := y.(intVal).val | ||||
| 		var c big.Int | ||||
| 		switch op { | ||||
| 		case token.ADD: | ||||
| 			c.Add(a, b) | ||||
| 		case token.SUB: | ||||
| 			c.Sub(a, b) | ||||
| 		case token.MUL: | ||||
| 			c.Mul(a, b) | ||||
| 		case token.QUO: | ||||
| 			return normFloat(new(big.Rat).SetFrac(a, b)) | ||||
| 		case token.QUO_ASSIGN: // force integer division | ||||
| 			c.Quo(a, b) | ||||
| 		case token.REM: | ||||
| 			c.Rem(a, b) | ||||
| 		case token.AND: | ||||
| 			c.And(a, b) | ||||
| 		case token.OR: | ||||
| 			c.Or(a, b) | ||||
| 		case token.XOR: | ||||
| 			c.Xor(a, b) | ||||
| 		case token.AND_NOT: | ||||
| 			c.AndNot(a, b) | ||||
| 		default: | ||||
| 			goto Error | ||||
| 		} | ||||
| 		return normInt(&c) | ||||
|  | ||||
| 	case floatVal: | ||||
| 		a := x.val | ||||
| 		b := y.(floatVal).val | ||||
| 		var c big.Rat | ||||
| 		switch op { | ||||
| 		case token.ADD: | ||||
| 			c.Add(a, b) | ||||
| 		case token.SUB: | ||||
| 			c.Sub(a, b) | ||||
| 		case token.MUL: | ||||
| 			c.Mul(a, b) | ||||
| 		case token.QUO: | ||||
| 			c.Quo(a, b) | ||||
| 		default: | ||||
| 			goto Error | ||||
| 		} | ||||
| 		return normFloat(&c) | ||||
|  | ||||
| 	case complexVal: | ||||
| 		y := y.(complexVal) | ||||
| 		a, b := x.re, x.im | ||||
| 		c, d := y.re, y.im | ||||
| 		var re, im big.Rat | ||||
| 		switch op { | ||||
| 		case token.ADD: | ||||
| 			// (a+c) + i(b+d) | ||||
| 			re.Add(a, c) | ||||
| 			im.Add(b, d) | ||||
| 		case token.SUB: | ||||
| 			// (a-c) + i(b-d) | ||||
| 			re.Sub(a, c) | ||||
| 			im.Sub(b, d) | ||||
| 		case token.MUL: | ||||
| 			// (ac-bd) + i(bc+ad) | ||||
| 			var ac, bd, bc, ad big.Rat | ||||
| 			ac.Mul(a, c) | ||||
| 			bd.Mul(b, d) | ||||
| 			bc.Mul(b, c) | ||||
| 			ad.Mul(a, d) | ||||
| 			re.Sub(&ac, &bd) | ||||
| 			im.Add(&bc, &ad) | ||||
| 		case token.QUO: | ||||
| 			// (ac+bd)/s + i(bc-ad)/s, with s = cc + dd | ||||
| 			var ac, bd, bc, ad, s, cc, dd big.Rat | ||||
| 			ac.Mul(a, c) | ||||
| 			bd.Mul(b, d) | ||||
| 			bc.Mul(b, c) | ||||
| 			ad.Mul(a, d) | ||||
| 			cc.Mul(c, c) | ||||
| 			dd.Mul(d, d) | ||||
| 			s.Add(&cc, &dd) | ||||
| 			re.Add(&ac, &bd) | ||||
| 			re.Quo(&re, &s) | ||||
| 			im.Sub(&bc, &ad) | ||||
| 			im.Quo(&im, &s) | ||||
| 		default: | ||||
| 			goto Error | ||||
| 		} | ||||
| 		return normComplex(&re, &im) | ||||
|  | ||||
| 	case stringVal: | ||||
| 		if op == token.ADD { | ||||
| 			return x + y.(stringVal) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| Error: | ||||
| 	panic(fmt.Sprintf("invalid binary operation %v %s %v", x, op, y)) | ||||
| } | ||||
|  | ||||
| // Shift returns the result of the shift expression x op s | ||||
| // with op == token.SHL or token.SHR (<< or >>). x must be | ||||
| // an Int or an Unknown. If x is Unknown, the result is x. | ||||
| // | ||||
| func Shift(x Value, op token.Token, s uint) Value { | ||||
| 	switch x := x.(type) { | ||||
| 	case unknownVal: | ||||
| 		return x | ||||
|  | ||||
| 	case int64Val: | ||||
| 		if s == 0 { | ||||
| 			return x | ||||
| 		} | ||||
| 		switch op { | ||||
| 		case token.SHL: | ||||
| 			z := big.NewInt(int64(x)) | ||||
| 			return normInt(z.Lsh(z, s)) | ||||
| 		case token.SHR: | ||||
| 			return x >> s | ||||
| 		} | ||||
|  | ||||
| 	case intVal: | ||||
| 		if s == 0 { | ||||
| 			return x | ||||
| 		} | ||||
| 		var z big.Int | ||||
| 		switch op { | ||||
| 		case token.SHL: | ||||
| 			return normInt(z.Lsh(x.val, s)) | ||||
| 		case token.SHR: | ||||
| 			return normInt(z.Rsh(x.val, s)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	panic(fmt.Sprintf("invalid shift %v %s %d", x, op, s)) | ||||
| } | ||||
|  | ||||
| func cmpZero(x int, op token.Token) bool { | ||||
| 	switch op { | ||||
| 	case token.EQL: | ||||
| 		return x == 0 | ||||
| 	case token.NEQ: | ||||
| 		return x != 0 | ||||
| 	case token.LSS: | ||||
| 		return x < 0 | ||||
| 	case token.LEQ: | ||||
| 		return x <= 0 | ||||
| 	case token.GTR: | ||||
| 		return x > 0 | ||||
| 	case token.GEQ: | ||||
| 		return x >= 0 | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
|  | ||||
| // Compare returns the result of the comparison x op y. | ||||
| // The comparison must be defined for the operands. | ||||
| // If one of the operands is Unknown, the result is | ||||
| // false. | ||||
| // | ||||
| func Compare(x Value, op token.Token, y Value) bool { | ||||
| 	x, y = match(x, y) | ||||
|  | ||||
| 	switch x := x.(type) { | ||||
| 	case unknownVal: | ||||
| 		return false | ||||
|  | ||||
| 	case boolVal: | ||||
| 		y := y.(boolVal) | ||||
| 		switch op { | ||||
| 		case token.EQL: | ||||
| 			return x == y | ||||
| 		case token.NEQ: | ||||
| 			return x != y | ||||
| 		} | ||||
|  | ||||
| 	case int64Val: | ||||
| 		y := y.(int64Val) | ||||
| 		switch op { | ||||
| 		case token.EQL: | ||||
| 			return x == y | ||||
| 		case token.NEQ: | ||||
| 			return x != y | ||||
| 		case token.LSS: | ||||
| 			return x < y | ||||
| 		case token.LEQ: | ||||
| 			return x <= y | ||||
| 		case token.GTR: | ||||
| 			return x > y | ||||
| 		case token.GEQ: | ||||
| 			return x >= y | ||||
| 		} | ||||
|  | ||||
| 	case intVal: | ||||
| 		return cmpZero(x.val.Cmp(y.(intVal).val), op) | ||||
|  | ||||
| 	case floatVal: | ||||
| 		return cmpZero(x.val.Cmp(y.(floatVal).val), op) | ||||
|  | ||||
| 	case complexVal: | ||||
| 		y := y.(complexVal) | ||||
| 		re := x.re.Cmp(y.re) | ||||
| 		im := x.im.Cmp(y.im) | ||||
| 		switch op { | ||||
| 		case token.EQL: | ||||
| 			return re == 0 && im == 0 | ||||
| 		case token.NEQ: | ||||
| 			return re != 0 || im != 0 | ||||
| 		} | ||||
|  | ||||
| 	case stringVal: | ||||
| 		y := y.(stringVal) | ||||
| 		switch op { | ||||
| 		case token.EQL: | ||||
| 			return x == y | ||||
| 		case token.NEQ: | ||||
| 			return x != y | ||||
| 		case token.LSS: | ||||
| 			return x < y | ||||
| 		case token.LEQ: | ||||
| 			return x <= y | ||||
| 		case token.GTR: | ||||
| 			return x > y | ||||
| 		case token.GEQ: | ||||
| 			return x >= y | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	panic(fmt.Sprintf("invalid comparison %v %s %v", x, op, y)) | ||||
| } | ||||
							
								
								
									
										375
									
								
								third_party/golang/go/constant/value_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										375
									
								
								third_party/golang/go/constant/value_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,375 @@ | ||||
| // Copyright 2013 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. | ||||
|  | ||||
| package constant | ||||
|  | ||||
| import ( | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| // TODO(gri) expand this test framework | ||||
|  | ||||
| var opTests = []string{ | ||||
| 	// unary operations | ||||
| 	`+ 0 = 0`, | ||||
| 	`+ ? = ?`, | ||||
| 	`- 1 = -1`, | ||||
| 	`- ? = ?`, | ||||
| 	`^ 0 = -1`, | ||||
| 	`^ ? = ?`, | ||||
|  | ||||
| 	`! true = false`, | ||||
| 	`! false = true`, | ||||
| 	`! ? = ?`, | ||||
|  | ||||
| 	// etc. | ||||
|  | ||||
| 	// binary operations | ||||
| 	`"" + "" = ""`, | ||||
| 	`"foo" + "" = "foo"`, | ||||
| 	`"" + "bar" = "bar"`, | ||||
| 	`"foo" + "bar" = "foobar"`, | ||||
|  | ||||
| 	`0 + 0 = 0`, | ||||
| 	`0 + 0.1 = 0.1`, | ||||
| 	`0 + 0.1i = 0.1i`, | ||||
| 	`0.1 + 0.9 = 1`, | ||||
| 	`1e100 + 1e100 = 2e100`, | ||||
| 	`? + 0 = ?`, | ||||
| 	`0 + ? = ?`, | ||||
|  | ||||
| 	`0 - 0 = 0`, | ||||
| 	`0 - 0.1 = -0.1`, | ||||
| 	`0 - 0.1i = -0.1i`, | ||||
| 	`1e100 - 1e100 = 0`, | ||||
| 	`? - 0 = ?`, | ||||
| 	`0 - ? = ?`, | ||||
|  | ||||
| 	`0 * 0 = 0`, | ||||
| 	`1 * 0.1 = 0.1`, | ||||
| 	`1 * 0.1i = 0.1i`, | ||||
| 	`1i * 1i = -1`, | ||||
| 	`? * 0 = ?`, | ||||
| 	`0 * ? = ?`, | ||||
|  | ||||
| 	`0 / 0 = "division_by_zero"`, | ||||
| 	`10 / 2 = 5`, | ||||
| 	`5 / 3 = 5/3`, | ||||
| 	`5i / 3i = 5/3`, | ||||
| 	`? / 0 = ?`, | ||||
| 	`0 / ? = ?`, | ||||
|  | ||||
| 	`0 % 0 = "runtime_error:_integer_divide_by_zero"`, // TODO(gri) should be the same as for / | ||||
| 	`10 % 3 = 1`, | ||||
| 	`? % 0 = ?`, | ||||
| 	`0 % ? = ?`, | ||||
|  | ||||
| 	`0 & 0 = 0`, | ||||
| 	`12345 & 0 = 0`, | ||||
| 	`0xff & 0xf = 0xf`, | ||||
| 	`? & 0 = ?`, | ||||
| 	`0 & ? = ?`, | ||||
|  | ||||
| 	`0 | 0 = 0`, | ||||
| 	`12345 | 0 = 12345`, | ||||
| 	`0xb | 0xa0 = 0xab`, | ||||
| 	`? | 0 = ?`, | ||||
| 	`0 | ? = ?`, | ||||
|  | ||||
| 	`0 ^ 0 = 0`, | ||||
| 	`1 ^ -1 = -2`, | ||||
| 	`? ^ 0 = ?`, | ||||
| 	`0 ^ ? = ?`, | ||||
|  | ||||
| 	`0 &^ 0 = 0`, | ||||
| 	`0xf &^ 1 = 0xe`, | ||||
| 	`1 &^ 0xf = 0`, | ||||
| 	// etc. | ||||
|  | ||||
| 	// shifts | ||||
| 	`0 << 0 = 0`, | ||||
| 	`1 << 10 = 1024`, | ||||
| 	`0 >> 0 = 0`, | ||||
| 	`1024 >> 10 == 1`, | ||||
| 	`? << 0 == ?`, | ||||
| 	`? >> 10 == ?`, | ||||
| 	// etc. | ||||
|  | ||||
| 	// comparisons | ||||
| 	`false == false = true`, | ||||
| 	`false == true = false`, | ||||
| 	`true == false = false`, | ||||
| 	`true == true = true`, | ||||
|  | ||||
| 	`false != false = false`, | ||||
| 	`false != true = true`, | ||||
| 	`true != false = true`, | ||||
| 	`true != true = false`, | ||||
|  | ||||
| 	`"foo" == "bar" = false`, | ||||
| 	`"foo" != "bar" = true`, | ||||
| 	`"foo" < "bar" = false`, | ||||
| 	`"foo" <= "bar" = false`, | ||||
| 	`"foo" > "bar" = true`, | ||||
| 	`"foo" >= "bar" = true`, | ||||
|  | ||||
| 	`0 == 0 = true`, | ||||
| 	`0 != 0 = false`, | ||||
| 	`0 < 10 = true`, | ||||
| 	`10 <= 10 = true`, | ||||
| 	`0 > 10 = false`, | ||||
| 	`10 >= 10 = true`, | ||||
|  | ||||
| 	`1/123456789 == 1/123456789 == true`, | ||||
| 	`1/123456789 != 1/123456789 == false`, | ||||
| 	`1/123456789 < 1/123456788 == true`, | ||||
| 	`1/123456788 <= 1/123456789 == false`, | ||||
| 	`0.11 > 0.11 = false`, | ||||
| 	`0.11 >= 0.11 = true`, | ||||
|  | ||||
| 	`? == 0 = false`, | ||||
| 	`? != 0 = false`, | ||||
| 	`? < 10 = false`, | ||||
| 	`? <= 10 = false`, | ||||
| 	`? > 10 = false`, | ||||
| 	`? >= 10 = false`, | ||||
|  | ||||
| 	`0 == ? = false`, | ||||
| 	`0 != ? = false`, | ||||
| 	`0 < ? = false`, | ||||
| 	`10 <= ? = false`, | ||||
| 	`0 > ? = false`, | ||||
| 	`10 >= ? = false`, | ||||
|  | ||||
| 	// etc. | ||||
| } | ||||
|  | ||||
| func TestOps(t *testing.T) { | ||||
| 	for _, test := range opTests { | ||||
| 		a := strings.Split(test, " ") | ||||
| 		i := 0 // operator index | ||||
|  | ||||
| 		var x, x0 Value | ||||
| 		switch len(a) { | ||||
| 		case 4: | ||||
| 			// unary operation | ||||
| 		case 5: | ||||
| 			// binary operation | ||||
| 			x, x0 = val(a[0]), val(a[0]) | ||||
| 			i = 1 | ||||
| 		default: | ||||
| 			t.Errorf("invalid test case: %s", test) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		op, ok := optab[a[i]] | ||||
| 		if !ok { | ||||
| 			panic("missing optab entry for " + a[i]) | ||||
| 		} | ||||
|  | ||||
| 		y, y0 := val(a[i+1]), val(a[i+1]) | ||||
|  | ||||
| 		got := doOp(x, op, y) | ||||
| 		want := val(a[i+3]) | ||||
| 		if !eql(got, want) { | ||||
| 			t.Errorf("%s: got %s; want %s", test, got, want) | ||||
| 		} | ||||
| 		if x0 != nil && !eql(x, x0) { | ||||
| 			t.Errorf("%s: x changed to %s", test, x) | ||||
| 		} | ||||
| 		if !eql(y, y0) { | ||||
| 			t.Errorf("%s: y changed to %s", test, y) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func eql(x, y Value) bool { | ||||
| 	_, ux := x.(unknownVal) | ||||
| 	_, uy := y.(unknownVal) | ||||
| 	if ux || uy { | ||||
| 		return ux == uy | ||||
| 	} | ||||
| 	return Compare(x, token.EQL, y) | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Support functions | ||||
|  | ||||
| func val(lit string) Value { | ||||
| 	if len(lit) == 0 { | ||||
| 		return MakeUnknown() | ||||
| 	} | ||||
|  | ||||
| 	switch lit { | ||||
| 	case "?": | ||||
| 		return MakeUnknown() | ||||
| 	case "true": | ||||
| 		return MakeBool(true) | ||||
| 	case "false": | ||||
| 		return MakeBool(false) | ||||
| 	} | ||||
|  | ||||
| 	tok := token.INT | ||||
| 	switch first, last := lit[0], lit[len(lit)-1]; { | ||||
| 	case first == '"' || first == '`': | ||||
| 		tok = token.STRING | ||||
| 		lit = strings.Replace(lit, "_", " ", -1) | ||||
| 	case first == '\'': | ||||
| 		tok = token.CHAR | ||||
| 	case last == 'i': | ||||
| 		tok = token.IMAG | ||||
| 	default: | ||||
| 		if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") { | ||||
| 			tok = token.FLOAT | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return MakeFromLiteral(lit, tok, 0) | ||||
| } | ||||
|  | ||||
| var optab = map[string]token.Token{ | ||||
| 	"!": token.NOT, | ||||
|  | ||||
| 	"+": token.ADD, | ||||
| 	"-": token.SUB, | ||||
| 	"*": token.MUL, | ||||
| 	"/": token.QUO, | ||||
| 	"%": token.REM, | ||||
|  | ||||
| 	"<<": token.SHL, | ||||
| 	">>": token.SHR, | ||||
|  | ||||
| 	"&":  token.AND, | ||||
| 	"|":  token.OR, | ||||
| 	"^":  token.XOR, | ||||
| 	"&^": token.AND_NOT, | ||||
|  | ||||
| 	"==": token.EQL, | ||||
| 	"!=": token.NEQ, | ||||
| 	"<":  token.LSS, | ||||
| 	"<=": token.LEQ, | ||||
| 	">":  token.GTR, | ||||
| 	">=": token.GEQ, | ||||
| } | ||||
|  | ||||
| func panicHandler(v *Value) { | ||||
| 	switch p := recover().(type) { | ||||
| 	case nil: | ||||
| 		// nothing to do | ||||
| 	case string: | ||||
| 		*v = MakeString(p) | ||||
| 	case error: | ||||
| 		*v = MakeString(p.Error()) | ||||
| 	default: | ||||
| 		panic(p) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func doOp(x Value, op token.Token, y Value) (z Value) { | ||||
| 	defer panicHandler(&z) | ||||
|  | ||||
| 	if x == nil { | ||||
| 		return UnaryOp(op, y, 0) | ||||
| 	} | ||||
|  | ||||
| 	switch op { | ||||
| 	case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ: | ||||
| 		return MakeBool(Compare(x, op, y)) | ||||
| 	case token.SHL, token.SHR: | ||||
| 		s, _ := Int64Val(y) | ||||
| 		return Shift(x, op, uint(s)) | ||||
| 	default: | ||||
| 		return BinaryOp(x, op, y) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Other tests | ||||
|  | ||||
| var fracTests = []string{ | ||||
| 	"0 0 1", | ||||
| 	"1 1 1", | ||||
| 	"-1 -1 1", | ||||
| 	"1.2 6 5", | ||||
| 	"-0.991 -991 1000", | ||||
| 	"1e100 1e100 1", | ||||
| } | ||||
|  | ||||
| func TestFractions(t *testing.T) { | ||||
| 	for _, test := range fracTests { | ||||
| 		a := strings.Split(test, " ") | ||||
| 		if len(a) != 3 { | ||||
| 			t.Errorf("invalid test case: %s", test) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		x := val(a[0]) | ||||
| 		n := val(a[1]) | ||||
| 		d := val(a[2]) | ||||
|  | ||||
| 		if got := Num(x); !eql(got, n) { | ||||
| 			t.Errorf("%s: got num = %s; want %s", test, got, n) | ||||
| 		} | ||||
|  | ||||
| 		if got := Denom(x); !eql(got, d) { | ||||
| 			t.Errorf("%s: got denom = %s; want %s", test, got, d) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var bytesTests = []string{ | ||||
| 	"0", | ||||
| 	"1", | ||||
| 	"123456789", | ||||
| 	"123456789012345678901234567890123456789012345678901234567890", | ||||
| } | ||||
|  | ||||
| func TestBytes(t *testing.T) { | ||||
| 	for _, test := range bytesTests { | ||||
| 		x := val(test) | ||||
| 		bytes := Bytes(x) | ||||
|  | ||||
| 		// special case 0 | ||||
| 		if Sign(x) == 0 && len(bytes) != 0 { | ||||
| 			t.Errorf("%s: got %v; want empty byte slice", test, bytes) | ||||
| 		} | ||||
|  | ||||
| 		if n := len(bytes); n > 0 && bytes[n-1] == 0 { | ||||
| 			t.Errorf("%s: got %v; want no leading 0 byte", test, bytes) | ||||
| 		} | ||||
|  | ||||
| 		if got := MakeFromBytes(bytes); !eql(got, x) { | ||||
| 			t.Errorf("%s: got %s; want %s (bytes = %v)", test, got, x, bytes) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestUnknown(t *testing.T) { | ||||
| 	u := MakeUnknown() | ||||
| 	var values = []Value{ | ||||
| 		u, | ||||
| 		MakeBool(false), // token.ADD ok below, operation is never considered | ||||
| 		MakeString(""), | ||||
| 		MakeInt64(1), | ||||
| 		MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT, 0), | ||||
| 		MakeFloat64(1.2), | ||||
| 		MakeImag(MakeFloat64(1.2)), | ||||
| 	} | ||||
| 	for _, val := range values { | ||||
| 		x, y := val, u | ||||
| 		for i := range [2]int{} { | ||||
| 			if i == 1 { | ||||
| 				x, y = y, x | ||||
| 			} | ||||
| 			if got := BinaryOp(x, token.ADD, y); got.Kind() != Unknown { | ||||
| 				t.Errorf("%s + %s: got %s; want %s", x, y, got, u) | ||||
| 			} | ||||
| 			if got := Compare(x, token.EQL, y); got { | ||||
| 				t.Errorf("%s == %s: got true; want false", x, y) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										7
									
								
								third_party/golang/go/doc/Makefile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								third_party/golang/go/doc/Makefile
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| # Copyright 2009 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. | ||||
|  | ||||
| # Script to test heading detection heuristic | ||||
| headscan: headscan.go | ||||
| 	go build headscan.go | ||||
							
								
								
									
										480
									
								
								third_party/golang/go/doc/comment.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										480
									
								
								third_party/golang/go/doc/comment.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,480 @@ | ||||
| // Copyright 2009 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. | ||||
|  | ||||
| // Godoc comment extraction and comment -> HTML formatting. | ||||
|  | ||||
| package doc | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"text/template" // for HTMLEscape | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	ldquo = []byte("“") | ||||
| 	rdquo = []byte("”") | ||||
| ) | ||||
|  | ||||
| // Escape comment text for HTML. If nice is set, | ||||
| // also turn `` into “ and '' into ”. | ||||
| func commentEscape(w io.Writer, text string, nice bool) { | ||||
| 	last := 0 | ||||
| 	if nice { | ||||
| 		for i := 0; i < len(text)-1; i++ { | ||||
| 			ch := text[i] | ||||
| 			if ch == text[i+1] && (ch == '`' || ch == '\'') { | ||||
| 				template.HTMLEscape(w, []byte(text[last:i])) | ||||
| 				last = i + 2 | ||||
| 				switch ch { | ||||
| 				case '`': | ||||
| 					w.Write(ldquo) | ||||
| 				case '\'': | ||||
| 					w.Write(rdquo) | ||||
| 				} | ||||
| 				i++ // loop will add one more | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	template.HTMLEscape(w, []byte(text[last:])) | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	// Regexp for Go identifiers | ||||
| 	identRx = `[\pL_][\pL_0-9]*` | ||||
|  | ||||
| 	// Regexp for URLs | ||||
| 	protocol = `https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero` | ||||
| 	hostPart = `[a-zA-Z0-9_@\-]+` | ||||
| 	filePart = `[a-zA-Z0-9_?%#~&/\-+=()]+` // parentheses may not be matching; see pairedParensPrefixLen | ||||
| 	urlRx    = `(` + protocol + `)://` +   // http:// | ||||
| 		hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/ | ||||
| 		filePart + `([:.,]` + filePart + `)*` | ||||
| ) | ||||
|  | ||||
| var matchRx = regexp.MustCompile(`(` + urlRx + `)|(` + identRx + `)`) | ||||
|  | ||||
| var ( | ||||
| 	html_a      = []byte(`<a href="`) | ||||
| 	html_aq     = []byte(`">`) | ||||
| 	html_enda   = []byte("</a>") | ||||
| 	html_i      = []byte("<i>") | ||||
| 	html_endi   = []byte("</i>") | ||||
| 	html_p      = []byte("<p>\n") | ||||
| 	html_endp   = []byte("</p>\n") | ||||
| 	html_pre    = []byte("<pre>") | ||||
| 	html_endpre = []byte("</pre>\n") | ||||
| 	html_h      = []byte(`<h3 id="`) | ||||
| 	html_hq     = []byte(`">`) | ||||
| 	html_endh   = []byte("</h3>\n") | ||||
| ) | ||||
|  | ||||
| // pairedParensPrefixLen returns the length of the longest prefix of s containing paired parentheses. | ||||
| func pairedParensPrefixLen(s string) int { | ||||
| 	parens := 0 | ||||
| 	l := len(s) | ||||
| 	for i, ch := range s { | ||||
| 		switch ch { | ||||
| 		case '(': | ||||
| 			if parens == 0 { | ||||
| 				l = i | ||||
| 			} | ||||
| 			parens++ | ||||
| 		case ')': | ||||
| 			parens-- | ||||
| 			if parens == 0 { | ||||
| 				l = len(s) | ||||
| 			} else if parens < 0 { | ||||
| 				return i | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return l | ||||
| } | ||||
|  | ||||
| // Emphasize and escape a line of text for HTML. URLs are converted into links; | ||||
| // if the URL also appears in the words map, the link is taken from the map (if | ||||
| // the corresponding map value is the empty string, the URL is not converted | ||||
| // into a link). Go identifiers that appear in the words map are italicized; if | ||||
| // the corresponding map value is not the empty string, it is considered a URL | ||||
| // and the word is converted into a link. If nice is set, the remaining text's | ||||
| // appearance is improved where it makes sense (e.g., `` is turned into “ | ||||
| // and '' into ”). | ||||
| func emphasize(w io.Writer, line string, words map[string]string, nice bool) { | ||||
| 	for { | ||||
| 		m := matchRx.FindStringSubmatchIndex(line) | ||||
| 		if m == nil { | ||||
| 			break | ||||
| 		} | ||||
| 		// m >= 6 (two parenthesized sub-regexps in matchRx, 1st one is urlRx) | ||||
|  | ||||
| 		// write text before match | ||||
| 		commentEscape(w, line[0:m[0]], nice) | ||||
|  | ||||
| 		// adjust match if necessary | ||||
| 		match := line[m[0]:m[1]] | ||||
| 		if n := pairedParensPrefixLen(match); n < len(match) { | ||||
| 			// match contains unpaired parentheses (rare); | ||||
| 			// redo matching with shortened line for correct indices | ||||
| 			m = matchRx.FindStringSubmatchIndex(line[:m[0]+n]) | ||||
| 			match = match[:n] | ||||
| 		} | ||||
|  | ||||
| 		// analyze match | ||||
| 		url := "" | ||||
| 		italics := false | ||||
| 		if words != nil { | ||||
| 			url, italics = words[match] | ||||
| 		} | ||||
| 		if m[2] >= 0 { | ||||
| 			// match against first parenthesized sub-regexp; must be match against urlRx | ||||
| 			if !italics { | ||||
| 				// no alternative URL in words list, use match instead | ||||
| 				url = match | ||||
| 			} | ||||
| 			italics = false // don't italicize URLs | ||||
| 		} | ||||
|  | ||||
| 		// write match | ||||
| 		if len(url) > 0 { | ||||
| 			w.Write(html_a) | ||||
| 			template.HTMLEscape(w, []byte(url)) | ||||
| 			w.Write(html_aq) | ||||
| 		} | ||||
| 		if italics { | ||||
| 			w.Write(html_i) | ||||
| 		} | ||||
| 		commentEscape(w, match, nice) | ||||
| 		if italics { | ||||
| 			w.Write(html_endi) | ||||
| 		} | ||||
| 		if len(url) > 0 { | ||||
| 			w.Write(html_enda) | ||||
| 		} | ||||
|  | ||||
| 		// advance | ||||
| 		line = line[m[1]:] | ||||
| 	} | ||||
| 	commentEscape(w, line, nice) | ||||
| } | ||||
|  | ||||
| func indentLen(s string) int { | ||||
| 	i := 0 | ||||
| 	for i < len(s) && (s[i] == ' ' || s[i] == '\t') { | ||||
| 		i++ | ||||
| 	} | ||||
| 	return i | ||||
| } | ||||
|  | ||||
| func isBlank(s string) bool { | ||||
| 	return len(s) == 0 || (len(s) == 1 && s[0] == '\n') | ||||
| } | ||||
|  | ||||
| func commonPrefix(a, b string) string { | ||||
| 	i := 0 | ||||
| 	for i < len(a) && i < len(b) && a[i] == b[i] { | ||||
| 		i++ | ||||
| 	} | ||||
| 	return a[0:i] | ||||
| } | ||||
|  | ||||
| func unindent(block []string) { | ||||
| 	if len(block) == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// compute maximum common white prefix | ||||
| 	prefix := block[0][0:indentLen(block[0])] | ||||
| 	for _, line := range block { | ||||
| 		if !isBlank(line) { | ||||
| 			prefix = commonPrefix(prefix, line[0:indentLen(line)]) | ||||
| 		} | ||||
| 	} | ||||
| 	n := len(prefix) | ||||
|  | ||||
| 	// remove | ||||
| 	for i, line := range block { | ||||
| 		if !isBlank(line) { | ||||
| 			block[i] = line[n:] | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // heading returns the trimmed line if it passes as a section heading; | ||||
| // otherwise it returns the empty string. | ||||
| func heading(line string) string { | ||||
| 	line = strings.TrimSpace(line) | ||||
| 	if len(line) == 0 { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	// a heading must start with an uppercase letter | ||||
| 	r, _ := utf8.DecodeRuneInString(line) | ||||
| 	if !unicode.IsLetter(r) || !unicode.IsUpper(r) { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	// it must end in a letter or digit: | ||||
| 	r, _ = utf8.DecodeLastRuneInString(line) | ||||
| 	if !unicode.IsLetter(r) && !unicode.IsDigit(r) { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	// exclude lines with illegal characters | ||||
| 	if strings.IndexAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") >= 0 { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	// allow "'" for possessive "'s" only | ||||
| 	for b := line; ; { | ||||
| 		i := strings.IndexRune(b, '\'') | ||||
| 		if i < 0 { | ||||
| 			break | ||||
| 		} | ||||
| 		if i+1 >= len(b) || b[i+1] != 's' || (i+2 < len(b) && b[i+2] != ' ') { | ||||
| 			return "" // not followed by "s " | ||||
| 		} | ||||
| 		b = b[i+2:] | ||||
| 	} | ||||
|  | ||||
| 	return line | ||||
| } | ||||
|  | ||||
| type op int | ||||
|  | ||||
| const ( | ||||
| 	opPara op = iota | ||||
| 	opHead | ||||
| 	opPre | ||||
| ) | ||||
|  | ||||
| type block struct { | ||||
| 	op    op | ||||
| 	lines []string | ||||
| } | ||||
|  | ||||
| var nonAlphaNumRx = regexp.MustCompile(`[^a-zA-Z0-9]`) | ||||
|  | ||||
| func anchorID(line string) string { | ||||
| 	// Add a "hdr-" prefix to avoid conflicting with IDs used for package symbols. | ||||
| 	return "hdr-" + nonAlphaNumRx.ReplaceAllString(line, "_") | ||||
| } | ||||
|  | ||||
| // ToHTML converts comment text to formatted HTML. | ||||
| // The comment was prepared by DocReader, | ||||
| // so it is known not to have leading, trailing blank lines | ||||
| // nor to have trailing spaces at the end of lines. | ||||
| // The comment markers have already been removed. | ||||
| // | ||||
| // Each span of unindented non-blank lines is converted into | ||||
| // a single paragraph. There is one exception to the rule: a span that | ||||
| // consists of a single line, is followed by another paragraph span, | ||||
| // begins with a capital letter, and contains no punctuation | ||||
| // is formatted as a heading. | ||||
| // | ||||
| // A span of indented lines is converted into a <pre> block, | ||||
| // with the common indent prefix removed. | ||||
| // | ||||
| // URLs in the comment text are converted into links; if the URL also appears | ||||
| // in the words map, the link is taken from the map (if the corresponding map | ||||
| // value is the empty string, the URL is not converted into a link). | ||||
| // | ||||
| // Go identifiers that appear in the words map are italicized; if the corresponding | ||||
| // map value is not the empty string, it is considered a URL and the word is converted | ||||
| // into a link. | ||||
| func ToHTML(w io.Writer, text string, words map[string]string) { | ||||
| 	for _, b := range blocks(text) { | ||||
| 		switch b.op { | ||||
| 		case opPara: | ||||
| 			w.Write(html_p) | ||||
| 			for _, line := range b.lines { | ||||
| 				emphasize(w, line, words, true) | ||||
| 			} | ||||
| 			w.Write(html_endp) | ||||
| 		case opHead: | ||||
| 			w.Write(html_h) | ||||
| 			id := "" | ||||
| 			for _, line := range b.lines { | ||||
| 				if id == "" { | ||||
| 					id = anchorID(line) | ||||
| 					w.Write([]byte(id)) | ||||
| 					w.Write(html_hq) | ||||
| 				} | ||||
| 				commentEscape(w, line, true) | ||||
| 			} | ||||
| 			if id == "" { | ||||
| 				w.Write(html_hq) | ||||
| 			} | ||||
| 			w.Write(html_endh) | ||||
| 		case opPre: | ||||
| 			w.Write(html_pre) | ||||
| 			for _, line := range b.lines { | ||||
| 				emphasize(w, line, nil, false) | ||||
| 			} | ||||
| 			w.Write(html_endpre) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func blocks(text string) []block { | ||||
| 	var ( | ||||
| 		out  []block | ||||
| 		para []string | ||||
|  | ||||
| 		lastWasBlank   = false | ||||
| 		lastWasHeading = false | ||||
| 	) | ||||
|  | ||||
| 	close := func() { | ||||
| 		if para != nil { | ||||
| 			out = append(out, block{opPara, para}) | ||||
| 			para = nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	lines := strings.SplitAfter(text, "\n") | ||||
| 	unindent(lines) | ||||
| 	for i := 0; i < len(lines); { | ||||
| 		line := lines[i] | ||||
| 		if isBlank(line) { | ||||
| 			// close paragraph | ||||
| 			close() | ||||
| 			i++ | ||||
| 			lastWasBlank = true | ||||
| 			continue | ||||
| 		} | ||||
| 		if indentLen(line) > 0 { | ||||
| 			// close paragraph | ||||
| 			close() | ||||
|  | ||||
| 			// count indented or blank lines | ||||
| 			j := i + 1 | ||||
| 			for j < len(lines) && (isBlank(lines[j]) || indentLen(lines[j]) > 0) { | ||||
| 				j++ | ||||
| 			} | ||||
| 			// but not trailing blank lines | ||||
| 			for j > i && isBlank(lines[j-1]) { | ||||
| 				j-- | ||||
| 			} | ||||
| 			pre := lines[i:j] | ||||
| 			i = j | ||||
|  | ||||
| 			unindent(pre) | ||||
|  | ||||
| 			// put those lines in a pre block | ||||
| 			out = append(out, block{opPre, pre}) | ||||
| 			lastWasHeading = false | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if lastWasBlank && !lastWasHeading && i+2 < len(lines) && | ||||
| 			isBlank(lines[i+1]) && !isBlank(lines[i+2]) && indentLen(lines[i+2]) == 0 { | ||||
| 			// current line is non-blank, surrounded by blank lines | ||||
| 			// and the next non-blank line is not indented: this | ||||
| 			// might be a heading. | ||||
| 			if head := heading(line); head != "" { | ||||
| 				close() | ||||
| 				out = append(out, block{opHead, []string{head}}) | ||||
| 				i += 2 | ||||
| 				lastWasHeading = true | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// open paragraph | ||||
| 		lastWasBlank = false | ||||
| 		lastWasHeading = false | ||||
| 		para = append(para, lines[i]) | ||||
| 		i++ | ||||
| 	} | ||||
| 	close() | ||||
|  | ||||
| 	return out | ||||
| } | ||||
|  | ||||
| // ToText prepares comment text for presentation in textual output. | ||||
| // It wraps paragraphs of text to width or fewer Unicode code points | ||||
| // and then prefixes each line with the indent.  In preformatted sections | ||||
| // (such as program text), it prefixes each non-blank line with preIndent. | ||||
| func ToText(w io.Writer, text string, indent, preIndent string, width int) { | ||||
| 	l := lineWrapper{ | ||||
| 		out:    w, | ||||
| 		width:  width, | ||||
| 		indent: indent, | ||||
| 	} | ||||
| 	for _, b := range blocks(text) { | ||||
| 		switch b.op { | ||||
| 		case opPara: | ||||
| 			// l.write will add leading newline if required | ||||
| 			for _, line := range b.lines { | ||||
| 				l.write(line) | ||||
| 			} | ||||
| 			l.flush() | ||||
| 		case opHead: | ||||
| 			w.Write(nl) | ||||
| 			for _, line := range b.lines { | ||||
| 				l.write(line + "\n") | ||||
| 			} | ||||
| 			l.flush() | ||||
| 		case opPre: | ||||
| 			w.Write(nl) | ||||
| 			for _, line := range b.lines { | ||||
| 				if isBlank(line) { | ||||
| 					w.Write([]byte("\n")) | ||||
| 				} else { | ||||
| 					w.Write([]byte(preIndent)) | ||||
| 					w.Write([]byte(line)) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type lineWrapper struct { | ||||
| 	out       io.Writer | ||||
| 	printed   bool | ||||
| 	width     int | ||||
| 	indent    string | ||||
| 	n         int | ||||
| 	pendSpace int | ||||
| } | ||||
|  | ||||
| var nl = []byte("\n") | ||||
| var space = []byte(" ") | ||||
|  | ||||
| func (l *lineWrapper) write(text string) { | ||||
| 	if l.n == 0 && l.printed { | ||||
| 		l.out.Write(nl) // blank line before new paragraph | ||||
| 	} | ||||
| 	l.printed = true | ||||
|  | ||||
| 	for _, f := range strings.Fields(text) { | ||||
| 		w := utf8.RuneCountInString(f) | ||||
| 		// wrap if line is too long | ||||
| 		if l.n > 0 && l.n+l.pendSpace+w > l.width { | ||||
| 			l.out.Write(nl) | ||||
| 			l.n = 0 | ||||
| 			l.pendSpace = 0 | ||||
| 		} | ||||
| 		if l.n == 0 { | ||||
| 			l.out.Write([]byte(l.indent)) | ||||
| 		} | ||||
| 		l.out.Write(space[:l.pendSpace]) | ||||
| 		l.out.Write([]byte(f)) | ||||
| 		l.n += l.pendSpace + w | ||||
| 		l.pendSpace = 1 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (l *lineWrapper) flush() { | ||||
| 	if l.n == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	l.out.Write(nl) | ||||
| 	l.pendSpace = 0 | ||||
| 	l.n = 0 | ||||
| } | ||||
							
								
								
									
										207
									
								
								third_party/golang/go/doc/comment_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								third_party/golang/go/doc/comment_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,207 @@ | ||||
| // Copyright 2011 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. | ||||
|  | ||||
| package doc | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| var headingTests = []struct { | ||||
| 	line string | ||||
| 	ok   bool | ||||
| }{ | ||||
| 	{"Section", true}, | ||||
| 	{"A typical usage", true}, | ||||
| 	{"ΔΛΞ is Greek", true}, | ||||
| 	{"Foo 42", true}, | ||||
| 	{"", false}, | ||||
| 	{"section", false}, | ||||
| 	{"A typical usage:", false}, | ||||
| 	{"This code:", false}, | ||||
| 	{"δ is Greek", false}, | ||||
| 	{"Foo §", false}, | ||||
| 	{"Fermat's Last Sentence", true}, | ||||
| 	{"Fermat's", true}, | ||||
| 	{"'sX", false}, | ||||
| 	{"Ted 'Too' Bar", false}, | ||||
| 	{"Use n+m", false}, | ||||
| 	{"Scanning:", false}, | ||||
| 	{"N:M", false}, | ||||
| } | ||||
|  | ||||
| func TestIsHeading(t *testing.T) { | ||||
| 	for _, tt := range headingTests { | ||||
| 		if h := heading(tt.line); (len(h) > 0) != tt.ok { | ||||
| 			t.Errorf("isHeading(%q) = %v, want %v", tt.line, h, tt.ok) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var blocksTests = []struct { | ||||
| 	in   string | ||||
| 	out  []block | ||||
| 	text string | ||||
| }{ | ||||
| 	{ | ||||
| 		in: `Para 1. | ||||
| Para 1 line 2. | ||||
|  | ||||
| Para 2. | ||||
|  | ||||
| Section | ||||
|  | ||||
| Para 3. | ||||
|  | ||||
| 	pre | ||||
| 	pre1 | ||||
|  | ||||
| Para 4. | ||||
|  | ||||
| 	pre | ||||
| 	pre1 | ||||
|  | ||||
| 	pre2 | ||||
|  | ||||
| Para 5. | ||||
|  | ||||
|  | ||||
| 	pre | ||||
|  | ||||
|  | ||||
| 	pre1 | ||||
| 	pre2 | ||||
|  | ||||
| Para 6. | ||||
| 	pre | ||||
| 	pre2 | ||||
| `, | ||||
| 		out: []block{ | ||||
| 			{opPara, []string{"Para 1.\n", "Para 1 line 2.\n"}}, | ||||
| 			{opPara, []string{"Para 2.\n"}}, | ||||
| 			{opHead, []string{"Section"}}, | ||||
| 			{opPara, []string{"Para 3.\n"}}, | ||||
| 			{opPre, []string{"pre\n", "pre1\n"}}, | ||||
| 			{opPara, []string{"Para 4.\n"}}, | ||||
| 			{opPre, []string{"pre\n", "pre1\n", "\n", "pre2\n"}}, | ||||
| 			{opPara, []string{"Para 5.\n"}}, | ||||
| 			{opPre, []string{"pre\n", "\n", "\n", "pre1\n", "pre2\n"}}, | ||||
| 			{opPara, []string{"Para 6.\n"}}, | ||||
| 			{opPre, []string{"pre\n", "pre2\n"}}, | ||||
| 		}, | ||||
| 		text: `.   Para 1. Para 1 line 2. | ||||
|  | ||||
| .   Para 2. | ||||
|  | ||||
|  | ||||
| .   Section | ||||
|  | ||||
| .   Para 3. | ||||
|  | ||||
| $	pre | ||||
| $	pre1 | ||||
|  | ||||
| .   Para 4. | ||||
|  | ||||
| $	pre | ||||
| $	pre1 | ||||
|  | ||||
| $	pre2 | ||||
|  | ||||
| .   Para 5. | ||||
|  | ||||
| $	pre | ||||
|  | ||||
|  | ||||
| $	pre1 | ||||
| $	pre2 | ||||
|  | ||||
| .   Para 6. | ||||
|  | ||||
| $	pre | ||||
| $	pre2 | ||||
| `, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func TestBlocks(t *testing.T) { | ||||
| 	for i, tt := range blocksTests { | ||||
| 		b := blocks(tt.in) | ||||
| 		if !reflect.DeepEqual(b, tt.out) { | ||||
| 			t.Errorf("#%d: mismatch\nhave: %v\nwant: %v", i, b, tt.out) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestToText(t *testing.T) { | ||||
| 	var buf bytes.Buffer | ||||
| 	for i, tt := range blocksTests { | ||||
| 		ToText(&buf, tt.in, ".   ", "$\t", 40) | ||||
| 		if have := buf.String(); have != tt.text { | ||||
| 			t.Errorf("#%d: mismatch\nhave: %s\nwant: %s\nhave vs want:\n%q\n%q", i, have, tt.text, have, tt.text) | ||||
| 		} | ||||
| 		buf.Reset() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var emphasizeTests = []struct { | ||||
| 	in, out string | ||||
| }{ | ||||
| 	{"http://www.google.com/", `<a href="http://www.google.com/">http://www.google.com/</a>`}, | ||||
| 	{"https://www.google.com/", `<a href="https://www.google.com/">https://www.google.com/</a>`}, | ||||
| 	{"http://www.google.com/path.", `<a href="http://www.google.com/path">http://www.google.com/path</a>.`}, | ||||
| 	{"http://en.wikipedia.org/wiki/Camellia_(cipher)", `<a href="http://en.wikipedia.org/wiki/Camellia_(cipher)">http://en.wikipedia.org/wiki/Camellia_(cipher)</a>`}, | ||||
| 	{"(http://www.google.com/)", `(<a href="http://www.google.com/">http://www.google.com/</a>)`}, | ||||
| 	{"http://gmail.com)", `<a href="http://gmail.com">http://gmail.com</a>)`}, | ||||
| 	{"((http://gmail.com))", `((<a href="http://gmail.com">http://gmail.com</a>))`}, | ||||
| 	{"http://gmail.com ((http://gmail.com)) ()", `<a href="http://gmail.com">http://gmail.com</a> ((<a href="http://gmail.com">http://gmail.com</a>)) ()`}, | ||||
| 	{"Foo bar http://example.com/ quux!", `Foo bar <a href="http://example.com/">http://example.com/</a> quux!`}, | ||||
| 	{"Hello http://example.com/%2f/ /world.", `Hello <a href="http://example.com/%2f/">http://example.com/%2f/</a> /world.`}, | ||||
| 	{"Lorem http: ipsum //host/path", "Lorem http: ipsum //host/path"}, | ||||
| 	{"javascript://is/not/linked", "javascript://is/not/linked"}, | ||||
| } | ||||
|  | ||||
| func TestEmphasize(t *testing.T) { | ||||
| 	for i, tt := range emphasizeTests { | ||||
| 		var buf bytes.Buffer | ||||
| 		emphasize(&buf, tt.in, nil, true) | ||||
| 		out := buf.String() | ||||
| 		if out != tt.out { | ||||
| 			t.Errorf("#%d: mismatch\nhave: %v\nwant: %v", i, out, tt.out) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var pairedParensPrefixLenTests = []struct { | ||||
| 	in, out string | ||||
| }{ | ||||
| 	{"", ""}, | ||||
| 	{"foo", "foo"}, | ||||
| 	{"()", "()"}, | ||||
| 	{"foo()", "foo()"}, | ||||
| 	{"foo()()()", "foo()()()"}, | ||||
| 	{"foo()((()()))", "foo()((()()))"}, | ||||
| 	{"foo()((()()))bar", "foo()((()()))bar"}, | ||||
| 	{"foo)", "foo"}, | ||||
| 	{"foo))", "foo"}, | ||||
| 	{"foo)))))", "foo"}, | ||||
| 	{"(foo", ""}, | ||||
| 	{"((foo", ""}, | ||||
| 	{"(((((foo", ""}, | ||||
| 	{"(foo)", "(foo)"}, | ||||
| 	{"((((foo))))", "((((foo))))"}, | ||||
| 	{"foo()())", "foo()()"}, | ||||
| 	{"foo((()())", "foo"}, | ||||
| 	{"foo((()())) (() foo ", "foo((()())) "}, | ||||
| } | ||||
|  | ||||
| func TestPairedParensPrefixLen(t *testing.T) { | ||||
| 	for i, tt := range pairedParensPrefixLenTests { | ||||
| 		if out := tt.in[:pairedParensPrefixLen(tt.in)]; out != tt.out { | ||||
| 			t.Errorf("#%d: mismatch\nhave: %q\nwant: %q", i, out, tt.out) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										112
									
								
								third_party/golang/go/doc/doc.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								third_party/golang/go/doc/doc.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| // Copyright 2009 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. | ||||
|  | ||||
| // Package doc extracts source code documentation from a Go AST. | ||||
| package doc | ||||
|  | ||||
| import ( | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/ast" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| ) | ||||
|  | ||||
| // Package is the documentation for an entire package. | ||||
| type Package struct { | ||||
| 	Doc        string | ||||
| 	Name       string | ||||
| 	ImportPath string | ||||
| 	Imports    []string | ||||
| 	Filenames  []string | ||||
| 	Notes      map[string][]*Note | ||||
|  | ||||
| 	// Deprecated: For backward compatibility Bugs is still populated, | ||||
| 	// but all new code should use Notes instead. | ||||
| 	Bugs []string | ||||
|  | ||||
| 	// declarations | ||||
| 	Consts []*Value | ||||
| 	Types  []*Type | ||||
| 	Vars   []*Value | ||||
| 	Funcs  []*Func | ||||
| } | ||||
|  | ||||
| // Value is the documentation for a (possibly grouped) var or const declaration. | ||||
| type Value struct { | ||||
| 	Doc   string | ||||
| 	Names []string // var or const names in declaration order | ||||
| 	Decl  *ast.GenDecl | ||||
|  | ||||
| 	order int | ||||
| } | ||||
|  | ||||
| // Type is the documentation for a type declaration. | ||||
| type Type struct { | ||||
| 	Doc  string | ||||
| 	Name string | ||||
| 	Decl *ast.GenDecl | ||||
|  | ||||
| 	// associated declarations | ||||
| 	Consts  []*Value // sorted list of constants of (mostly) this type | ||||
| 	Vars    []*Value // sorted list of variables of (mostly) this type | ||||
| 	Funcs   []*Func  // sorted list of functions returning this type | ||||
| 	Methods []*Func  // sorted list of methods (including embedded ones) of this type | ||||
| } | ||||
|  | ||||
| // Func is the documentation for a func declaration. | ||||
| type Func struct { | ||||
| 	Doc  string | ||||
| 	Name string | ||||
| 	Decl *ast.FuncDecl | ||||
|  | ||||
| 	// methods | ||||
| 	// (for functions, these fields have the respective zero value) | ||||
| 	Recv  string // actual   receiver "T" or "*T" | ||||
| 	Orig  string // original receiver "T" or "*T" | ||||
| 	Level int    // embedding level; 0 means not embedded | ||||
| } | ||||
|  | ||||
| // A Note represents a marked comment starting with "MARKER(uid): note body". | ||||
| // Any note with a marker of 2 or more upper case [A-Z] letters and a uid of | ||||
| // at least one character is recognized. The ":" following the uid is optional. | ||||
| // Notes are collected in the Package.Notes map indexed by the notes marker. | ||||
| type Note struct { | ||||
| 	Pos, End token.Pos // position range of the comment containing the marker | ||||
| 	UID      string    // uid found with the marker | ||||
| 	Body     string    // note body text | ||||
| } | ||||
|  | ||||
| // Mode values control the operation of New. | ||||
| type Mode int | ||||
|  | ||||
| const ( | ||||
| 	// extract documentation for all package-level declarations, | ||||
| 	// not just exported ones | ||||
| 	AllDecls Mode = 1 << iota | ||||
|  | ||||
| 	// show all embedded methods, not just the ones of | ||||
| 	// invisible (unexported) anonymous fields | ||||
| 	AllMethods | ||||
| ) | ||||
|  | ||||
| // New computes the package documentation for the given package AST. | ||||
| // New takes ownership of the AST pkg and may edit or overwrite it. | ||||
| // | ||||
| func New(pkg *ast.Package, importPath string, mode Mode) *Package { | ||||
| 	var r reader | ||||
| 	r.readPackage(pkg, mode) | ||||
| 	r.computeMethodSets() | ||||
| 	r.cleanupTypes() | ||||
| 	return &Package{ | ||||
| 		Doc:        r.doc, | ||||
| 		Name:       pkg.Name, | ||||
| 		ImportPath: importPath, | ||||
| 		Imports:    sortedKeys(r.imports), | ||||
| 		Filenames:  r.filenames, | ||||
| 		Notes:      r.notes, | ||||
| 		Bugs:       noteBodies(r.notes["BUG"]), | ||||
| 		Consts:     sortedValues(r.values, token.CONST), | ||||
| 		Types:      sortedTypes(r.types, mode&AllMethods != 0), | ||||
| 		Vars:       sortedValues(r.values, token.VAR), | ||||
| 		Funcs:      sortedFuncs(r.funcs, true), | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										146
									
								
								third_party/golang/go/doc/doc_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								third_party/golang/go/doc/doc_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| package doc | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/parser" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/printer" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 	"text/template" | ||||
| ) | ||||
|  | ||||
| var update = flag.Bool("update", false, "update golden (.out) files") | ||||
| var files = flag.String("files", "", "consider only Go test files matching this regular expression") | ||||
|  | ||||
| const dataDir = "testdata" | ||||
|  | ||||
| var templateTxt = readTemplate("template.txt") | ||||
|  | ||||
| func readTemplate(filename string) *template.Template { | ||||
| 	t := template.New(filename) | ||||
| 	t.Funcs(template.FuncMap{ | ||||
| 		"node":     nodeFmt, | ||||
| 		"synopsis": synopsisFmt, | ||||
| 		"indent":   indentFmt, | ||||
| 	}) | ||||
| 	return template.Must(t.ParseFiles(filepath.Join(dataDir, filename))) | ||||
| } | ||||
|  | ||||
| func nodeFmt(node interface{}, fset *token.FileSet) string { | ||||
| 	var buf bytes.Buffer | ||||
| 	printer.Fprint(&buf, fset, node) | ||||
| 	return strings.Replace(strings.TrimSpace(buf.String()), "\n", "\n\t", -1) | ||||
| } | ||||
|  | ||||
| func synopsisFmt(s string) string { | ||||
| 	const n = 64 | ||||
| 	if len(s) > n { | ||||
| 		// cut off excess text and go back to a word boundary | ||||
| 		s = s[0:n] | ||||
| 		if i := strings.LastIndexAny(s, "\t\n "); i >= 0 { | ||||
| 			s = s[0:i] | ||||
| 		} | ||||
| 		s = strings.TrimSpace(s) + " ..." | ||||
| 	} | ||||
| 	return "// " + strings.Replace(s, "\n", " ", -1) | ||||
| } | ||||
|  | ||||
| func indentFmt(indent, s string) string { | ||||
| 	end := "" | ||||
| 	if strings.HasSuffix(s, "\n") { | ||||
| 		end = "\n" | ||||
| 		s = s[:len(s)-1] | ||||
| 	} | ||||
| 	return indent + strings.Replace(s, "\n", "\n"+indent, -1) + end | ||||
| } | ||||
|  | ||||
| func isGoFile(fi os.FileInfo) bool { | ||||
| 	name := fi.Name() | ||||
| 	return !fi.IsDir() && | ||||
| 		len(name) > 0 && name[0] != '.' && // ignore .files | ||||
| 		filepath.Ext(name) == ".go" | ||||
| } | ||||
|  | ||||
| type bundle struct { | ||||
| 	*Package | ||||
| 	FSet *token.FileSet | ||||
| } | ||||
|  | ||||
| func test(t *testing.T, mode Mode) { | ||||
| 	// determine file filter | ||||
| 	filter := isGoFile | ||||
| 	if *files != "" { | ||||
| 		rx, err := regexp.Compile(*files) | ||||
| 		if err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
| 		filter = func(fi os.FileInfo) bool { | ||||
| 			return isGoFile(fi) && rx.MatchString(fi.Name()) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// get packages | ||||
| 	fset := token.NewFileSet() | ||||
| 	pkgs, err := parser.ParseDir(fset, dataDir, filter, parser.ParseComments) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// test packages | ||||
| 	for _, pkg := range pkgs { | ||||
| 		importpath := dataDir + "/" + pkg.Name | ||||
| 		doc := New(pkg, importpath, mode) | ||||
|  | ||||
| 		// golden files always use / in filenames - canonicalize them | ||||
| 		for i, filename := range doc.Filenames { | ||||
| 			doc.Filenames[i] = filepath.ToSlash(filename) | ||||
| 		} | ||||
|  | ||||
| 		// print documentation | ||||
| 		var buf bytes.Buffer | ||||
| 		if err := templateTxt.Execute(&buf, bundle{doc, fset}); err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
| 		got := buf.Bytes() | ||||
|  | ||||
| 		// update golden file if necessary | ||||
| 		golden := filepath.Join(dataDir, fmt.Sprintf("%s.%d.golden", pkg.Name, mode)) | ||||
| 		if *update { | ||||
| 			err := ioutil.WriteFile(golden, got, 0644) | ||||
| 			if err != nil { | ||||
| 				t.Error(err) | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// get golden file | ||||
| 		want, err := ioutil.ReadFile(golden) | ||||
| 		if err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// compare | ||||
| 		if !bytes.Equal(got, want) { | ||||
| 			t.Errorf("package %s\n\tgot:\n%s\n\twant:\n%s", pkg.Name, got, want) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Test(t *testing.T) { | ||||
| 	test(t, 0) | ||||
| 	test(t, AllDecls) | ||||
| 	test(t, AllMethods) | ||||
| } | ||||
							
								
								
									
										355
									
								
								third_party/golang/go/doc/example.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										355
									
								
								third_party/golang/go/doc/example.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,355 @@ | ||||
| // Copyright 2011 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. | ||||
|  | ||||
| // Extract example functions from file ASTs. | ||||
|  | ||||
| package doc | ||||
|  | ||||
| import ( | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/ast" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"path" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| // An Example represents an example function found in a source files. | ||||
| type Example struct { | ||||
| 	Name        string // name of the item being exemplified | ||||
| 	Doc         string // example function doc string | ||||
| 	Code        ast.Node | ||||
| 	Play        *ast.File // a whole program version of the example | ||||
| 	Comments    []*ast.CommentGroup | ||||
| 	Output      string // expected output | ||||
| 	EmptyOutput bool   // expect empty output | ||||
| 	Order       int    // original source code order | ||||
| } | ||||
|  | ||||
| // Examples returns the examples found in the files, sorted by Name field. | ||||
| // The Order fields record the order in which the examples were encountered. | ||||
| // | ||||
| // Playable Examples must be in a package whose name ends in "_test". | ||||
| // An Example is "playable" (the Play field is non-nil) in either of these | ||||
| // circumstances: | ||||
| //   - The example function is self-contained: the function references only | ||||
| //     identifiers from other packages (or predeclared identifiers, such as | ||||
| //     "int") and the test file does not include a dot import. | ||||
| //   - The entire test file is the example: the file contains exactly one | ||||
| //     example function, zero test or benchmark functions, and at least one | ||||
| //     top-level function, type, variable, or constant declaration other | ||||
| //     than the example function. | ||||
| func Examples(files ...*ast.File) []*Example { | ||||
| 	var list []*Example | ||||
| 	for _, file := range files { | ||||
| 		hasTests := false // file contains tests or benchmarks | ||||
| 		numDecl := 0      // number of non-import declarations in the file | ||||
| 		var flist []*Example | ||||
| 		for _, decl := range file.Decls { | ||||
| 			if g, ok := decl.(*ast.GenDecl); ok && g.Tok != token.IMPORT { | ||||
| 				numDecl++ | ||||
| 				continue | ||||
| 			} | ||||
| 			f, ok := decl.(*ast.FuncDecl) | ||||
| 			if !ok { | ||||
| 				continue | ||||
| 			} | ||||
| 			numDecl++ | ||||
| 			name := f.Name.Name | ||||
| 			if isTest(name, "Test") || isTest(name, "Benchmark") { | ||||
| 				hasTests = true | ||||
| 				continue | ||||
| 			} | ||||
| 			if !isTest(name, "Example") { | ||||
| 				continue | ||||
| 			} | ||||
| 			var doc string | ||||
| 			if f.Doc != nil { | ||||
| 				doc = f.Doc.Text() | ||||
| 			} | ||||
| 			output, hasOutput := exampleOutput(f.Body, file.Comments) | ||||
| 			flist = append(flist, &Example{ | ||||
| 				Name:        name[len("Example"):], | ||||
| 				Doc:         doc, | ||||
| 				Code:        f.Body, | ||||
| 				Play:        playExample(file, f.Body), | ||||
| 				Comments:    file.Comments, | ||||
| 				Output:      output, | ||||
| 				EmptyOutput: output == "" && hasOutput, | ||||
| 				Order:       len(flist), | ||||
| 			}) | ||||
| 		} | ||||
| 		if !hasTests && numDecl > 1 && len(flist) == 1 { | ||||
| 			// If this file only has one example function, some | ||||
| 			// other top-level declarations, and no tests or | ||||
| 			// benchmarks, use the whole file as the example. | ||||
| 			flist[0].Code = file | ||||
| 			flist[0].Play = playExampleFile(file) | ||||
| 		} | ||||
| 		list = append(list, flist...) | ||||
| 	} | ||||
| 	sort.Sort(exampleByName(list)) | ||||
| 	return list | ||||
| } | ||||
|  | ||||
| var outputPrefix = regexp.MustCompile(`(?i)^[[:space:]]*output:`) | ||||
|  | ||||
| // Extracts the expected output and whether there was a valid output comment | ||||
| func exampleOutput(b *ast.BlockStmt, comments []*ast.CommentGroup) (output string, ok bool) { | ||||
| 	if _, last := lastComment(b, comments); last != nil { | ||||
| 		// test that it begins with the correct prefix | ||||
| 		text := last.Text() | ||||
| 		if loc := outputPrefix.FindStringIndex(text); loc != nil { | ||||
| 			text = text[loc[1]:] | ||||
| 			// Strip zero or more spaces followed by \n or a single space. | ||||
| 			text = strings.TrimLeft(text, " ") | ||||
| 			if len(text) > 0 && text[0] == '\n' { | ||||
| 				text = text[1:] | ||||
| 			} | ||||
| 			return text, true | ||||
| 		} | ||||
| 	} | ||||
| 	return "", false // no suitable comment found | ||||
| } | ||||
|  | ||||
| // isTest tells whether name looks like a test, example, or benchmark. | ||||
| // It is a Test (say) if there is a character after Test that is not a | ||||
| // lower-case letter. (We don't want Testiness.) | ||||
| func isTest(name, prefix string) bool { | ||||
| 	if !strings.HasPrefix(name, prefix) { | ||||
| 		return false | ||||
| 	} | ||||
| 	if len(name) == len(prefix) { // "Test" is ok | ||||
| 		return true | ||||
| 	} | ||||
| 	rune, _ := utf8.DecodeRuneInString(name[len(prefix):]) | ||||
| 	return !unicode.IsLower(rune) | ||||
| } | ||||
|  | ||||
| type exampleByName []*Example | ||||
|  | ||||
| func (s exampleByName) Len() int           { return len(s) } | ||||
| func (s exampleByName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] } | ||||
| func (s exampleByName) Less(i, j int) bool { return s[i].Name < s[j].Name } | ||||
|  | ||||
| // playExample synthesizes a new *ast.File based on the provided | ||||
| // file with the provided function body as the body of main. | ||||
| func playExample(file *ast.File, body *ast.BlockStmt) *ast.File { | ||||
| 	if !strings.HasSuffix(file.Name.Name, "_test") { | ||||
| 		// We don't support examples that are part of the | ||||
| 		// greater package (yet). | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// Find top-level declarations in the file. | ||||
| 	topDecls := make(map[*ast.Object]bool) | ||||
| 	for _, decl := range file.Decls { | ||||
| 		switch d := decl.(type) { | ||||
| 		case *ast.FuncDecl: | ||||
| 			topDecls[d.Name.Obj] = true | ||||
| 		case *ast.GenDecl: | ||||
| 			for _, spec := range d.Specs { | ||||
| 				switch s := spec.(type) { | ||||
| 				case *ast.TypeSpec: | ||||
| 					topDecls[s.Name.Obj] = true | ||||
| 				case *ast.ValueSpec: | ||||
| 					for _, id := range s.Names { | ||||
| 						topDecls[id.Obj] = true | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Find unresolved identifiers and uses of top-level declarations. | ||||
| 	unresolved := make(map[string]bool) | ||||
| 	usesTopDecl := false | ||||
| 	var inspectFunc func(ast.Node) bool | ||||
| 	inspectFunc = func(n ast.Node) bool { | ||||
| 		// For selector expressions, only inspect the left hand side. | ||||
| 		// (For an expression like fmt.Println, only add "fmt" to the | ||||
| 		// set of unresolved names, not "Println".) | ||||
| 		if e, ok := n.(*ast.SelectorExpr); ok { | ||||
| 			ast.Inspect(e.X, inspectFunc) | ||||
| 			return false | ||||
| 		} | ||||
| 		// For key value expressions, only inspect the value | ||||
| 		// as the key should be resolved by the type of the | ||||
| 		// composite literal. | ||||
| 		if e, ok := n.(*ast.KeyValueExpr); ok { | ||||
| 			ast.Inspect(e.Value, inspectFunc) | ||||
| 			return false | ||||
| 		} | ||||
| 		if id, ok := n.(*ast.Ident); ok { | ||||
| 			if id.Obj == nil { | ||||
| 				unresolved[id.Name] = true | ||||
| 			} else if topDecls[id.Obj] { | ||||
| 				usesTopDecl = true | ||||
| 			} | ||||
| 		} | ||||
| 		return true | ||||
| 	} | ||||
| 	ast.Inspect(body, inspectFunc) | ||||
| 	if usesTopDecl { | ||||
| 		// We don't support examples that are not self-contained (yet). | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// Remove predeclared identifiers from unresolved list. | ||||
| 	for n := range unresolved { | ||||
| 		if predeclaredTypes[n] || predeclaredConstants[n] || predeclaredFuncs[n] { | ||||
| 			delete(unresolved, n) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Use unresolved identifiers to determine the imports used by this | ||||
| 	// example. The heuristic assumes package names match base import | ||||
| 	// paths for imports w/o renames (should be good enough most of the time). | ||||
| 	namedImports := make(map[string]string) // [name]path | ||||
| 	var blankImports []ast.Spec             // _ imports | ||||
| 	for _, s := range file.Imports { | ||||
| 		p, err := strconv.Unquote(s.Path.Value) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		n := path.Base(p) | ||||
| 		if s.Name != nil { | ||||
| 			n = s.Name.Name | ||||
| 			switch n { | ||||
| 			case "_": | ||||
| 				blankImports = append(blankImports, s) | ||||
| 				continue | ||||
| 			case ".": | ||||
| 				// We can't resolve dot imports (yet). | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 		if unresolved[n] { | ||||
| 			namedImports[n] = p | ||||
| 			delete(unresolved, n) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// If there are other unresolved identifiers, give up because this | ||||
| 	// synthesized file is not going to build. | ||||
| 	if len(unresolved) > 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// Include documentation belonging to blank imports. | ||||
| 	var comments []*ast.CommentGroup | ||||
| 	for _, s := range blankImports { | ||||
| 		if c := s.(*ast.ImportSpec).Doc; c != nil { | ||||
| 			comments = append(comments, c) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Include comments that are inside the function body. | ||||
| 	for _, c := range file.Comments { | ||||
| 		if body.Pos() <= c.Pos() && c.End() <= body.End() { | ||||
| 			comments = append(comments, c) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Strip "Output:" comment and adjust body end position. | ||||
| 	body, comments = stripOutputComment(body, comments) | ||||
|  | ||||
| 	// Synthesize import declaration. | ||||
| 	importDecl := &ast.GenDecl{ | ||||
| 		Tok:    token.IMPORT, | ||||
| 		Lparen: 1, // Need non-zero Lparen and Rparen so that printer | ||||
| 		Rparen: 1, // treats this as a factored import. | ||||
| 	} | ||||
| 	for n, p := range namedImports { | ||||
| 		s := &ast.ImportSpec{Path: &ast.BasicLit{Value: strconv.Quote(p)}} | ||||
| 		if path.Base(p) != n { | ||||
| 			s.Name = ast.NewIdent(n) | ||||
| 		} | ||||
| 		importDecl.Specs = append(importDecl.Specs, s) | ||||
| 	} | ||||
| 	importDecl.Specs = append(importDecl.Specs, blankImports...) | ||||
|  | ||||
| 	// Synthesize main function. | ||||
| 	funcDecl := &ast.FuncDecl{ | ||||
| 		Name: ast.NewIdent("main"), | ||||
| 		Type: &ast.FuncType{Params: &ast.FieldList{}}, // FuncType.Params must be non-nil | ||||
| 		Body: body, | ||||
| 	} | ||||
|  | ||||
| 	// Synthesize file. | ||||
| 	return &ast.File{ | ||||
| 		Name:     ast.NewIdent("main"), | ||||
| 		Decls:    []ast.Decl{importDecl, funcDecl}, | ||||
| 		Comments: comments, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // playExampleFile takes a whole file example and synthesizes a new *ast.File | ||||
| // such that the example is function main in package main. | ||||
| func playExampleFile(file *ast.File) *ast.File { | ||||
| 	// Strip copyright comment if present. | ||||
| 	comments := file.Comments | ||||
| 	if len(comments) > 0 && strings.HasPrefix(comments[0].Text(), "Copyright") { | ||||
| 		comments = comments[1:] | ||||
| 	} | ||||
|  | ||||
| 	// Copy declaration slice, rewriting the ExampleX function to main. | ||||
| 	var decls []ast.Decl | ||||
| 	for _, d := range file.Decls { | ||||
| 		if f, ok := d.(*ast.FuncDecl); ok && isTest(f.Name.Name, "Example") { | ||||
| 			// Copy the FuncDecl, as it may be used elsewhere. | ||||
| 			newF := *f | ||||
| 			newF.Name = ast.NewIdent("main") | ||||
| 			newF.Body, comments = stripOutputComment(f.Body, comments) | ||||
| 			d = &newF | ||||
| 		} | ||||
| 		decls = append(decls, d) | ||||
| 	} | ||||
|  | ||||
| 	// Copy the File, as it may be used elsewhere. | ||||
| 	f := *file | ||||
| 	f.Name = ast.NewIdent("main") | ||||
| 	f.Decls = decls | ||||
| 	f.Comments = comments | ||||
| 	return &f | ||||
| } | ||||
|  | ||||
| // stripOutputComment finds and removes an "Output:" comment from body | ||||
| // and comments, and adjusts the body block's end position. | ||||
| func stripOutputComment(body *ast.BlockStmt, comments []*ast.CommentGroup) (*ast.BlockStmt, []*ast.CommentGroup) { | ||||
| 	// Do nothing if no "Output:" comment found. | ||||
| 	i, last := lastComment(body, comments) | ||||
| 	if last == nil || !outputPrefix.MatchString(last.Text()) { | ||||
| 		return body, comments | ||||
| 	} | ||||
|  | ||||
| 	// Copy body and comments, as the originals may be used elsewhere. | ||||
| 	newBody := &ast.BlockStmt{ | ||||
| 		Lbrace: body.Lbrace, | ||||
| 		List:   body.List, | ||||
| 		Rbrace: last.Pos(), | ||||
| 	} | ||||
| 	newComments := make([]*ast.CommentGroup, len(comments)-1) | ||||
| 	copy(newComments, comments[:i]) | ||||
| 	copy(newComments[i:], comments[i+1:]) | ||||
| 	return newBody, newComments | ||||
| } | ||||
|  | ||||
| // lastComment returns the last comment inside the provided block. | ||||
| func lastComment(b *ast.BlockStmt, c []*ast.CommentGroup) (i int, last *ast.CommentGroup) { | ||||
| 	pos, end := b.Pos(), b.End() | ||||
| 	for j, cg := range c { | ||||
| 		if cg.Pos() < pos { | ||||
| 			continue | ||||
| 		} | ||||
| 		if cg.End() > end { | ||||
| 			break | ||||
| 		} | ||||
| 		i, last = j, cg | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										191
									
								
								third_party/golang/go/doc/example_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								third_party/golang/go/doc/example_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | ||||
| // Copyright 2013 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. | ||||
|  | ||||
| package doc_test | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"go/doc" | ||||
| 	"go/format" | ||||
| 	"go/parser" | ||||
| 	"go/token" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| const exampleTestFile = ` | ||||
| package foo_test | ||||
|  | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"os/exec" | ||||
| ) | ||||
|  | ||||
| func ExampleHello() { | ||||
| 	fmt.Println("Hello, world!") | ||||
| 	// Output: Hello, world! | ||||
| } | ||||
|  | ||||
| func ExampleImport() { | ||||
| 	out, err := exec.Command("date").Output() | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	fmt.Printf("The date is %s\n", out) | ||||
| } | ||||
|  | ||||
| func ExampleKeyValue() { | ||||
| 	v := struct { | ||||
| 		a string | ||||
| 		b int | ||||
| 	}{ | ||||
| 		a: "A", | ||||
| 		b: 1, | ||||
| 	} | ||||
| 	fmt.Print(v) | ||||
| 	// Output: a: "A", b: 1 | ||||
| } | ||||
|  | ||||
| func ExampleKeyValueImport() { | ||||
| 	f := flag.Flag{ | ||||
| 		Name: "play", | ||||
| 	} | ||||
| 	fmt.Print(f) | ||||
| 	// Output: Name: "play" | ||||
| } | ||||
|  | ||||
| var keyValueTopDecl = struct { | ||||
| 	a string | ||||
| 	b int | ||||
| }{ | ||||
| 	a: "B", | ||||
| 	b: 2, | ||||
| } | ||||
|  | ||||
| func ExampleKeyValueTopDecl() { | ||||
| 	fmt.Print(keyValueTopDecl) | ||||
| } | ||||
| ` | ||||
|  | ||||
| var exampleTestCases = []struct { | ||||
| 	Name, Play, Output string | ||||
| }{ | ||||
| 	{ | ||||
| 		Name:   "Hello", | ||||
| 		Play:   exampleHelloPlay, | ||||
| 		Output: "Hello, world!\n", | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "Import", | ||||
| 		Play: exampleImportPlay, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:   "KeyValue", | ||||
| 		Play:   exampleKeyValuePlay, | ||||
| 		Output: "a: \"A\", b: 1\n", | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:   "KeyValueImport", | ||||
| 		Play:   exampleKeyValueImportPlay, | ||||
| 		Output: "Name: \"play\"\n", | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "KeyValueTopDecl", | ||||
| 		Play: "<nil>", | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| const exampleHelloPlay = `package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	fmt.Println("Hello, world!") | ||||
| } | ||||
| ` | ||||
| const exampleImportPlay = `package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"os/exec" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	out, err := exec.Command("date").Output() | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	fmt.Printf("The date is %s\n", out) | ||||
| } | ||||
| ` | ||||
|  | ||||
| const exampleKeyValuePlay = `package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	v := struct { | ||||
| 		a string | ||||
| 		b int | ||||
| 	}{ | ||||
| 		a: "A", | ||||
| 		b: 1, | ||||
| 	} | ||||
| 	fmt.Print(v) | ||||
| } | ||||
| ` | ||||
|  | ||||
| const exampleKeyValueImportPlay = `package main | ||||
|  | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	f := flag.Flag{ | ||||
| 		Name: "play", | ||||
| 	} | ||||
| 	fmt.Print(f) | ||||
| } | ||||
| ` | ||||
|  | ||||
| func TestExamples(t *testing.T) { | ||||
| 	fset := token.NewFileSet() | ||||
| 	file, err := parser.ParseFile(fset, "test.go", strings.NewReader(exampleTestFile), parser.ParseComments) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	for i, e := range doc.Examples(file) { | ||||
| 		c := exampleTestCases[i] | ||||
| 		if e.Name != c.Name { | ||||
| 			t.Errorf("got Name == %q, want %q", e.Name, c.Name) | ||||
| 		} | ||||
| 		if w := c.Play; w != "" { | ||||
| 			var g string // hah | ||||
| 			if e.Play == nil { | ||||
| 				g = "<nil>" | ||||
| 			} else { | ||||
| 				var buf bytes.Buffer | ||||
| 				if err := format.Node(&buf, fset, e.Play); err != nil { | ||||
| 					t.Fatal(err) | ||||
| 				} | ||||
| 				g = buf.String() | ||||
| 			} | ||||
| 			if g != w { | ||||
| 				t.Errorf("%s: got Play == %q, want %q", c.Name, g, w) | ||||
| 			} | ||||
| 		} | ||||
| 		if g, w := e.Output, c.Output; g != w { | ||||
| 			t.Errorf("%s: got Output == %q, want %q", c.Name, g, w) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										252
									
								
								third_party/golang/go/doc/exports.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								third_party/golang/go/doc/exports.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,252 @@ | ||||
| // Copyright 2011 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. | ||||
|  | ||||
| // This file implements export filtering of an AST. | ||||
|  | ||||
| package doc | ||||
|  | ||||
| import ( | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/ast" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| ) | ||||
|  | ||||
| // filterIdentList removes unexported names from list in place | ||||
| // and returns the resulting list. | ||||
| // | ||||
| func filterIdentList(list []*ast.Ident) []*ast.Ident { | ||||
| 	j := 0 | ||||
| 	for _, x := range list { | ||||
| 		if ast.IsExported(x.Name) { | ||||
| 			list[j] = x | ||||
| 			j++ | ||||
| 		} | ||||
| 	} | ||||
| 	return list[0:j] | ||||
| } | ||||
|  | ||||
| // hasExportedName reports whether list contains any exported names. | ||||
| // | ||||
| func hasExportedName(list []*ast.Ident) bool { | ||||
| 	for _, x := range list { | ||||
| 		if x.IsExported() { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // removeErrorField removes anonymous fields named "error" from an interface. | ||||
| // This is called when "error" has been determined to be a local name, | ||||
| // not the predeclared type. | ||||
| // | ||||
| func removeErrorField(ityp *ast.InterfaceType) { | ||||
| 	list := ityp.Methods.List // we know that ityp.Methods != nil | ||||
| 	j := 0 | ||||
| 	for _, field := range list { | ||||
| 		keepField := true | ||||
| 		if n := len(field.Names); n == 0 { | ||||
| 			// anonymous field | ||||
| 			if fname, _ := baseTypeName(field.Type); fname == "error" { | ||||
| 				keepField = false | ||||
| 			} | ||||
| 		} | ||||
| 		if keepField { | ||||
| 			list[j] = field | ||||
| 			j++ | ||||
| 		} | ||||
| 	} | ||||
| 	if j < len(list) { | ||||
| 		ityp.Incomplete = true | ||||
| 	} | ||||
| 	ityp.Methods.List = list[0:j] | ||||
| } | ||||
|  | ||||
| // filterFieldList removes unexported fields (field names) from the field list | ||||
| // in place and reports whether fields were removed. Anonymous fields are | ||||
| // recorded with the parent type. filterType is called with the types of | ||||
| // all remaining fields. | ||||
| // | ||||
| func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp *ast.InterfaceType) (removedFields bool) { | ||||
| 	if fields == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	list := fields.List | ||||
| 	j := 0 | ||||
| 	for _, field := range list { | ||||
| 		keepField := false | ||||
| 		if n := len(field.Names); n == 0 { | ||||
| 			// anonymous field | ||||
| 			fname := r.recordAnonymousField(parent, field.Type) | ||||
| 			if ast.IsExported(fname) { | ||||
| 				keepField = true | ||||
| 			} else if ityp != nil && fname == "error" { | ||||
| 				// possibly the predeclared error interface; keep | ||||
| 				// it for now but remember this interface so that | ||||
| 				// it can be fixed if error is also defined locally | ||||
| 				keepField = true | ||||
| 				r.remember(ityp) | ||||
| 			} | ||||
| 		} else { | ||||
| 			field.Names = filterIdentList(field.Names) | ||||
| 			if len(field.Names) < n { | ||||
| 				removedFields = true | ||||
| 			} | ||||
| 			if len(field.Names) > 0 { | ||||
| 				keepField = true | ||||
| 			} | ||||
| 		} | ||||
| 		if keepField { | ||||
| 			r.filterType(nil, field.Type) | ||||
| 			list[j] = field | ||||
| 			j++ | ||||
| 		} | ||||
| 	} | ||||
| 	if j < len(list) { | ||||
| 		removedFields = true | ||||
| 	} | ||||
| 	fields.List = list[0:j] | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // filterParamList applies filterType to each parameter type in fields. | ||||
| // | ||||
| func (r *reader) filterParamList(fields *ast.FieldList) { | ||||
| 	if fields != nil { | ||||
| 		for _, f := range fields.List { | ||||
| 			r.filterType(nil, f.Type) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // filterType strips any unexported struct fields or method types from typ | ||||
| // in place. If fields (or methods) have been removed, the corresponding | ||||
| // struct or interface type has the Incomplete field set to true. | ||||
| // | ||||
| func (r *reader) filterType(parent *namedType, typ ast.Expr) { | ||||
| 	switch t := typ.(type) { | ||||
| 	case *ast.Ident: | ||||
| 		// nothing to do | ||||
| 	case *ast.ParenExpr: | ||||
| 		r.filterType(nil, t.X) | ||||
| 	case *ast.ArrayType: | ||||
| 		r.filterType(nil, t.Elt) | ||||
| 	case *ast.StructType: | ||||
| 		if r.filterFieldList(parent, t.Fields, nil) { | ||||
| 			t.Incomplete = true | ||||
| 		} | ||||
| 	case *ast.FuncType: | ||||
| 		r.filterParamList(t.Params) | ||||
| 		r.filterParamList(t.Results) | ||||
| 	case *ast.InterfaceType: | ||||
| 		if r.filterFieldList(parent, t.Methods, t) { | ||||
| 			t.Incomplete = true | ||||
| 		} | ||||
| 	case *ast.MapType: | ||||
| 		r.filterType(nil, t.Key) | ||||
| 		r.filterType(nil, t.Value) | ||||
| 	case *ast.ChanType: | ||||
| 		r.filterType(nil, t.Value) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool { | ||||
| 	switch s := spec.(type) { | ||||
| 	case *ast.ImportSpec: | ||||
| 		// always keep imports so we can collect them | ||||
| 		return true | ||||
| 	case *ast.ValueSpec: | ||||
| 		s.Names = filterIdentList(s.Names) | ||||
| 		if len(s.Names) > 0 { | ||||
| 			r.filterType(nil, s.Type) | ||||
| 			return true | ||||
| 		} | ||||
| 	case *ast.TypeSpec: | ||||
| 		if name := s.Name.Name; ast.IsExported(name) { | ||||
| 			r.filterType(r.lookupType(s.Name.Name), s.Type) | ||||
| 			return true | ||||
| 		} else if name == "error" { | ||||
| 			// special case: remember that error is declared locally | ||||
| 			r.errorDecl = true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // copyConstType returns a copy of typ with position pos. | ||||
| // typ must be a valid constant type. | ||||
| // In practice, only (possibly qualified) identifiers are possible. | ||||
| // | ||||
| func copyConstType(typ ast.Expr, pos token.Pos) ast.Expr { | ||||
| 	switch typ := typ.(type) { | ||||
| 	case *ast.Ident: | ||||
| 		return &ast.Ident{Name: typ.Name, NamePos: pos} | ||||
| 	case *ast.SelectorExpr: | ||||
| 		if id, ok := typ.X.(*ast.Ident); ok { | ||||
| 			// presumably a qualified identifier | ||||
| 			return &ast.SelectorExpr{ | ||||
| 				Sel: ast.NewIdent(typ.Sel.Name), | ||||
| 				X:   &ast.Ident{Name: id.Name, NamePos: pos}, | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil // shouldn't happen, but be conservative and don't panic | ||||
| } | ||||
|  | ||||
| func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec { | ||||
| 	if tok == token.CONST { | ||||
| 		// Propagate any type information that would get lost otherwise | ||||
| 		// when unexported constants are filtered. | ||||
| 		var prevType ast.Expr | ||||
| 		for _, spec := range list { | ||||
| 			spec := spec.(*ast.ValueSpec) | ||||
| 			if spec.Type == nil && prevType != nil { | ||||
| 				// provide current spec with an explicit type | ||||
| 				spec.Type = copyConstType(prevType, spec.Pos()) | ||||
| 			} | ||||
| 			if hasExportedName(spec.Names) { | ||||
| 				// exported names are preserved so there's no need to propagate the type | ||||
| 				prevType = nil | ||||
| 			} else { | ||||
| 				prevType = spec.Type | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	j := 0 | ||||
| 	for _, s := range list { | ||||
| 		if r.filterSpec(s, tok) { | ||||
| 			list[j] = s | ||||
| 			j++ | ||||
| 		} | ||||
| 	} | ||||
| 	return list[0:j] | ||||
| } | ||||
|  | ||||
| func (r *reader) filterDecl(decl ast.Decl) bool { | ||||
| 	switch d := decl.(type) { | ||||
| 	case *ast.GenDecl: | ||||
| 		d.Specs = r.filterSpecList(d.Specs, d.Tok) | ||||
| 		return len(d.Specs) > 0 | ||||
| 	case *ast.FuncDecl: | ||||
| 		// ok to filter these methods early because any | ||||
| 		// conflicting method will be filtered here, too - | ||||
| 		// thus, removing these methods early will not lead | ||||
| 		// to the false removal of possible conflicts | ||||
| 		return ast.IsExported(d.Name.Name) | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // fileExports removes unexported declarations from src in place. | ||||
| // | ||||
| func (r *reader) fileExports(src *ast.File) { | ||||
| 	j := 0 | ||||
| 	for _, d := range src.Decls { | ||||
| 		if r.filterDecl(d) { | ||||
| 			src.Decls[j] = d | ||||
| 			j++ | ||||
| 		} | ||||
| 	} | ||||
| 	src.Decls = src.Decls[0:j] | ||||
| } | ||||
							
								
								
									
										105
									
								
								third_party/golang/go/doc/filter.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								third_party/golang/go/doc/filter.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| // Copyright 2009 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. | ||||
|  | ||||
| package doc | ||||
|  | ||||
| import "k8s.io/kubernetes/third_party/golang/go/ast" | ||||
|  | ||||
| type Filter func(string) bool | ||||
|  | ||||
| func matchFields(fields *ast.FieldList, f Filter) bool { | ||||
| 	if fields != nil { | ||||
| 		for _, field := range fields.List { | ||||
| 			for _, name := range field.Names { | ||||
| 				if f(name.Name) { | ||||
| 					return true | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func matchDecl(d *ast.GenDecl, f Filter) bool { | ||||
| 	for _, d := range d.Specs { | ||||
| 		switch v := d.(type) { | ||||
| 		case *ast.ValueSpec: | ||||
| 			for _, name := range v.Names { | ||||
| 				if f(name.Name) { | ||||
| 					return true | ||||
| 				} | ||||
| 			} | ||||
| 		case *ast.TypeSpec: | ||||
| 			if f(v.Name.Name) { | ||||
| 				return true | ||||
| 			} | ||||
| 			switch t := v.Type.(type) { | ||||
| 			case *ast.StructType: | ||||
| 				if matchFields(t.Fields, f) { | ||||
| 					return true | ||||
| 				} | ||||
| 			case *ast.InterfaceType: | ||||
| 				if matchFields(t.Methods, f) { | ||||
| 					return true | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func filterValues(a []*Value, f Filter) []*Value { | ||||
| 	w := 0 | ||||
| 	for _, vd := range a { | ||||
| 		if matchDecl(vd.Decl, f) { | ||||
| 			a[w] = vd | ||||
| 			w++ | ||||
| 		} | ||||
| 	} | ||||
| 	return a[0:w] | ||||
| } | ||||
|  | ||||
| func filterFuncs(a []*Func, f Filter) []*Func { | ||||
| 	w := 0 | ||||
| 	for _, fd := range a { | ||||
| 		if f(fd.Name) { | ||||
| 			a[w] = fd | ||||
| 			w++ | ||||
| 		} | ||||
| 	} | ||||
| 	return a[0:w] | ||||
| } | ||||
|  | ||||
| func filterTypes(a []*Type, f Filter) []*Type { | ||||
| 	w := 0 | ||||
| 	for _, td := range a { | ||||
| 		n := 0 // number of matches | ||||
| 		if matchDecl(td.Decl, f) { | ||||
| 			n = 1 | ||||
| 		} else { | ||||
| 			// type name doesn't match, but we may have matching consts, vars, factories or methods | ||||
| 			td.Consts = filterValues(td.Consts, f) | ||||
| 			td.Vars = filterValues(td.Vars, f) | ||||
| 			td.Funcs = filterFuncs(td.Funcs, f) | ||||
| 			td.Methods = filterFuncs(td.Methods, f) | ||||
| 			n += len(td.Consts) + len(td.Vars) + len(td.Funcs) + len(td.Methods) | ||||
| 		} | ||||
| 		if n > 0 { | ||||
| 			a[w] = td | ||||
| 			w++ | ||||
| 		} | ||||
| 	} | ||||
| 	return a[0:w] | ||||
| } | ||||
|  | ||||
| // Filter eliminates documentation for names that don't pass through the filter f. | ||||
| // TODO(gri): Recognize "Type.Method" as a name. | ||||
| // | ||||
| func (p *Package) Filter(f Filter) { | ||||
| 	p.Consts = filterValues(p.Consts, f) | ||||
| 	p.Vars = filterValues(p.Vars, f) | ||||
| 	p.Types = filterTypes(p.Types, f) | ||||
| 	p.Funcs = filterFuncs(p.Funcs, f) | ||||
| 	p.Doc = "" // don't show top-level package doc | ||||
| } | ||||
							
								
								
									
										114
									
								
								third_party/golang/go/doc/headscan.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								third_party/golang/go/doc/headscan.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| // Copyright 2011 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. | ||||
|  | ||||
| // +build ignore | ||||
|  | ||||
| /* | ||||
| 	The headscan command extracts comment headings from package files; | ||||
| 	it is used to detect false positives which may require an adjustment | ||||
| 	to the comment formatting heuristics in comment.go. | ||||
|  | ||||
| 	Usage: headscan [-root root_directory] | ||||
|  | ||||
| 	By default, the $GOROOT/src directory is scanned. | ||||
| */ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/doc" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/parser" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	root    = flag.String("root", filepath.Join(runtime.GOROOT(), "src"), "root of filesystem tree to scan") | ||||
| 	verbose = flag.Bool("v", false, "verbose mode") | ||||
| ) | ||||
|  | ||||
| // ToHTML in comment.go assigns a (possibly blank) ID to each heading | ||||
| var html_h = regexp.MustCompile(`<h3 id="[^"]*">`) | ||||
|  | ||||
| const html_endh = "</h3>\n" | ||||
|  | ||||
| func isGoFile(fi os.FileInfo) bool { | ||||
| 	return strings.HasSuffix(fi.Name(), ".go") && | ||||
| 		!strings.HasSuffix(fi.Name(), "_test.go") | ||||
| } | ||||
|  | ||||
| func appendHeadings(list []string, comment string) []string { | ||||
| 	var buf bytes.Buffer | ||||
| 	doc.ToHTML(&buf, comment, nil) | ||||
| 	for s := buf.String(); ; { | ||||
| 		loc := html_h.FindStringIndex(s) | ||||
| 		if len(loc) == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 		i := loc[1] | ||||
| 		j := strings.Index(s, html_endh) | ||||
| 		if j < 0 { | ||||
| 			list = append(list, s[i:]) // incorrect HTML | ||||
| 			break | ||||
| 		} | ||||
| 		list = append(list, s[i:j]) | ||||
| 		s = s[j+len(html_endh):] | ||||
| 	} | ||||
| 	return list | ||||
| } | ||||
|  | ||||
| func main() { | ||||
| 	flag.Parse() | ||||
| 	fset := token.NewFileSet() | ||||
| 	nheadings := 0 | ||||
| 	err := filepath.Walk(*root, func(path string, fi os.FileInfo, err error) error { | ||||
| 		if !fi.IsDir() { | ||||
| 			return nil | ||||
| 		} | ||||
| 		pkgs, err := parser.ParseDir(fset, path, isGoFile, parser.ParseComments) | ||||
| 		if err != nil { | ||||
| 			if *verbose { | ||||
| 				fmt.Fprintln(os.Stderr, err) | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 		for _, pkg := range pkgs { | ||||
| 			d := doc.New(pkg, path, doc.Mode(0)) | ||||
| 			list := appendHeadings(nil, d.Doc) | ||||
| 			for _, d := range d.Consts { | ||||
| 				list = appendHeadings(list, d.Doc) | ||||
| 			} | ||||
| 			for _, d := range d.Types { | ||||
| 				list = appendHeadings(list, d.Doc) | ||||
| 			} | ||||
| 			for _, d := range d.Vars { | ||||
| 				list = appendHeadings(list, d.Doc) | ||||
| 			} | ||||
| 			for _, d := range d.Funcs { | ||||
| 				list = appendHeadings(list, d.Doc) | ||||
| 			} | ||||
| 			if len(list) > 0 { | ||||
| 				// directories may contain multiple packages; | ||||
| 				// print path and package name | ||||
| 				fmt.Printf("%s (package %s)\n", path, pkg.Name) | ||||
| 				for _, h := range list { | ||||
| 					fmt.Printf("\t%s\n", h) | ||||
| 				} | ||||
| 				nheadings += len(list) | ||||
| 			} | ||||
| 		} | ||||
| 		return nil | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintln(os.Stderr, err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	fmt.Println(nheadings, "headings found") | ||||
| } | ||||
							
								
								
									
										853
									
								
								third_party/golang/go/doc/reader.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										853
									
								
								third_party/golang/go/doc/reader.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,853 @@ | ||||
| // Copyright 2009 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. | ||||
|  | ||||
| package doc | ||||
|  | ||||
| import ( | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/ast" | ||||
| 	"k8s.io/kubernetes/third_party/golang/go/token" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // function/method sets | ||||
| // | ||||
| // Internally, we treat functions like methods and collect them in method sets. | ||||
|  | ||||
| // A methodSet describes a set of methods. Entries where Decl == nil are conflict | ||||
| // entries (more then one method with the same name at the same embedding level). | ||||
| // | ||||
| type methodSet map[string]*Func | ||||
|  | ||||
| // recvString returns a string representation of recv of the | ||||
| // form "T", "*T", or "BADRECV" (if not a proper receiver type). | ||||
| // | ||||
| func recvString(recv ast.Expr) string { | ||||
| 	switch t := recv.(type) { | ||||
| 	case *ast.Ident: | ||||
| 		return t.Name | ||||
| 	case *ast.StarExpr: | ||||
| 		return "*" + recvString(t.X) | ||||
| 	} | ||||
| 	return "BADRECV" | ||||
| } | ||||
|  | ||||
| // set creates the corresponding Func for f and adds it to mset. | ||||
| // If there are multiple f's with the same name, set keeps the first | ||||
| // one with documentation; conflicts are ignored. | ||||
| // | ||||
| func (mset methodSet) set(f *ast.FuncDecl) { | ||||
| 	name := f.Name.Name | ||||
| 	if g := mset[name]; g != nil && g.Doc != "" { | ||||
| 		// A function with the same name has already been registered; | ||||
| 		// since it has documentation, assume f is simply another | ||||
| 		// implementation and ignore it. This does not happen if the | ||||
| 		// caller is using go/build.ScanDir to determine the list of | ||||
| 		// files implementing a package. | ||||
| 		return | ||||
| 	} | ||||
| 	// function doesn't exist or has no documentation; use f | ||||
| 	recv := "" | ||||
| 	if f.Recv != nil { | ||||
| 		var typ ast.Expr | ||||
| 		// be careful in case of incorrect ASTs | ||||
| 		if list := f.Recv.List; len(list) == 1 { | ||||
| 			typ = list[0].Type | ||||
| 		} | ||||
| 		recv = recvString(typ) | ||||
| 	} | ||||
| 	mset[name] = &Func{ | ||||
| 		Doc:  f.Doc.Text(), | ||||
| 		Name: name, | ||||
| 		Decl: f, | ||||
| 		Recv: recv, | ||||
| 		Orig: recv, | ||||
| 	} | ||||
| 	f.Doc = nil // doc consumed - remove from AST | ||||
| } | ||||
|  | ||||
| // add adds method m to the method set; m is ignored if the method set | ||||
| // already contains a method with the same name at the same or a higher | ||||
| // level then m. | ||||
| // | ||||
| func (mset methodSet) add(m *Func) { | ||||
| 	old := mset[m.Name] | ||||
| 	if old == nil || m.Level < old.Level { | ||||
| 		mset[m.Name] = m | ||||
| 		return | ||||
| 	} | ||||
| 	if old != nil && m.Level == old.Level { | ||||
| 		// conflict - mark it using a method with nil Decl | ||||
| 		mset[m.Name] = &Func{ | ||||
| 			Name:  m.Name, | ||||
| 			Level: m.Level, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Named types | ||||
|  | ||||
| // baseTypeName returns the name of the base type of x (or "") | ||||
| // and whether the type is imported or not. | ||||
| // | ||||
| func baseTypeName(x ast.Expr) (name string, imported bool) { | ||||
| 	switch t := x.(type) { | ||||
| 	case *ast.Ident: | ||||
| 		return t.Name, false | ||||
| 	case *ast.SelectorExpr: | ||||
| 		if _, ok := t.X.(*ast.Ident); ok { | ||||
| 			// only possible for qualified type names; | ||||
| 			// assume type is imported | ||||
| 			return t.Sel.Name, true | ||||
| 		} | ||||
| 	case *ast.StarExpr: | ||||
| 		return baseTypeName(t.X) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // An embeddedSet describes a set of embedded types. | ||||
| type embeddedSet map[*namedType]bool | ||||
|  | ||||
| // A namedType represents a named unqualified (package local, or possibly | ||||
| // predeclared) type. The namedType for a type name is always found via | ||||
| // reader.lookupType. | ||||
| // | ||||
| type namedType struct { | ||||
| 	doc  string       // doc comment for type | ||||
| 	name string       // type name | ||||
| 	decl *ast.GenDecl // nil if declaration hasn't been seen yet | ||||
|  | ||||
| 	isEmbedded bool        // true if this type is embedded | ||||
| 	isStruct   bool        // true if this type is a struct | ||||
| 	embedded   embeddedSet // true if the embedded type is a pointer | ||||
|  | ||||
| 	// associated declarations | ||||
| 	values  []*Value // consts and vars | ||||
| 	funcs   methodSet | ||||
| 	methods methodSet | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // AST reader | ||||
|  | ||||
| // reader accumulates documentation for a single package. | ||||
| // It modifies the AST: Comments (declaration documentation) | ||||
| // that have been collected by the reader are set to nil | ||||
| // in the respective AST nodes so that they are not printed | ||||
| // twice (once when printing the documentation and once when | ||||
| // printing the corresponding AST node). | ||||
| // | ||||
| type reader struct { | ||||
| 	mode Mode | ||||
|  | ||||
| 	// package properties | ||||
| 	doc       string // package documentation, if any | ||||
| 	filenames []string | ||||
| 	notes     map[string][]*Note | ||||
|  | ||||
| 	// declarations | ||||
| 	imports map[string]int | ||||
| 	values  []*Value // consts and vars | ||||
| 	types   map[string]*namedType | ||||
| 	funcs   methodSet | ||||
|  | ||||
| 	// support for package-local error type declarations | ||||
| 	errorDecl bool                 // if set, type "error" was declared locally | ||||
| 	fixlist   []*ast.InterfaceType // list of interfaces containing anonymous field "error" | ||||
| } | ||||
|  | ||||
| func (r *reader) isVisible(name string) bool { | ||||
| 	return r.mode&AllDecls != 0 || ast.IsExported(name) | ||||
| } | ||||
|  | ||||
| // lookupType returns the base type with the given name. | ||||
| // If the base type has not been encountered yet, a new | ||||
| // type with the given name but no associated declaration | ||||
| // is added to the type map. | ||||
| // | ||||
| func (r *reader) lookupType(name string) *namedType { | ||||
| 	if name == "" || name == "_" { | ||||
| 		return nil // no type docs for anonymous types | ||||
| 	} | ||||
| 	if typ, found := r.types[name]; found { | ||||
| 		return typ | ||||
| 	} | ||||
| 	// type not found - add one without declaration | ||||
| 	typ := &namedType{ | ||||
| 		name:     name, | ||||
| 		embedded: make(embeddedSet), | ||||
| 		funcs:    make(methodSet), | ||||
| 		methods:  make(methodSet), | ||||
| 	} | ||||
| 	r.types[name] = typ | ||||
| 	return typ | ||||
| } | ||||
|  | ||||
| // recordAnonymousField registers fieldType as the type of an | ||||
| // anonymous field in the parent type. If the field is imported | ||||
| // (qualified name) or the parent is nil, the field is ignored. | ||||
| // The function returns the field name. | ||||
| // | ||||
| func (r *reader) recordAnonymousField(parent *namedType, fieldType ast.Expr) (fname string) { | ||||
| 	fname, imp := baseTypeName(fieldType) | ||||
| 	if parent == nil || imp { | ||||
| 		return | ||||
| 	} | ||||
| 	if ftype := r.lookupType(fname); ftype != nil { | ||||
| 		ftype.isEmbedded = true | ||||
| 		_, ptr := fieldType.(*ast.StarExpr) | ||||
| 		parent.embedded[ftype] = ptr | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (r *reader) readDoc(comment *ast.CommentGroup) { | ||||
| 	// By convention there should be only one package comment | ||||
| 	// but collect all of them if there are more then one. | ||||
| 	text := comment.Text() | ||||
| 	if r.doc == "" { | ||||
| 		r.doc = text | ||||
| 		return | ||||
| 	} | ||||
| 	r.doc += "\n" + text | ||||
| } | ||||
|  | ||||
| func (r *reader) remember(typ *ast.InterfaceType) { | ||||
| 	r.fixlist = append(r.fixlist, typ) | ||||
| } | ||||
|  | ||||
| func specNames(specs []ast.Spec) []string { | ||||
| 	names := make([]string, 0, len(specs)) // reasonable estimate | ||||
| 	for _, s := range specs { | ||||
| 		// s guaranteed to be an *ast.ValueSpec by readValue | ||||
| 		for _, ident := range s.(*ast.ValueSpec).Names { | ||||
| 			names = append(names, ident.Name) | ||||
| 		} | ||||
| 	} | ||||
| 	return names | ||||
| } | ||||
|  | ||||
| // readValue processes a const or var declaration. | ||||
| // | ||||
| func (r *reader) readValue(decl *ast.GenDecl) { | ||||
| 	// determine if decl should be associated with a type | ||||
| 	// Heuristic: For each typed entry, determine the type name, if any. | ||||
| 	//            If there is exactly one type name that is sufficiently | ||||
| 	//            frequent, associate the decl with the respective type. | ||||
| 	domName := "" | ||||
| 	domFreq := 0 | ||||
| 	prev := "" | ||||
| 	n := 0 | ||||
| 	for _, spec := range decl.Specs { | ||||
| 		s, ok := spec.(*ast.ValueSpec) | ||||
| 		if !ok { | ||||
| 			continue // should not happen, but be conservative | ||||
| 		} | ||||
| 		name := "" | ||||
| 		switch { | ||||
| 		case s.Type != nil: | ||||
| 			// a type is present; determine its name | ||||
| 			if n, imp := baseTypeName(s.Type); !imp { | ||||
| 				name = n | ||||
| 			} | ||||
| 		case decl.Tok == token.CONST: | ||||
| 			// no type is present but we have a constant declaration; | ||||
| 			// use the previous type name (w/o more type information | ||||
| 			// we cannot handle the case of unnamed variables with | ||||
| 			// initializer expressions except for some trivial cases) | ||||
| 			name = prev | ||||
| 		} | ||||
| 		if name != "" { | ||||
| 			// entry has a named type | ||||
| 			if domName != "" && domName != name { | ||||
| 				// more than one type name - do not associate | ||||
| 				// with any type | ||||
| 				domName = "" | ||||
| 				break | ||||
| 			} | ||||
| 			domName = name | ||||
| 			domFreq++ | ||||
| 		} | ||||
| 		prev = name | ||||
| 		n++ | ||||
| 	} | ||||
|  | ||||
| 	// nothing to do w/o a legal declaration | ||||
| 	if n == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// determine values list with which to associate the Value for this decl | ||||
| 	values := &r.values | ||||
| 	const threshold = 0.75 | ||||
| 	if domName != "" && r.isVisible(domName) && domFreq >= int(float64(len(decl.Specs))*threshold) { | ||||
| 		// typed entries are sufficiently frequent | ||||
| 		if typ := r.lookupType(domName); typ != nil { | ||||
| 			values = &typ.values // associate with that type | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	*values = append(*values, &Value{ | ||||
| 		Doc:   decl.Doc.Text(), | ||||
| 		Names: specNames(decl.Specs), | ||||
| 		Decl:  decl, | ||||
| 		order: len(*values), | ||||
| 	}) | ||||
| 	decl.Doc = nil // doc consumed - remove from AST | ||||
| } | ||||
|  | ||||
| // fields returns a struct's fields or an interface's methods. | ||||
| // | ||||
| func fields(typ ast.Expr) (list []*ast.Field, isStruct bool) { | ||||
| 	var fields *ast.FieldList | ||||
| 	switch t := typ.(type) { | ||||
| 	case *ast.StructType: | ||||
| 		fields = t.Fields | ||||
| 		isStruct = true | ||||
| 	case *ast.InterfaceType: | ||||
| 		fields = t.Methods | ||||
| 	} | ||||
| 	if fields != nil { | ||||
| 		list = fields.List | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // readType processes a type declaration. | ||||
| // | ||||
| func (r *reader) readType(decl *ast.GenDecl, spec *ast.TypeSpec) { | ||||
| 	typ := r.lookupType(spec.Name.Name) | ||||
| 	if typ == nil { | ||||
| 		return // no name or blank name - ignore the type | ||||
| 	} | ||||
|  | ||||
| 	// A type should be added at most once, so typ.decl | ||||
| 	// should be nil - if it is not, simply overwrite it. | ||||
| 	typ.decl = decl | ||||
|  | ||||
| 	// compute documentation | ||||
| 	doc := spec.Doc | ||||
| 	spec.Doc = nil // doc consumed - remove from AST | ||||
| 	if doc == nil { | ||||
| 		// no doc associated with the spec, use the declaration doc, if any | ||||
| 		doc = decl.Doc | ||||
| 	} | ||||
| 	decl.Doc = nil // doc consumed - remove from AST | ||||
| 	typ.doc = doc.Text() | ||||
|  | ||||
| 	// record anonymous fields (they may contribute methods) | ||||
| 	// (some fields may have been recorded already when filtering | ||||
| 	// exports, but that's ok) | ||||
| 	var list []*ast.Field | ||||
| 	list, typ.isStruct = fields(spec.Type) | ||||
| 	for _, field := range list { | ||||
| 		if len(field.Names) == 0 { | ||||
| 			r.recordAnonymousField(typ, field.Type) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readFunc processes a func or method declaration. | ||||
| // | ||||
| func (r *reader) readFunc(fun *ast.FuncDecl) { | ||||
| 	// strip function body | ||||
| 	fun.Body = nil | ||||
|  | ||||
| 	// associate methods with the receiver type, if any | ||||
| 	if fun.Recv != nil { | ||||
| 		// method | ||||
| 		recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type) | ||||
| 		if imp { | ||||
| 			// should not happen (incorrect AST); | ||||
| 			// don't show this method | ||||
| 			return | ||||
| 		} | ||||
| 		if typ := r.lookupType(recvTypeName); typ != nil { | ||||
| 			typ.methods.set(fun) | ||||
| 		} | ||||
| 		// otherwise ignore the method | ||||
| 		// TODO(gri): There may be exported methods of non-exported types | ||||
| 		// that can be called because of exported values (consts, vars, or | ||||
| 		// function results) of that type. Could determine if that is the | ||||
| 		// case and then show those methods in an appropriate section. | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// associate factory functions with the first visible result type, if any | ||||
| 	if fun.Type.Results.NumFields() >= 1 { | ||||
| 		res := fun.Type.Results.List[0] | ||||
| 		if len(res.Names) <= 1 { | ||||
| 			// exactly one (named or anonymous) result associated | ||||
| 			// with the first type in result signature (there may | ||||
| 			// be more than one result) | ||||
| 			if n, imp := baseTypeName(res.Type); !imp && r.isVisible(n) { | ||||
| 				if typ := r.lookupType(n); typ != nil { | ||||
| 					// associate function with typ | ||||
| 					typ.funcs.set(fun) | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// just an ordinary function | ||||
| 	r.funcs.set(fun) | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	noteMarker    = `([A-Z][A-Z]+)\(([^)]+)\):?`                    // MARKER(uid), MARKER at least 2 chars, uid at least 1 char | ||||
| 	noteMarkerRx  = regexp.MustCompile(`^[ \t]*` + noteMarker)      // MARKER(uid) at text start | ||||
| 	noteCommentRx = regexp.MustCompile(`^/[/*][ \t]*` + noteMarker) // MARKER(uid) at comment start | ||||
| ) | ||||
|  | ||||
| // readNote collects a single note from a sequence of comments. | ||||
| // | ||||
| func (r *reader) readNote(list []*ast.Comment) { | ||||
| 	text := (&ast.CommentGroup{List: list}).Text() | ||||
| 	if m := noteMarkerRx.FindStringSubmatchIndex(text); m != nil { | ||||
| 		// The note body starts after the marker. | ||||
| 		// We remove any formatting so that we don't | ||||
| 		// get spurious line breaks/indentation when | ||||
| 		// showing the TODO body. | ||||
| 		body := clean(text[m[1]:], keepNL) | ||||
| 		if body != "" { | ||||
| 			marker := text[m[2]:m[3]] | ||||
| 			r.notes[marker] = append(r.notes[marker], &Note{ | ||||
| 				Pos:  list[0].Pos(), | ||||
| 				End:  list[len(list)-1].End(), | ||||
| 				UID:  text[m[4]:m[5]], | ||||
| 				Body: body, | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readNotes extracts notes from comments. | ||||
| // A note must start at the beginning of a comment with "MARKER(uid):" | ||||
| // and is followed by the note body (e.g., "// BUG(gri): fix this"). | ||||
| // The note ends at the end of the comment group or at the start of | ||||
| // another note in the same comment group, whichever comes first. | ||||
| // | ||||
| func (r *reader) readNotes(comments []*ast.CommentGroup) { | ||||
| 	for _, group := range comments { | ||||
| 		i := -1 // comment index of most recent note start, valid if >= 0 | ||||
| 		list := group.List | ||||
| 		for j, c := range list { | ||||
| 			if noteCommentRx.MatchString(c.Text) { | ||||
| 				if i >= 0 { | ||||
| 					r.readNote(list[i:j]) | ||||
| 				} | ||||
| 				i = j | ||||
| 			} | ||||
| 		} | ||||
| 		if i >= 0 { | ||||
| 			r.readNote(list[i:]) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readFile adds the AST for a source file to the reader. | ||||
| // | ||||
| func (r *reader) readFile(src *ast.File) { | ||||
| 	// add package documentation | ||||
| 	if src.Doc != nil { | ||||
| 		r.readDoc(src.Doc) | ||||
| 		src.Doc = nil // doc consumed - remove from AST | ||||
| 	} | ||||
|  | ||||
| 	// add all declarations | ||||
| 	for _, decl := range src.Decls { | ||||
| 		switch d := decl.(type) { | ||||
| 		case *ast.GenDecl: | ||||
| 			switch d.Tok { | ||||
| 			case token.IMPORT: | ||||
| 				// imports are handled individually | ||||
| 				for _, spec := range d.Specs { | ||||
| 					if s, ok := spec.(*ast.ImportSpec); ok { | ||||
| 						if import_, err := strconv.Unquote(s.Path.Value); err == nil { | ||||
| 							r.imports[import_] = 1 | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			case token.CONST, token.VAR: | ||||
| 				// constants and variables are always handled as a group | ||||
| 				r.readValue(d) | ||||
| 			case token.TYPE: | ||||
| 				// types are handled individually | ||||
| 				if len(d.Specs) == 1 && !d.Lparen.IsValid() { | ||||
| 					// common case: single declaration w/o parentheses | ||||
| 					// (if a single declaration is parenthesized, | ||||
| 					// create a new fake declaration below, so that | ||||
| 					// go/doc type declarations always appear w/o | ||||
| 					// parentheses) | ||||
| 					if s, ok := d.Specs[0].(*ast.TypeSpec); ok { | ||||
| 						r.readType(d, s) | ||||
| 					} | ||||
| 					break | ||||
| 				} | ||||
| 				for _, spec := range d.Specs { | ||||
| 					if s, ok := spec.(*ast.TypeSpec); ok { | ||||
| 						// use an individual (possibly fake) declaration | ||||
| 						// for each type; this also ensures that each type | ||||
| 						// gets to (re-)use the declaration documentation | ||||
| 						// if there's none associated with the spec itself | ||||
| 						fake := &ast.GenDecl{ | ||||
| 							Doc: d.Doc, | ||||
| 							// don't use the existing TokPos because it | ||||
| 							// will lead to the wrong selection range for | ||||
| 							// the fake declaration if there are more | ||||
| 							// than one type in the group (this affects | ||||
| 							// src/cmd/godoc/godoc.go's posLink_urlFunc) | ||||
| 							TokPos: s.Pos(), | ||||
| 							Tok:    token.TYPE, | ||||
| 							Specs:  []ast.Spec{s}, | ||||
| 						} | ||||
| 						r.readType(fake, s) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		case *ast.FuncDecl: | ||||
| 			r.readFunc(d) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// collect MARKER(...): annotations | ||||
| 	r.readNotes(src.Comments) | ||||
| 	src.Comments = nil // consumed unassociated comments - remove from AST | ||||
| } | ||||
|  | ||||
| func (r *reader) readPackage(pkg *ast.Package, mode Mode) { | ||||
| 	// initialize reader | ||||
| 	r.filenames = make([]string, len(pkg.Files)) | ||||
| 	r.imports = make(map[string]int) | ||||
| 	r.mode = mode | ||||
| 	r.types = make(map[string]*namedType) | ||||
| 	r.funcs = make(methodSet) | ||||
| 	r.notes = make(map[string][]*Note) | ||||
|  | ||||
| 	// sort package files before reading them so that the | ||||
| 	// result does not depend on map iteration order | ||||
| 	i := 0 | ||||
| 	for filename := range pkg.Files { | ||||
| 		r.filenames[i] = filename | ||||
| 		i++ | ||||
| 	} | ||||
| 	sort.Strings(r.filenames) | ||||
|  | ||||
| 	// process files in sorted order | ||||
| 	for _, filename := range r.filenames { | ||||
| 		f := pkg.Files[filename] | ||||
| 		if mode&AllDecls == 0 { | ||||
| 			r.fileExports(f) | ||||
| 		} | ||||
| 		r.readFile(f) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Types | ||||
|  | ||||
| func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int) *Func { | ||||
| 	if f == nil || f.Decl == nil || f.Decl.Recv == nil || len(f.Decl.Recv.List) != 1 { | ||||
| 		return f // shouldn't happen, but be safe | ||||
| 	} | ||||
|  | ||||
| 	// copy existing receiver field and set new type | ||||
| 	newField := *f.Decl.Recv.List[0] | ||||
| 	origPos := newField.Type.Pos() | ||||
| 	_, origRecvIsPtr := newField.Type.(*ast.StarExpr) | ||||
| 	newIdent := &ast.Ident{NamePos: origPos, Name: recvTypeName} | ||||
| 	var typ ast.Expr = newIdent | ||||
| 	if !embeddedIsPtr && origRecvIsPtr { | ||||
| 		newIdent.NamePos++ // '*' is one character | ||||
| 		typ = &ast.StarExpr{Star: origPos, X: newIdent} | ||||
| 	} | ||||
| 	newField.Type = typ | ||||
|  | ||||
| 	// copy existing receiver field list and set new receiver field | ||||
| 	newFieldList := *f.Decl.Recv | ||||
| 	newFieldList.List = []*ast.Field{&newField} | ||||
|  | ||||
| 	// copy existing function declaration and set new receiver field list | ||||
| 	newFuncDecl := *f.Decl | ||||
| 	newFuncDecl.Recv = &newFieldList | ||||
|  | ||||
| 	// copy existing function documentation and set new declaration | ||||
| 	newF := *f | ||||
| 	newF.Decl = &newFuncDecl | ||||
| 	newF.Recv = recvString(typ) | ||||
| 	// the Orig field never changes | ||||
| 	newF.Level = level | ||||
|  | ||||
| 	return &newF | ||||
| } | ||||
|  | ||||
| // collectEmbeddedMethods collects the embedded methods of typ in mset. | ||||
| // | ||||
| func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvTypeName string, embeddedIsPtr bool, level int, visited embeddedSet) { | ||||
| 	visited[typ] = true | ||||
| 	for embedded, isPtr := range typ.embedded { | ||||
| 		// Once an embedded type is embedded as a pointer type | ||||
| 		// all embedded types in those types are treated like | ||||
| 		// pointer types for the purpose of the receiver type | ||||
| 		// computation; i.e., embeddedIsPtr is sticky for this | ||||
| 		// embedding hierarchy. | ||||
| 		thisEmbeddedIsPtr := embeddedIsPtr || isPtr | ||||
| 		for _, m := range embedded.methods { | ||||
| 			// only top-level methods are embedded | ||||
| 			if m.Level == 0 { | ||||
| 				mset.add(customizeRecv(m, recvTypeName, thisEmbeddedIsPtr, level)) | ||||
| 			} | ||||
| 		} | ||||
| 		if !visited[embedded] { | ||||
| 			r.collectEmbeddedMethods(mset, embedded, recvTypeName, thisEmbeddedIsPtr, level+1, visited) | ||||
| 		} | ||||
| 	} | ||||
| 	delete(visited, typ) | ||||
| } | ||||
|  | ||||
| // computeMethodSets determines the actual method sets for each type encountered. | ||||
| // | ||||
| func (r *reader) computeMethodSets() { | ||||
| 	for _, t := range r.types { | ||||
| 		// collect embedded methods for t | ||||
| 		if t.isStruct { | ||||
| 			// struct | ||||
| 			r.collectEmbeddedMethods(t.methods, t, t.name, false, 1, make(embeddedSet)) | ||||
| 		} else { | ||||
| 			// interface | ||||
| 			// TODO(gri) fix this | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// if error was declared locally, don't treat it as exported field anymore | ||||
| 	if r.errorDecl { | ||||
| 		for _, ityp := range r.fixlist { | ||||
| 			removeErrorField(ityp) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // cleanupTypes removes the association of functions and methods with | ||||
| // types that have no declaration. Instead, these functions and methods | ||||
| // are shown at the package level. It also removes types with missing | ||||
| // declarations or which are not visible. | ||||
| // | ||||
| func (r *reader) cleanupTypes() { | ||||
| 	for _, t := range r.types { | ||||
| 		visible := r.isVisible(t.name) | ||||
| 		if t.decl == nil && (predeclaredTypes[t.name] || t.isEmbedded && visible) { | ||||
| 			// t.name is a predeclared type (and was not redeclared in this package), | ||||
| 			// or it was embedded somewhere but its declaration is missing (because | ||||
| 			// the AST is incomplete): move any associated values, funcs, and methods | ||||
| 			// back to the top-level so that they are not lost. | ||||
| 			// 1) move values | ||||
| 			r.values = append(r.values, t.values...) | ||||
| 			// 2) move factory functions | ||||
| 			for name, f := range t.funcs { | ||||
| 				// in a correct AST, package-level function names | ||||
| 				// are all different - no need to check for conflicts | ||||
| 				r.funcs[name] = f | ||||
| 			} | ||||
| 			// 3) move methods | ||||
| 			for name, m := range t.methods { | ||||
| 				// don't overwrite functions with the same name - drop them | ||||
| 				if _, found := r.funcs[name]; !found { | ||||
| 					r.funcs[name] = m | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		// remove types w/o declaration or which are not visible | ||||
| 		if t.decl == nil || !visible { | ||||
| 			delete(r.types, t.name) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Sorting | ||||
|  | ||||
| type data struct { | ||||
| 	n    int | ||||
| 	swap func(i, j int) | ||||
| 	less func(i, j int) bool | ||||
| } | ||||
|  | ||||
| func (d *data) Len() int           { return d.n } | ||||
| func (d *data) Swap(i, j int)      { d.swap(i, j) } | ||||
| func (d *data) Less(i, j int) bool { return d.less(i, j) } | ||||
|  | ||||
| // sortBy is a helper function for sorting | ||||
| func sortBy(less func(i, j int) bool, swap func(i, j int), n int) { | ||||
| 	sort.Sort(&data{n, swap, less}) | ||||
| } | ||||
|  | ||||
| func sortedKeys(m map[string]int) []string { | ||||
| 	list := make([]string, len(m)) | ||||
| 	i := 0 | ||||
| 	for key := range m { | ||||
| 		list[i] = key | ||||
| 		i++ | ||||
| 	} | ||||
| 	sort.Strings(list) | ||||
| 	return list | ||||
| } | ||||
|  | ||||
| // sortingName returns the name to use when sorting d into place. | ||||
| // | ||||
| func sortingName(d *ast.GenDecl) string { | ||||
| 	if len(d.Specs) == 1 { | ||||
| 		if s, ok := d.Specs[0].(*ast.ValueSpec); ok { | ||||
| 			return s.Names[0].Name | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func sortedValues(m []*Value, tok token.Token) []*Value { | ||||
| 	list := make([]*Value, len(m)) // big enough in any case | ||||
| 	i := 0 | ||||
| 	for _, val := range m { | ||||
| 		if val.Decl.Tok == tok { | ||||
| 			list[i] = val | ||||
| 			i++ | ||||
| 		} | ||||
| 	} | ||||
| 	list = list[0:i] | ||||
|  | ||||
| 	sortBy( | ||||
| 		func(i, j int) bool { | ||||
| 			if ni, nj := sortingName(list[i].Decl), sortingName(list[j].Decl); ni != nj { | ||||
| 				return ni < nj | ||||
| 			} | ||||
| 			return list[i].order < list[j].order | ||||
| 		}, | ||||
| 		func(i, j int) { list[i], list[j] = list[j], list[i] }, | ||||
| 		len(list), | ||||
| 	) | ||||
|  | ||||
| 	return list | ||||
| } | ||||
|  | ||||
| func sortedTypes(m map[string]*namedType, allMethods bool) []*Type { | ||||
| 	list := make([]*Type, len(m)) | ||||
| 	i := 0 | ||||
| 	for _, t := range m { | ||||
| 		list[i] = &Type{ | ||||
| 			Doc:     t.doc, | ||||
| 			Name:    t.name, | ||||
| 			Decl:    t.decl, | ||||
| 			Consts:  sortedValues(t.values, token.CONST), | ||||
| 			Vars:    sortedValues(t.values, token.VAR), | ||||
| 			Funcs:   sortedFuncs(t.funcs, true), | ||||
| 			Methods: sortedFuncs(t.methods, allMethods), | ||||
| 		} | ||||
| 		i++ | ||||
| 	} | ||||
|  | ||||
| 	sortBy( | ||||
| 		func(i, j int) bool { return list[i].Name < list[j].Name }, | ||||
| 		func(i, j int) { list[i], list[j] = list[j], list[i] }, | ||||
| 		len(list), | ||||
| 	) | ||||
|  | ||||
| 	return list | ||||
| } | ||||
|  | ||||
| func removeStar(s string) string { | ||||
| 	if len(s) > 0 && s[0] == '*' { | ||||
| 		return s[1:] | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| func sortedFuncs(m methodSet, allMethods bool) []*Func { | ||||
| 	list := make([]*Func, len(m)) | ||||
| 	i := 0 | ||||
| 	for _, m := range m { | ||||
| 		// determine which methods to include | ||||
| 		switch { | ||||
| 		case m.Decl == nil: | ||||
| 			// exclude conflict entry | ||||
| 		case allMethods, m.Level == 0, !ast.IsExported(removeStar(m.Orig)): | ||||
| 			// forced inclusion, method not embedded, or method | ||||
| 			// embedded but original receiver type not exported | ||||
| 			list[i] = m | ||||
| 			i++ | ||||
| 		} | ||||
| 	} | ||||
| 	list = list[0:i] | ||||
| 	sortBy( | ||||
| 		func(i, j int) bool { return list[i].Name < list[j].Name }, | ||||
| 		func(i, j int) { list[i], list[j] = list[j], list[i] }, | ||||
| 		len(list), | ||||
| 	) | ||||
| 	return list | ||||
| } | ||||
|  | ||||
| // noteBodies returns a list of note body strings given a list of notes. | ||||
| // This is only used to populate the deprecated Package.Bugs field. | ||||
| // | ||||
| func noteBodies(notes []*Note) []string { | ||||
| 	var list []string | ||||
| 	for _, n := range notes { | ||||
| 		list = append(list, n.Body) | ||||
| 	} | ||||
| 	return list | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Predeclared identifiers | ||||
|  | ||||
| var predeclaredTypes = map[string]bool{ | ||||
| 	"bool":       true, | ||||
| 	"byte":       true, | ||||
| 	"complex64":  true, | ||||
| 	"complex128": true, | ||||
| 	"error":      true, | ||||
| 	"float32":    true, | ||||
| 	"float64":    true, | ||||
| 	"int":        true, | ||||
| 	"int8":       true, | ||||
| 	"int16":      true, | ||||
| 	"int32":      true, | ||||
| 	"int64":      true, | ||||
| 	"rune":       true, | ||||
| 	"string":     true, | ||||
| 	"uint":       true, | ||||
| 	"uint8":      true, | ||||
| 	"uint16":     true, | ||||
| 	"uint32":     true, | ||||
| 	"uint64":     true, | ||||
| 	"uintptr":    true, | ||||
| } | ||||
|  | ||||
| var predeclaredFuncs = map[string]bool{ | ||||
| 	"append":  true, | ||||
| 	"cap":     true, | ||||
| 	"close":   true, | ||||
| 	"complex": true, | ||||
| 	"copy":    true, | ||||
| 	"delete":  true, | ||||
| 	"imag":    true, | ||||
| 	"len":     true, | ||||
| 	"make":    true, | ||||
| 	"new":     true, | ||||
| 	"panic":   true, | ||||
| 	"print":   true, | ||||
| 	"println": true, | ||||
| 	"real":    true, | ||||
| 	"recover": true, | ||||
| } | ||||
|  | ||||
| var predeclaredConstants = map[string]bool{ | ||||
| 	"false": true, | ||||
| 	"iota":  true, | ||||
| 	"nil":   true, | ||||
| 	"true":  true, | ||||
| } | ||||
							
								
								
									
										82
									
								
								third_party/golang/go/doc/synopsis.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								third_party/golang/go/doc/synopsis.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| package doc | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| ) | ||||
|  | ||||
| // firstSentenceLen returns the length of the first sentence in s. | ||||
| // The sentence ends after the first period followed by space and | ||||
| // not preceded by exactly one uppercase letter. | ||||
| // | ||||
| func firstSentenceLen(s string) int { | ||||
| 	var ppp, pp, p rune | ||||
| 	for i, q := range s { | ||||
| 		if q == '\n' || q == '\r' || q == '\t' { | ||||
| 			q = ' ' | ||||
| 		} | ||||
| 		if q == ' ' && p == '.' && (!unicode.IsUpper(pp) || unicode.IsUpper(ppp)) { | ||||
| 			return i | ||||
| 		} | ||||
| 		if p == '。' || p == '.' { | ||||
| 			return i | ||||
| 		} | ||||
| 		ppp, pp, p = pp, p, q | ||||
| 	} | ||||
| 	return len(s) | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	keepNL = 1 << iota | ||||
| ) | ||||
|  | ||||
| // clean replaces each sequence of space, \n, \r, or \t characters | ||||
| // with a single space and removes any trailing and leading spaces. | ||||
| // If the keepNL flag is set, newline characters are passed through | ||||
| // instead of being change to spaces. | ||||
| func clean(s string, flags int) string { | ||||
| 	var b []byte | ||||
| 	p := byte(' ') | ||||
| 	for i := 0; i < len(s); i++ { | ||||
| 		q := s[i] | ||||
| 		if (flags&keepNL) == 0 && q == '\n' || q == '\r' || q == '\t' { | ||||
| 			q = ' ' | ||||
| 		} | ||||
| 		if q != ' ' || p != ' ' { | ||||
| 			b = append(b, q) | ||||
| 			p = q | ||||
| 		} | ||||
| 	} | ||||
| 	// remove trailing blank, if any | ||||
| 	if n := len(b); n > 0 && p == ' ' { | ||||
| 		b = b[0 : n-1] | ||||
| 	} | ||||
| 	return string(b) | ||||
| } | ||||
|  | ||||
| // Synopsis returns a cleaned version of the first sentence in s. | ||||
| // That sentence ends after the first period followed by space and | ||||
| // not preceded by exactly one uppercase letter. The result string | ||||
| // has no \n, \r, or \t characters and uses only single spaces between | ||||
| // words. If s starts with any of the IllegalPrefixes, the result | ||||
| // is the empty string. | ||||
| // | ||||
| func Synopsis(s string) string { | ||||
| 	s = clean(s[0:firstSentenceLen(s)], 0) | ||||
| 	for _, prefix := range IllegalPrefixes { | ||||
| 		if strings.HasPrefix(strings.ToLower(s), prefix) { | ||||
| 			return "" | ||||
| 		} | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| var IllegalPrefixes = []string{ | ||||
| 	"copyright", | ||||
| 	"all rights", | ||||
| 	"author", | ||||
| } | ||||
							
								
								
									
										51
									
								
								third_party/golang/go/doc/synopsis_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								third_party/golang/go/doc/synopsis_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| package doc | ||||
|  | ||||
| import "testing" | ||||
|  | ||||
| var tests = []struct { | ||||
| 	txt string | ||||
| 	fsl int | ||||
| 	syn string | ||||
| }{ | ||||
| 	{"", 0, ""}, | ||||
| 	{"foo", 3, "foo"}, | ||||
| 	{"foo.", 4, "foo."}, | ||||
| 	{"foo.bar", 7, "foo.bar"}, | ||||
| 	{"  foo.  ", 6, "foo."}, | ||||
| 	{"  foo\t  bar.\n", 12, "foo bar."}, | ||||
| 	{"  foo\t  bar.\n", 12, "foo bar."}, | ||||
| 	{"a  b\n\nc\r\rd\t\t", 12, "a b c d"}, | ||||
| 	{"a  b\n\nc\r\rd\t\t  . BLA", 15, "a b c d ."}, | ||||
| 	{"Package poems by T.S.Eliot. To rhyme...", 27, "Package poems by T.S.Eliot."}, | ||||
| 	{"Package poems by T. S. Eliot. To rhyme...", 29, "Package poems by T. S. Eliot."}, | ||||
| 	{"foo implements the foo ABI. The foo ABI is...", 27, "foo implements the foo ABI."}, | ||||
| 	{"Package\nfoo. ..", 12, "Package foo."}, | ||||
| 	{"P . Q.", 3, "P ."}, | ||||
| 	{"P. Q.   ", 8, "P. Q."}, | ||||
| 	{"Package Καλημέρα κόσμε.", 36, "Package Καλημέρα κόσμε."}, | ||||
| 	{"Package こんにちは 世界\n", 31, "Package こんにちは 世界"}, | ||||
| 	{"Package こんにちは。世界", 26, "Package こんにちは。"}, | ||||
| 	{"Package 안녕.世界", 17, "Package 안녕."}, | ||||
| 	{"Package foo does bar.", 21, "Package foo does bar."}, | ||||
| 	{"Copyright 2012 Google, Inc. Package foo does bar.", 27, ""}, | ||||
| 	{"All Rights reserved. Package foo does bar.", 20, ""}, | ||||
| 	{"All rights reserved. Package foo does bar.", 20, ""}, | ||||
| 	{"Authors: foo@bar.com. Package foo does bar.", 21, ""}, | ||||
| } | ||||
|  | ||||
| func TestSynopsis(t *testing.T) { | ||||
| 	for _, e := range tests { | ||||
| 		fsl := firstSentenceLen(e.txt) | ||||
| 		if fsl != e.fsl { | ||||
| 			t.Errorf("got fsl = %d; want %d for %q\n", fsl, e.fsl, e.txt) | ||||
| 		} | ||||
| 		syn := Synopsis(e.txt) | ||||
| 		if syn != e.syn { | ||||
| 			t.Errorf("got syn = %q; want %q for %q\n", syn, e.syn, e.txt) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										52
									
								
								third_party/golang/go/doc/testdata/a.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								third_party/golang/go/doc/testdata/a.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| // comment 0  comment 1  | ||||
| PACKAGE a | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/a | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/a0.go | ||||
| 	testdata/a1.go | ||||
|  | ||||
| BUGS .Bugs is now deprecated, please use .Notes instead | ||||
| 	bug0 | ||||
|  | ||||
| 	bug1 | ||||
|  | ||||
|  | ||||
| BUGS | ||||
| BUG(uid)	bug0 | ||||
|  | ||||
| BUG(uid)	bug1 | ||||
|  | ||||
|  | ||||
| NOTES | ||||
| NOTE(uid)	 | ||||
|  | ||||
| NOTE(foo)	1 of 4 - this is the first line of note 1 | ||||
| 	- note 1 continues on this 2nd line | ||||
| 	- note 1 continues on this 3rd line | ||||
|  | ||||
| NOTE(foo)	2 of 4 | ||||
|  | ||||
| NOTE(bar)	3 of 4 | ||||
|  | ||||
| NOTE(bar)	4 of 4 | ||||
| 	- this is the last line of note 4 | ||||
|  | ||||
| NOTE(bam)	This note which contains a (parenthesized) subphrase | ||||
| 	 must appear in its entirety. | ||||
|  | ||||
| NOTE(xxx)	The ':' after the marker and uid is optional. | ||||
|  | ||||
|  | ||||
| SECBUGS | ||||
| SECBUG(uid)	sec hole 0 | ||||
| 	need to fix asap | ||||
|  | ||||
|  | ||||
| TODOS | ||||
| TODO(uid)	todo0 | ||||
|  | ||||
| TODO(uid)	todo1 | ||||
|  | ||||
							
								
								
									
										52
									
								
								third_party/golang/go/doc/testdata/a.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								third_party/golang/go/doc/testdata/a.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| // comment 0  comment 1  | ||||
| PACKAGE a | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/a | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/a0.go | ||||
| 	testdata/a1.go | ||||
|  | ||||
| BUGS .Bugs is now deprecated, please use .Notes instead | ||||
| 	bug0 | ||||
|  | ||||
| 	bug1 | ||||
|  | ||||
|  | ||||
| BUGS | ||||
| BUG(uid)	bug0 | ||||
|  | ||||
| BUG(uid)	bug1 | ||||
|  | ||||
|  | ||||
| NOTES | ||||
| NOTE(uid)	 | ||||
|  | ||||
| NOTE(foo)	1 of 4 - this is the first line of note 1 | ||||
| 	- note 1 continues on this 2nd line | ||||
| 	- note 1 continues on this 3rd line | ||||
|  | ||||
| NOTE(foo)	2 of 4 | ||||
|  | ||||
| NOTE(bar)	3 of 4 | ||||
|  | ||||
| NOTE(bar)	4 of 4 | ||||
| 	- this is the last line of note 4 | ||||
|  | ||||
| NOTE(bam)	This note which contains a (parenthesized) subphrase | ||||
| 	 must appear in its entirety. | ||||
|  | ||||
| NOTE(xxx)	The ':' after the marker and uid is optional. | ||||
|  | ||||
|  | ||||
| SECBUGS | ||||
| SECBUG(uid)	sec hole 0 | ||||
| 	need to fix asap | ||||
|  | ||||
|  | ||||
| TODOS | ||||
| TODO(uid)	todo0 | ||||
|  | ||||
| TODO(uid)	todo1 | ||||
|  | ||||
							
								
								
									
										52
									
								
								third_party/golang/go/doc/testdata/a.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								third_party/golang/go/doc/testdata/a.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| // comment 0  comment 1  | ||||
| PACKAGE a | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/a | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/a0.go | ||||
| 	testdata/a1.go | ||||
|  | ||||
| BUGS .Bugs is now deprecated, please use .Notes instead | ||||
| 	bug0 | ||||
|  | ||||
| 	bug1 | ||||
|  | ||||
|  | ||||
| BUGS | ||||
| BUG(uid)	bug0 | ||||
|  | ||||
| BUG(uid)	bug1 | ||||
|  | ||||
|  | ||||
| NOTES | ||||
| NOTE(uid)	 | ||||
|  | ||||
| NOTE(foo)	1 of 4 - this is the first line of note 1 | ||||
| 	- note 1 continues on this 2nd line | ||||
| 	- note 1 continues on this 3rd line | ||||
|  | ||||
| NOTE(foo)	2 of 4 | ||||
|  | ||||
| NOTE(bar)	3 of 4 | ||||
|  | ||||
| NOTE(bar)	4 of 4 | ||||
| 	- this is the last line of note 4 | ||||
|  | ||||
| NOTE(bam)	This note which contains a (parenthesized) subphrase | ||||
| 	 must appear in its entirety. | ||||
|  | ||||
| NOTE(xxx)	The ':' after the marker and uid is optional. | ||||
|  | ||||
|  | ||||
| SECBUGS | ||||
| SECBUG(uid)	sec hole 0 | ||||
| 	need to fix asap | ||||
|  | ||||
|  | ||||
| TODOS | ||||
| TODO(uid)	todo0 | ||||
|  | ||||
| TODO(uid)	todo1 | ||||
|  | ||||
							
								
								
									
										40
									
								
								third_party/golang/go/doc/testdata/a0.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								third_party/golang/go/doc/testdata/a0.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // comment 0 | ||||
| package a | ||||
|  | ||||
| //BUG(uid): bug0 | ||||
|  | ||||
| //TODO(uid): todo0 | ||||
|  | ||||
| // A note with some spaces after it, should be ignored (watch out for | ||||
| // emacs modes that remove trailing whitespace). | ||||
| //NOTE(uid): | ||||
|  | ||||
| // SECBUG(uid): sec hole 0 | ||||
| // need to fix asap | ||||
|  | ||||
| // Multiple notes may be in the same comment group and should be | ||||
| // recognized individually. Notes may start in the middle of a | ||||
| // comment group as long as they start at the beginning of an | ||||
| // individual comment. | ||||
| // | ||||
| // NOTE(foo): 1 of 4 - this is the first line of note 1 | ||||
| // - note 1 continues on this 2nd line | ||||
| // - note 1 continues on this 3rd line | ||||
| // NOTE(foo): 2 of 4 | ||||
| // NOTE(bar): 3 of 4 | ||||
| /* NOTE(bar): 4 of 4 */ | ||||
| // - this is the last line of note 4 | ||||
| // | ||||
| // | ||||
|  | ||||
| // NOTE(bam): This note which contains a (parenthesized) subphrase | ||||
| //            must appear in its entirety. | ||||
|  | ||||
| // NOTE(xxx) The ':' after the marker and uid is optional. | ||||
|  | ||||
| // NOTE(): NO uid - should not show up. | ||||
| // NOTE()  NO uid - should not show up. | ||||
							
								
								
									
										12
									
								
								third_party/golang/go/doc/testdata/a1.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								third_party/golang/go/doc/testdata/a1.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // comment 1 | ||||
| package a | ||||
|  | ||||
| //BUG(uid): bug1 | ||||
|  | ||||
| //TODO(uid): todo1 | ||||
|  | ||||
| //TODO(): ignored | ||||
							
								
								
									
										71
									
								
								third_party/golang/go/doc/testdata/b.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								third_party/golang/go/doc/testdata/b.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| //  | ||||
| PACKAGE b | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/b | ||||
|  | ||||
| IMPORTS | ||||
| 	a | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/b.go | ||||
|  | ||||
| CONSTANTS | ||||
| 	//  | ||||
| 	const ( | ||||
| 		C1	notExported	= iota | ||||
| 		C2 | ||||
| 	 | ||||
| 		C4 | ||||
| 		C5 | ||||
| 	) | ||||
|  | ||||
| 	//  | ||||
| 	const C notExported = 0 | ||||
|  | ||||
| 	//  | ||||
| 	const Pi = 3.14	// Pi | ||||
|  | ||||
|  | ||||
| VARIABLES | ||||
| 	//  | ||||
| 	var ( | ||||
| 		U1, U2, U4, U5	notExported | ||||
| 	 | ||||
| 		U7	notExported	= 7 | ||||
| 	) | ||||
|  | ||||
| 	//  | ||||
| 	var MaxInt int	// MaxInt | ||||
|  | ||||
| 	//  | ||||
| 	var V notExported | ||||
|  | ||||
| 	//  | ||||
| 	var V1, V2, V4, V5 notExported | ||||
|  | ||||
|  | ||||
| FUNCTIONS | ||||
| 	//  | ||||
| 	func F(x int) int | ||||
|  | ||||
| 	//  | ||||
| 	func F1() notExported | ||||
|  | ||||
| 	// Always under the package functions list.  | ||||
| 	func NotAFactory() int | ||||
|  | ||||
| 	// Associated with uint type if AllDecls is set.  | ||||
| 	func UintFactory() uint | ||||
|  | ||||
|  | ||||
| TYPES | ||||
| 	//  | ||||
| 	type T struct{}	// T | ||||
|  | ||||
| 	//  | ||||
| 	var V T	// v | ||||
|  | ||||
| 	//  | ||||
| 	func (x *T) M() | ||||
|  | ||||
							
								
								
									
										83
									
								
								third_party/golang/go/doc/testdata/b.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								third_party/golang/go/doc/testdata/b.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| //  | ||||
| PACKAGE b | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/b | ||||
|  | ||||
| IMPORTS | ||||
| 	a | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/b.go | ||||
|  | ||||
| CONSTANTS | ||||
| 	//  | ||||
| 	const Pi = 3.14	// Pi | ||||
|  | ||||
|  | ||||
| VARIABLES | ||||
| 	//  | ||||
| 	var MaxInt int	// MaxInt | ||||
|  | ||||
|  | ||||
| FUNCTIONS | ||||
| 	//  | ||||
| 	func F(x int) int | ||||
|  | ||||
| 	// Always under the package functions list.  | ||||
| 	func NotAFactory() int | ||||
|  | ||||
|  | ||||
| TYPES | ||||
| 	//  | ||||
| 	type T struct{}	// T | ||||
|  | ||||
| 	//  | ||||
| 	var V T	// v | ||||
|  | ||||
| 	//  | ||||
| 	func (x *T) M() | ||||
|  | ||||
| 	//  | ||||
| 	type notExported int | ||||
|  | ||||
| 	//  | ||||
| 	const ( | ||||
| 		C1	notExported	= iota | ||||
| 		C2 | ||||
| 		c3 | ||||
| 		C4 | ||||
| 		C5 | ||||
| 	) | ||||
|  | ||||
| 	//  | ||||
| 	const C notExported = 0 | ||||
|  | ||||
| 	//  | ||||
| 	var ( | ||||
| 		U1, U2, u3, U4, U5	notExported | ||||
| 		u6			notExported | ||||
| 		U7			notExported	= 7 | ||||
| 	) | ||||
|  | ||||
| 	//  | ||||
| 	var V notExported | ||||
|  | ||||
| 	//  | ||||
| 	var V1, V2, v3, V4, V5 notExported | ||||
|  | ||||
| 	//  | ||||
| 	func F1() notExported | ||||
|  | ||||
| 	//  | ||||
| 	func f2() notExported | ||||
|  | ||||
| 	// Should only appear if AllDecls is set.  | ||||
| 	type uint struct{}	// overrides a predeclared type uint | ||||
|  | ||||
| 	// Associated with uint type if AllDecls is set.  | ||||
| 	func UintFactory() uint | ||||
|  | ||||
| 	// Associated with uint type if AllDecls is set.  | ||||
| 	func uintFactory() uint | ||||
|  | ||||
							
								
								
									
										71
									
								
								third_party/golang/go/doc/testdata/b.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								third_party/golang/go/doc/testdata/b.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| //  | ||||
| PACKAGE b | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/b | ||||
|  | ||||
| IMPORTS | ||||
| 	a | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/b.go | ||||
|  | ||||
| CONSTANTS | ||||
| 	//  | ||||
| 	const ( | ||||
| 		C1	notExported	= iota | ||||
| 		C2 | ||||
| 	 | ||||
| 		C4 | ||||
| 		C5 | ||||
| 	) | ||||
|  | ||||
| 	//  | ||||
| 	const C notExported = 0 | ||||
|  | ||||
| 	//  | ||||
| 	const Pi = 3.14	// Pi | ||||
|  | ||||
|  | ||||
| VARIABLES | ||||
| 	//  | ||||
| 	var ( | ||||
| 		U1, U2, U4, U5	notExported | ||||
| 	 | ||||
| 		U7	notExported	= 7 | ||||
| 	) | ||||
|  | ||||
| 	//  | ||||
| 	var MaxInt int	// MaxInt | ||||
|  | ||||
| 	//  | ||||
| 	var V notExported | ||||
|  | ||||
| 	//  | ||||
| 	var V1, V2, V4, V5 notExported | ||||
|  | ||||
|  | ||||
| FUNCTIONS | ||||
| 	//  | ||||
| 	func F(x int) int | ||||
|  | ||||
| 	//  | ||||
| 	func F1() notExported | ||||
|  | ||||
| 	// Always under the package functions list.  | ||||
| 	func NotAFactory() int | ||||
|  | ||||
| 	// Associated with uint type if AllDecls is set.  | ||||
| 	func UintFactory() uint | ||||
|  | ||||
|  | ||||
| TYPES | ||||
| 	//  | ||||
| 	type T struct{}	// T | ||||
|  | ||||
| 	//  | ||||
| 	var V T	// v | ||||
|  | ||||
| 	//  | ||||
| 	func (x *T) M() | ||||
|  | ||||
							
								
								
									
										58
									
								
								third_party/golang/go/doc/testdata/b.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								third_party/golang/go/doc/testdata/b.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| package b | ||||
|  | ||||
| import "a" | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Basic declarations | ||||
|  | ||||
| const Pi = 3.14   // Pi | ||||
| var MaxInt int    // MaxInt | ||||
| type T struct{}   // T | ||||
| var V T           // v | ||||
| func F(x int) int {} // F | ||||
| func (x *T) M()   {} // M | ||||
|  | ||||
| // Corner cases: association with (presumed) predeclared types | ||||
|  | ||||
| // Always under the package functions list. | ||||
| func NotAFactory() int {} | ||||
|  | ||||
| // Associated with uint type if AllDecls is set. | ||||
| func UintFactory() uint {} | ||||
|  | ||||
| // Associated with uint type if AllDecls is set. | ||||
| func uintFactory() uint {} | ||||
|  | ||||
| // Should only appear if AllDecls is set. | ||||
| type uint struct{} // overrides a predeclared type uint | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Exported declarations associated with non-exported types must always be shown. | ||||
|  | ||||
| type notExported int | ||||
|  | ||||
| const C notExported = 0 | ||||
|  | ||||
| const ( | ||||
| 	C1 notExported = iota | ||||
| 	C2 | ||||
| 	c3 | ||||
| 	C4 | ||||
| 	C5 | ||||
| ) | ||||
|  | ||||
| var V notExported | ||||
| var V1, V2, v3, V4, V5 notExported | ||||
|  | ||||
| var ( | ||||
| 	U1, U2, u3, U4, U5 notExported | ||||
| 	u6                 notExported | ||||
| 	U7                 notExported = 7 | ||||
| ) | ||||
|  | ||||
| func F1() notExported {} | ||||
| func f2() notExported {} | ||||
							
								
								
									
										293
									
								
								third_party/golang/go/doc/testdata/benchmark.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								third_party/golang/go/doc/testdata/benchmark.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,293 @@ | ||||
| // Copyright 2009 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. | ||||
|  | ||||
| package testing | ||||
|  | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"runtime" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run") | ||||
| var benchTime = flag.Duration("test.benchtime", 1*time.Second, "approximate run time for each benchmark") | ||||
|  | ||||
| // An internal type but exported because it is cross-package; part of the implementation | ||||
| // of go test. | ||||
| type InternalBenchmark struct { | ||||
| 	Name string | ||||
| 	F    func(b *B) | ||||
| } | ||||
|  | ||||
| // B is a type passed to Benchmark functions to manage benchmark | ||||
| // timing and to specify the number of iterations to run. | ||||
| type B struct { | ||||
| 	common | ||||
| 	N         int | ||||
| 	benchmark InternalBenchmark | ||||
| 	bytes     int64 | ||||
| 	timerOn   bool | ||||
| 	result    BenchmarkResult | ||||
| } | ||||
|  | ||||
| // StartTimer starts timing a test.  This function is called automatically | ||||
| // before a benchmark starts, but it can also used to resume timing after | ||||
| // a call to StopTimer. | ||||
| func (b *B) StartTimer() { | ||||
| 	if !b.timerOn { | ||||
| 		b.start = time.Now() | ||||
| 		b.timerOn = true | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // StopTimer stops timing a test.  This can be used to pause the timer | ||||
| // while performing complex initialization that you don't | ||||
| // want to measure. | ||||
| func (b *B) StopTimer() { | ||||
| 	if b.timerOn { | ||||
| 		b.duration += time.Now().Sub(b.start) | ||||
| 		b.timerOn = false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ResetTimer sets the elapsed benchmark time to zero. | ||||
| // It does not affect whether the timer is running. | ||||
| func (b *B) ResetTimer() { | ||||
| 	if b.timerOn { | ||||
| 		b.start = time.Now() | ||||
| 	} | ||||
| 	b.duration = 0 | ||||
| } | ||||
|  | ||||
| // SetBytes records the number of bytes processed in a single operation. | ||||
| // If this is called, the benchmark will report ns/op and MB/s. | ||||
| func (b *B) SetBytes(n int64) { b.bytes = n } | ||||
|  | ||||
| func (b *B) nsPerOp() int64 { | ||||
| 	if b.N <= 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return b.duration.Nanoseconds() / int64(b.N) | ||||
| } | ||||
|  | ||||
| // runN runs a single benchmark for the specified number of iterations. | ||||
| func (b *B) runN(n int) { | ||||
| 	// Try to get a comparable environment for each run | ||||
| 	// by clearing garbage from previous runs. | ||||
| 	runtime.GC() | ||||
| 	b.N = n | ||||
| 	b.ResetTimer() | ||||
| 	b.StartTimer() | ||||
| 	b.benchmark.F(b) | ||||
| 	b.StopTimer() | ||||
| } | ||||
|  | ||||
| func min(x, y int) int { | ||||
| 	if x > y { | ||||
| 		return y | ||||
| 	} | ||||
| 	return x | ||||
| } | ||||
|  | ||||
| func max(x, y int) int { | ||||
| 	if x < y { | ||||
| 		return y | ||||
| 	} | ||||
| 	return x | ||||
| } | ||||
|  | ||||
| // roundDown10 rounds a number down to the nearest power of 10. | ||||
| func roundDown10(n int) int { | ||||
| 	var tens = 0 | ||||
| 	// tens = floor(log_10(n)) | ||||
| 	for n > 10 { | ||||
| 		n = n / 10 | ||||
| 		tens++ | ||||
| 	} | ||||
| 	// result = 10^tens | ||||
| 	result := 1 | ||||
| 	for i := 0; i < tens; i++ { | ||||
| 		result *= 10 | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // roundUp rounds x up to a number of the form [1eX, 2eX, 5eX]. | ||||
| func roundUp(n int) int { | ||||
| 	base := roundDown10(n) | ||||
| 	if n < (2 * base) { | ||||
| 		return 2 * base | ||||
| 	} | ||||
| 	if n < (5 * base) { | ||||
| 		return 5 * base | ||||
| 	} | ||||
| 	return 10 * base | ||||
| } | ||||
|  | ||||
| // run times the benchmark function in a separate goroutine. | ||||
| func (b *B) run() BenchmarkResult { | ||||
| 	go b.launch() | ||||
| 	<-b.signal | ||||
| 	return b.result | ||||
| } | ||||
|  | ||||
| // launch launches the benchmark function.  It gradually increases the number | ||||
| // of benchmark iterations until the benchmark runs for a second in order | ||||
| // to get a reasonable measurement.  It prints timing information in this form | ||||
| //		testing.BenchmarkHello	100000		19 ns/op | ||||
| // launch is run by the fun function as a separate goroutine. | ||||
| func (b *B) launch() { | ||||
| 	// Run the benchmark for a single iteration in case it's expensive. | ||||
| 	n := 1 | ||||
|  | ||||
| 	// Signal that we're done whether we return normally | ||||
| 	// or by FailNow's runtime.Goexit. | ||||
| 	defer func() { | ||||
| 		b.signal <- b | ||||
| 	}() | ||||
|  | ||||
| 	b.runN(n) | ||||
| 	// Run the benchmark for at least the specified amount of time. | ||||
| 	d := *benchTime | ||||
| 	for !b.failed && b.duration < d && n < 1e9 { | ||||
| 		last := n | ||||
| 		// Predict iterations/sec. | ||||
| 		if b.nsPerOp() == 0 { | ||||
| 			n = 1e9 | ||||
| 		} else { | ||||
| 			n = int(d.Nanoseconds() / b.nsPerOp()) | ||||
| 		} | ||||
| 		// Run more iterations than we think we'll need for a second (1.5x). | ||||
| 		// Don't grow too fast in case we had timing errors previously. | ||||
| 		// Be sure to run at least one more than last time. | ||||
| 		n = max(min(n+n/2, 100*last), last+1) | ||||
| 		// Round up to something easy to read. | ||||
| 		n = roundUp(n) | ||||
| 		b.runN(n) | ||||
| 	} | ||||
| 	b.result = BenchmarkResult{b.N, b.duration, b.bytes} | ||||
| } | ||||
|  | ||||
| // The results of a benchmark run. | ||||
| type BenchmarkResult struct { | ||||
| 	N     int           // The number of iterations. | ||||
| 	T     time.Duration // The total time taken. | ||||
| 	Bytes int64         // Bytes processed in one iteration. | ||||
| } | ||||
|  | ||||
| func (r BenchmarkResult) NsPerOp() int64 { | ||||
| 	if r.N <= 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return r.T.Nanoseconds() / int64(r.N) | ||||
| } | ||||
|  | ||||
| func (r BenchmarkResult) mbPerSec() float64 { | ||||
| 	if r.Bytes <= 0 || r.T <= 0 || r.N <= 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds() | ||||
| } | ||||
|  | ||||
| func (r BenchmarkResult) String() string { | ||||
| 	mbs := r.mbPerSec() | ||||
| 	mb := "" | ||||
| 	if mbs != 0 { | ||||
| 		mb = fmt.Sprintf("\t%7.2f MB/s", mbs) | ||||
| 	} | ||||
| 	nsop := r.NsPerOp() | ||||
| 	ns := fmt.Sprintf("%10d ns/op", nsop) | ||||
| 	if r.N > 0 && nsop < 100 { | ||||
| 		// The format specifiers here make sure that | ||||
| 		// the ones digits line up for all three possible formats. | ||||
| 		if nsop < 10 { | ||||
| 			ns = fmt.Sprintf("%13.2f ns/op", float64(r.T.Nanoseconds())/float64(r.N)) | ||||
| 		} else { | ||||
| 			ns = fmt.Sprintf("%12.1f ns/op", float64(r.T.Nanoseconds())/float64(r.N)) | ||||
| 		} | ||||
| 	} | ||||
| 	return fmt.Sprintf("%8d\t%s%s", r.N, ns, mb) | ||||
| } | ||||
|  | ||||
| // An internal function but exported because it is cross-package; part of the implementation | ||||
| // of go test. | ||||
| func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) { | ||||
| 	// If no flag was specified, don't run benchmarks. | ||||
| 	if len(*matchBenchmarks) == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	for _, Benchmark := range benchmarks { | ||||
| 		matched, err := matchString(*matchBenchmarks, Benchmark.Name) | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.bench: %s\n", err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		if !matched { | ||||
| 			continue | ||||
| 		} | ||||
| 		for _, procs := range cpuList { | ||||
| 			runtime.GOMAXPROCS(procs) | ||||
| 			b := &B{ | ||||
| 				common: common{ | ||||
| 					signal: make(chan interface{}), | ||||
| 				}, | ||||
| 				benchmark: Benchmark, | ||||
| 			} | ||||
| 			benchName := Benchmark.Name | ||||
| 			if procs != 1 { | ||||
| 				benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs) | ||||
| 			} | ||||
| 			fmt.Printf("%s\t", benchName) | ||||
| 			r := b.run() | ||||
| 			if b.failed { | ||||
| 				// The output could be very long here, but probably isn't. | ||||
| 				// We print it all, regardless, because we don't want to trim the reason | ||||
| 				// the benchmark failed. | ||||
| 				fmt.Printf("--- FAIL: %s\n%s", benchName, b.output) | ||||
| 				continue | ||||
| 			} | ||||
| 			fmt.Printf("%v\n", r) | ||||
| 			// Unlike with tests, we ignore the -chatty flag and always print output for | ||||
| 			// benchmarks since the output generation time will skew the results. | ||||
| 			if len(b.output) > 0 { | ||||
| 				b.trimOutput() | ||||
| 				fmt.Printf("--- BENCH: %s\n%s", benchName, b.output) | ||||
| 			} | ||||
| 			if p := runtime.GOMAXPROCS(-1); p != procs { | ||||
| 				fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // trimOutput shortens the output from a benchmark, which can be very long. | ||||
| func (b *B) trimOutput() { | ||||
| 	// The output is likely to appear multiple times because the benchmark | ||||
| 	// is run multiple times, but at least it will be seen. This is not a big deal | ||||
| 	// because benchmarks rarely print, but just in case, we trim it if it's too long. | ||||
| 	const maxNewlines = 10 | ||||
| 	for nlCount, j := 0, 0; j < len(b.output); j++ { | ||||
| 		if b.output[j] == '\n' { | ||||
| 			nlCount++ | ||||
| 			if nlCount >= maxNewlines { | ||||
| 				b.output = append(b.output[:j], "\n\t... [output truncated]\n"...) | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Benchmark benchmarks a single function. Useful for creating | ||||
| // custom benchmarks that do not use go test. | ||||
| func Benchmark(f func(b *B)) BenchmarkResult { | ||||
| 	b := &B{ | ||||
| 		common: common{ | ||||
| 			signal: make(chan interface{}), | ||||
| 		}, | ||||
| 		benchmark: InternalBenchmark{"", f}, | ||||
| 	} | ||||
| 	return b.run() | ||||
| } | ||||
							
								
								
									
										55
									
								
								third_party/golang/go/doc/testdata/blank.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								third_party/golang/go/doc/testdata/blank.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| // Package blank is a go/doc test for the handling of _. See issue ... | ||||
| PACKAGE blank | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/blank | ||||
|  | ||||
| IMPORTS | ||||
| 	os | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/blank.go | ||||
|  | ||||
| CONSTANTS | ||||
| 	// T constants counting from unexported constants.  | ||||
| 	const ( | ||||
| 		C1	T | ||||
| 		C2 | ||||
| 	 | ||||
| 		C3 | ||||
| 	 | ||||
| 		C4	int | ||||
| 	) | ||||
|  | ||||
| 	// Constants with an imported type that needs to be propagated.  | ||||
| 	const ( | ||||
| 		Default		os.FileMode	= 0644 | ||||
| 		Useless				= 0312 | ||||
| 		WideOpen			= 0777 | ||||
| 	) | ||||
|  | ||||
| 	// Package constants.  | ||||
| 	const ( | ||||
| 		I1	int | ||||
| 		I2 | ||||
| 	) | ||||
|  | ||||
|  | ||||
| TYPES | ||||
| 	// S has a padding field.  | ||||
| 	type S struct { | ||||
| 		H	uint32 | ||||
| 	 | ||||
| 		A	uint8 | ||||
| 		// contains filtered or unexported fields | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type T int | ||||
|  | ||||
| 	// T constants counting from a blank constant.  | ||||
| 	const ( | ||||
| 		T1	T | ||||
| 		T2 | ||||
| 	) | ||||
|  | ||||
							
								
								
									
										75
									
								
								third_party/golang/go/doc/testdata/blank.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								third_party/golang/go/doc/testdata/blank.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| // Package blank is a go/doc test for the handling of _. See issue ... | ||||
| PACKAGE blank | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/blank | ||||
|  | ||||
| IMPORTS | ||||
| 	os | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/blank.go | ||||
|  | ||||
| CONSTANTS | ||||
| 	// T constants counting from unexported constants.  | ||||
| 	const ( | ||||
| 		tweedledee	T	= iota | ||||
| 		tweedledum | ||||
| 		C1 | ||||
| 		C2 | ||||
| 		alice | ||||
| 		C3 | ||||
| 		redQueen	int	= iota | ||||
| 		C4 | ||||
| 	) | ||||
|  | ||||
| 	// Package constants.  | ||||
| 	const ( | ||||
| 		_	int	= iota | ||||
| 		I1 | ||||
| 		I2 | ||||
| 	) | ||||
|  | ||||
| 	// Constants with an imported type that needs to be propagated.  | ||||
| 	const ( | ||||
| 		zero		os.FileMode	= 0 | ||||
| 		Default				= 0644 | ||||
| 		Useless				= 0312 | ||||
| 		WideOpen			= 0777 | ||||
| 	) | ||||
|  | ||||
| 	// Unexported constants counting from blank iota. See issue 9615.  | ||||
| 	const ( | ||||
| 		_	= iota | ||||
| 		one	= iota + 1 | ||||
| 	) | ||||
|  | ||||
|  | ||||
| VARIABLES | ||||
| 	//  | ||||
| 	var _ = T(55) | ||||
|  | ||||
|  | ||||
| FUNCTIONS | ||||
| 	//  | ||||
| 	func _() | ||||
|  | ||||
|  | ||||
| TYPES | ||||
| 	// S has a padding field.  | ||||
| 	type S struct { | ||||
| 		H	uint32 | ||||
| 		_	uint8 | ||||
| 		A	uint8 | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type T int | ||||
|  | ||||
| 	// T constants counting from a blank constant.  | ||||
| 	const ( | ||||
| 		_	T	= iota | ||||
| 		T1 | ||||
| 		T2 | ||||
| 	) | ||||
|  | ||||
							
								
								
									
										55
									
								
								third_party/golang/go/doc/testdata/blank.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								third_party/golang/go/doc/testdata/blank.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| // Package blank is a go/doc test for the handling of _. See issue ... | ||||
| PACKAGE blank | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/blank | ||||
|  | ||||
| IMPORTS | ||||
| 	os | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/blank.go | ||||
|  | ||||
| CONSTANTS | ||||
| 	// T constants counting from unexported constants.  | ||||
| 	const ( | ||||
| 		C1	T | ||||
| 		C2 | ||||
| 	 | ||||
| 		C3 | ||||
| 	 | ||||
| 		C4	int | ||||
| 	) | ||||
|  | ||||
| 	// Constants with an imported type that needs to be propagated.  | ||||
| 	const ( | ||||
| 		Default		os.FileMode	= 0644 | ||||
| 		Useless				= 0312 | ||||
| 		WideOpen			= 0777 | ||||
| 	) | ||||
|  | ||||
| 	// Package constants.  | ||||
| 	const ( | ||||
| 		I1	int | ||||
| 		I2 | ||||
| 	) | ||||
|  | ||||
|  | ||||
| TYPES | ||||
| 	// S has a padding field.  | ||||
| 	type S struct { | ||||
| 		H	uint32 | ||||
| 	 | ||||
| 		A	uint8 | ||||
| 		// contains filtered or unexported fields | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type T int | ||||
|  | ||||
| 	// T constants counting from a blank constant.  | ||||
| 	const ( | ||||
| 		T1	T | ||||
| 		T2 | ||||
| 	) | ||||
|  | ||||
							
								
								
									
										67
									
								
								third_party/golang/go/doc/testdata/blank.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								third_party/golang/go/doc/testdata/blank.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| // Copyright 2014 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. | ||||
|  | ||||
| // Package blank is a go/doc test for the handling of _. | ||||
| // See issue 5397. | ||||
| package blank | ||||
|  | ||||
| import "os" | ||||
|  | ||||
| type T int | ||||
|  | ||||
| // T constants counting from a blank constant. | ||||
| const ( | ||||
| 	_ T = iota | ||||
| 	T1 | ||||
| 	T2 | ||||
| ) | ||||
|  | ||||
| // T constants counting from unexported constants. | ||||
| const ( | ||||
| 	tweedledee T = iota | ||||
| 	tweedledum | ||||
| 	C1 | ||||
| 	C2 | ||||
| 	alice | ||||
| 	C3 | ||||
| 	redQueen int = iota | ||||
| 	C4 | ||||
| ) | ||||
|  | ||||
| // Constants with an imported type that needs to be propagated. | ||||
| const ( | ||||
| 	zero     os.FileMode = 0 | ||||
| 	Default              = 0644 | ||||
| 	Useless              = 0312 | ||||
| 	WideOpen             = 0777 | ||||
| ) | ||||
|  | ||||
| // Package constants. | ||||
| const ( | ||||
| 	_ int = iota | ||||
| 	I1 | ||||
| 	I2 | ||||
| ) | ||||
|  | ||||
| // Unexported constants counting from blank iota. | ||||
| // See issue 9615. | ||||
| const ( | ||||
| 	_   = iota | ||||
| 	one = iota + 1 | ||||
| ) | ||||
|  | ||||
| // Blanks not in doc output: | ||||
|  | ||||
| // S has a padding field. | ||||
| type S struct { | ||||
| 	H uint32 | ||||
| 	_ uint8 | ||||
| 	A uint8 | ||||
| } | ||||
|  | ||||
| func _() {} | ||||
|  | ||||
| type _ T | ||||
|  | ||||
| var _ = T(55) | ||||
							
								
								
									
										20
									
								
								third_party/golang/go/doc/testdata/bugpara.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								third_party/golang/go/doc/testdata/bugpara.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| //  | ||||
| PACKAGE bugpara | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/bugpara | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/bugpara.go | ||||
|  | ||||
| BUGS .Bugs is now deprecated, please use .Notes instead | ||||
| 	Sometimes bugs have multiple paragraphs. | ||||
| 	 | ||||
| 	Like this one. | ||||
|  | ||||
|  | ||||
| BUGS | ||||
| BUG(rsc)	Sometimes bugs have multiple paragraphs. | ||||
| 	 | ||||
| 	Like this one. | ||||
|  | ||||
							
								
								
									
										20
									
								
								third_party/golang/go/doc/testdata/bugpara.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								third_party/golang/go/doc/testdata/bugpara.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| //  | ||||
| PACKAGE bugpara | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/bugpara | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/bugpara.go | ||||
|  | ||||
| BUGS .Bugs is now deprecated, please use .Notes instead | ||||
| 	Sometimes bugs have multiple paragraphs. | ||||
| 	 | ||||
| 	Like this one. | ||||
|  | ||||
|  | ||||
| BUGS | ||||
| BUG(rsc)	Sometimes bugs have multiple paragraphs. | ||||
| 	 | ||||
| 	Like this one. | ||||
|  | ||||
							
								
								
									
										20
									
								
								third_party/golang/go/doc/testdata/bugpara.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								third_party/golang/go/doc/testdata/bugpara.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| //  | ||||
| PACKAGE bugpara | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/bugpara | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/bugpara.go | ||||
|  | ||||
| BUGS .Bugs is now deprecated, please use .Notes instead | ||||
| 	Sometimes bugs have multiple paragraphs. | ||||
| 	 | ||||
| 	Like this one. | ||||
|  | ||||
|  | ||||
| BUGS | ||||
| BUG(rsc)	Sometimes bugs have multiple paragraphs. | ||||
| 	 | ||||
| 	Like this one. | ||||
|  | ||||
							
								
								
									
										5
									
								
								third_party/golang/go/doc/testdata/bugpara.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								third_party/golang/go/doc/testdata/bugpara.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| package bugpara | ||||
|  | ||||
| // BUG(rsc): Sometimes bugs have multiple paragraphs. | ||||
| // | ||||
| // Like this one. | ||||
							
								
								
									
										48
									
								
								third_party/golang/go/doc/testdata/c.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								third_party/golang/go/doc/testdata/c.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| //  | ||||
| PACKAGE c | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/c | ||||
|  | ||||
| IMPORTS | ||||
| 	a | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/c.go | ||||
|  | ||||
| TYPES | ||||
| 	// A (should see this)  | ||||
| 	type A struct{} | ||||
|  | ||||
| 	// B (should see this)  | ||||
| 	type B struct{} | ||||
|  | ||||
| 	// C (should see this)  | ||||
| 	type C struct{} | ||||
|  | ||||
| 	// D (should see this)  | ||||
| 	type D struct{} | ||||
|  | ||||
| 	// E1 (should see this)  | ||||
| 	type E1 struct{} | ||||
|  | ||||
| 	// E (should see this for E2 and E3)  | ||||
| 	type E2 struct{} | ||||
|  | ||||
| 	// E (should see this for E2 and E3)  | ||||
| 	type E3 struct{} | ||||
|  | ||||
| 	// E4 (should see this)  | ||||
| 	type E4 struct{} | ||||
|  | ||||
| 	//  | ||||
| 	type T1 struct{} | ||||
|  | ||||
| 	//  | ||||
| 	func (t1 *T1) M() | ||||
|  | ||||
| 	// T2 must not show methods of local T1  | ||||
| 	type T2 struct { | ||||
| 		a.T1	// not the same as locally declared T1 | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										48
									
								
								third_party/golang/go/doc/testdata/c.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								third_party/golang/go/doc/testdata/c.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| //  | ||||
| PACKAGE c | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/c | ||||
|  | ||||
| IMPORTS | ||||
| 	a | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/c.go | ||||
|  | ||||
| TYPES | ||||
| 	// A (should see this)  | ||||
| 	type A struct{} | ||||
|  | ||||
| 	// B (should see this)  | ||||
| 	type B struct{} | ||||
|  | ||||
| 	// C (should see this)  | ||||
| 	type C struct{} | ||||
|  | ||||
| 	// D (should see this)  | ||||
| 	type D struct{} | ||||
|  | ||||
| 	// E1 (should see this)  | ||||
| 	type E1 struct{} | ||||
|  | ||||
| 	// E (should see this for E2 and E3)  | ||||
| 	type E2 struct{} | ||||
|  | ||||
| 	// E (should see this for E2 and E3)  | ||||
| 	type E3 struct{} | ||||
|  | ||||
| 	// E4 (should see this)  | ||||
| 	type E4 struct{} | ||||
|  | ||||
| 	//  | ||||
| 	type T1 struct{} | ||||
|  | ||||
| 	//  | ||||
| 	func (t1 *T1) M() | ||||
|  | ||||
| 	// T2 must not show methods of local T1  | ||||
| 	type T2 struct { | ||||
| 		a.T1	// not the same as locally declared T1 | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										48
									
								
								third_party/golang/go/doc/testdata/c.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								third_party/golang/go/doc/testdata/c.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| //  | ||||
| PACKAGE c | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/c | ||||
|  | ||||
| IMPORTS | ||||
| 	a | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/c.go | ||||
|  | ||||
| TYPES | ||||
| 	// A (should see this)  | ||||
| 	type A struct{} | ||||
|  | ||||
| 	// B (should see this)  | ||||
| 	type B struct{} | ||||
|  | ||||
| 	// C (should see this)  | ||||
| 	type C struct{} | ||||
|  | ||||
| 	// D (should see this)  | ||||
| 	type D struct{} | ||||
|  | ||||
| 	// E1 (should see this)  | ||||
| 	type E1 struct{} | ||||
|  | ||||
| 	// E (should see this for E2 and E3)  | ||||
| 	type E2 struct{} | ||||
|  | ||||
| 	// E (should see this for E2 and E3)  | ||||
| 	type E3 struct{} | ||||
|  | ||||
| 	// E4 (should see this)  | ||||
| 	type E4 struct{} | ||||
|  | ||||
| 	//  | ||||
| 	type T1 struct{} | ||||
|  | ||||
| 	//  | ||||
| 	func (t1 *T1) M() | ||||
|  | ||||
| 	// T2 must not show methods of local T1  | ||||
| 	type T2 struct { | ||||
| 		a.T1	// not the same as locally declared T1 | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										62
									
								
								third_party/golang/go/doc/testdata/c.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								third_party/golang/go/doc/testdata/c.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| package c | ||||
|  | ||||
| import "a" | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Test that empty declarations don't cause problems | ||||
|  | ||||
| const () | ||||
|  | ||||
| type () | ||||
|  | ||||
| var () | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Test that types with documentation on both, the Decl and the Spec node | ||||
| // are handled correctly. | ||||
|  | ||||
| // A (should see this) | ||||
| type A struct{} | ||||
|  | ||||
| // B (should see this) | ||||
| type ( | ||||
| 	B struct{} | ||||
| ) | ||||
|  | ||||
| type ( | ||||
| 	// C (should see this) | ||||
| 	C struct{} | ||||
| ) | ||||
|  | ||||
| // D (should not see this) | ||||
| type ( | ||||
| 	// D (should see this) | ||||
| 	D struct{} | ||||
| ) | ||||
|  | ||||
| // E (should see this for E2 and E3) | ||||
| type ( | ||||
| 	// E1 (should see this) | ||||
| 	E1 struct{} | ||||
| 	E2 struct{} | ||||
| 	E3 struct{} | ||||
| 	// E4 (should see this) | ||||
| 	E4 struct{} | ||||
| ) | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Test that local and imported types are different when | ||||
| // handling anonymous fields. | ||||
|  | ||||
| type T1 struct{} | ||||
|  | ||||
| func (t1 *T1) M() {} | ||||
|  | ||||
| // T2 must not show methods of local T1 | ||||
| type T2 struct { | ||||
| 	a.T1 // not the same as locally declared T1 | ||||
| } | ||||
							
								
								
									
										104
									
								
								third_party/golang/go/doc/testdata/d.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								third_party/golang/go/doc/testdata/d.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| //  | ||||
| PACKAGE d | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/d | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/d1.go | ||||
| 	testdata/d2.go | ||||
|  | ||||
| CONSTANTS | ||||
| 	// CBx constants should appear before CAx constants.  | ||||
| 	const ( | ||||
| 		CB2	= iota	// before CB1 | ||||
| 		CB1		// before CB0 | ||||
| 		CB0		// at end | ||||
| 	) | ||||
|  | ||||
| 	// CAx constants should appear after CBx constants.  | ||||
| 	const ( | ||||
| 		CA2	= iota	// before CA1 | ||||
| 		CA1		// before CA0 | ||||
| 		CA0		// at end | ||||
| 	) | ||||
|  | ||||
| 	// C0 should be first.  | ||||
| 	const C0 = 0 | ||||
|  | ||||
| 	// C1 should be second.  | ||||
| 	const C1 = 1 | ||||
|  | ||||
| 	// C2 should be third.  | ||||
| 	const C2 = 2 | ||||
|  | ||||
| 	//  | ||||
| 	const ( | ||||
| 		// Single const declarations inside ()'s are considered ungrouped | ||||
| 		// and show up in sorted order. | ||||
| 		Cungrouped = 0 | ||||
| 	) | ||||
|  | ||||
|  | ||||
| VARIABLES | ||||
| 	// VBx variables should appear before VAx variables.  | ||||
| 	var ( | ||||
| 		VB2	int	// before VB1 | ||||
| 		VB1	int	// before VB0 | ||||
| 		VB0	int	// at end | ||||
| 	) | ||||
|  | ||||
| 	// VAx variables should appear after VBx variables.  | ||||
| 	var ( | ||||
| 		VA2	int	// before VA1 | ||||
| 		VA1	int	// before VA0 | ||||
| 		VA0	int	// at end | ||||
| 	) | ||||
|  | ||||
| 	// V0 should be first.  | ||||
| 	var V0 uintptr | ||||
|  | ||||
| 	// V1 should be second.  | ||||
| 	var V1 uint | ||||
|  | ||||
| 	// V2 should be third.  | ||||
| 	var V2 int | ||||
|  | ||||
| 	//  | ||||
| 	var ( | ||||
| 		// Single var declarations inside ()'s are considered ungrouped | ||||
| 		// and show up in sorted order. | ||||
| 		Vungrouped = 0 | ||||
| 	) | ||||
|  | ||||
|  | ||||
| FUNCTIONS | ||||
| 	// F0 should be first.  | ||||
| 	func F0() | ||||
|  | ||||
| 	// F1 should be second.  | ||||
| 	func F1() | ||||
|  | ||||
| 	// F2 should be third.  | ||||
| 	func F2() | ||||
|  | ||||
|  | ||||
| TYPES | ||||
| 	// T0 should be first.  | ||||
| 	type T0 struct{} | ||||
|  | ||||
| 	// T1 should be second.  | ||||
| 	type T1 struct{} | ||||
|  | ||||
| 	// T2 should be third.  | ||||
| 	type T2 struct{} | ||||
|  | ||||
| 	// TG0 should be first.  | ||||
| 	type TG0 struct{} | ||||
|  | ||||
| 	// TG1 should be second.  | ||||
| 	type TG1 struct{} | ||||
|  | ||||
| 	// TG2 should be third.  | ||||
| 	type TG2 struct{} | ||||
|  | ||||
							
								
								
									
										104
									
								
								third_party/golang/go/doc/testdata/d.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								third_party/golang/go/doc/testdata/d.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| //  | ||||
| PACKAGE d | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/d | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/d1.go | ||||
| 	testdata/d2.go | ||||
|  | ||||
| CONSTANTS | ||||
| 	// CBx constants should appear before CAx constants.  | ||||
| 	const ( | ||||
| 		CB2	= iota	// before CB1 | ||||
| 		CB1		// before CB0 | ||||
| 		CB0		// at end | ||||
| 	) | ||||
|  | ||||
| 	// CAx constants should appear after CBx constants.  | ||||
| 	const ( | ||||
| 		CA2	= iota	// before CA1 | ||||
| 		CA1		// before CA0 | ||||
| 		CA0		// at end | ||||
| 	) | ||||
|  | ||||
| 	// C0 should be first.  | ||||
| 	const C0 = 0 | ||||
|  | ||||
| 	// C1 should be second.  | ||||
| 	const C1 = 1 | ||||
|  | ||||
| 	// C2 should be third.  | ||||
| 	const C2 = 2 | ||||
|  | ||||
| 	//  | ||||
| 	const ( | ||||
| 		// Single const declarations inside ()'s are considered ungrouped | ||||
| 		// and show up in sorted order. | ||||
| 		Cungrouped = 0 | ||||
| 	) | ||||
|  | ||||
|  | ||||
| VARIABLES | ||||
| 	// VBx variables should appear before VAx variables.  | ||||
| 	var ( | ||||
| 		VB2	int	// before VB1 | ||||
| 		VB1	int	// before VB0 | ||||
| 		VB0	int	// at end | ||||
| 	) | ||||
|  | ||||
| 	// VAx variables should appear after VBx variables.  | ||||
| 	var ( | ||||
| 		VA2	int	// before VA1 | ||||
| 		VA1	int	// before VA0 | ||||
| 		VA0	int	// at end | ||||
| 	) | ||||
|  | ||||
| 	// V0 should be first.  | ||||
| 	var V0 uintptr | ||||
|  | ||||
| 	// V1 should be second.  | ||||
| 	var V1 uint | ||||
|  | ||||
| 	// V2 should be third.  | ||||
| 	var V2 int | ||||
|  | ||||
| 	//  | ||||
| 	var ( | ||||
| 		// Single var declarations inside ()'s are considered ungrouped | ||||
| 		// and show up in sorted order. | ||||
| 		Vungrouped = 0 | ||||
| 	) | ||||
|  | ||||
|  | ||||
| FUNCTIONS | ||||
| 	// F0 should be first.  | ||||
| 	func F0() | ||||
|  | ||||
| 	// F1 should be second.  | ||||
| 	func F1() | ||||
|  | ||||
| 	// F2 should be third.  | ||||
| 	func F2() | ||||
|  | ||||
|  | ||||
| TYPES | ||||
| 	// T0 should be first.  | ||||
| 	type T0 struct{} | ||||
|  | ||||
| 	// T1 should be second.  | ||||
| 	type T1 struct{} | ||||
|  | ||||
| 	// T2 should be third.  | ||||
| 	type T2 struct{} | ||||
|  | ||||
| 	// TG0 should be first.  | ||||
| 	type TG0 struct{} | ||||
|  | ||||
| 	// TG1 should be second.  | ||||
| 	type TG1 struct{} | ||||
|  | ||||
| 	// TG2 should be third.  | ||||
| 	type TG2 struct{} | ||||
|  | ||||
							
								
								
									
										104
									
								
								third_party/golang/go/doc/testdata/d.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								third_party/golang/go/doc/testdata/d.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| //  | ||||
| PACKAGE d | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/d | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/d1.go | ||||
| 	testdata/d2.go | ||||
|  | ||||
| CONSTANTS | ||||
| 	// CBx constants should appear before CAx constants.  | ||||
| 	const ( | ||||
| 		CB2	= iota	// before CB1 | ||||
| 		CB1		// before CB0 | ||||
| 		CB0		// at end | ||||
| 	) | ||||
|  | ||||
| 	// CAx constants should appear after CBx constants.  | ||||
| 	const ( | ||||
| 		CA2	= iota	// before CA1 | ||||
| 		CA1		// before CA0 | ||||
| 		CA0		// at end | ||||
| 	) | ||||
|  | ||||
| 	// C0 should be first.  | ||||
| 	const C0 = 0 | ||||
|  | ||||
| 	// C1 should be second.  | ||||
| 	const C1 = 1 | ||||
|  | ||||
| 	// C2 should be third.  | ||||
| 	const C2 = 2 | ||||
|  | ||||
| 	//  | ||||
| 	const ( | ||||
| 		// Single const declarations inside ()'s are considered ungrouped | ||||
| 		// and show up in sorted order. | ||||
| 		Cungrouped = 0 | ||||
| 	) | ||||
|  | ||||
|  | ||||
| VARIABLES | ||||
| 	// VBx variables should appear before VAx variables.  | ||||
| 	var ( | ||||
| 		VB2	int	// before VB1 | ||||
| 		VB1	int	// before VB0 | ||||
| 		VB0	int	// at end | ||||
| 	) | ||||
|  | ||||
| 	// VAx variables should appear after VBx variables.  | ||||
| 	var ( | ||||
| 		VA2	int	// before VA1 | ||||
| 		VA1	int	// before VA0 | ||||
| 		VA0	int	// at end | ||||
| 	) | ||||
|  | ||||
| 	// V0 should be first.  | ||||
| 	var V0 uintptr | ||||
|  | ||||
| 	// V1 should be second.  | ||||
| 	var V1 uint | ||||
|  | ||||
| 	// V2 should be third.  | ||||
| 	var V2 int | ||||
|  | ||||
| 	//  | ||||
| 	var ( | ||||
| 		// Single var declarations inside ()'s are considered ungrouped | ||||
| 		// and show up in sorted order. | ||||
| 		Vungrouped = 0 | ||||
| 	) | ||||
|  | ||||
|  | ||||
| FUNCTIONS | ||||
| 	// F0 should be first.  | ||||
| 	func F0() | ||||
|  | ||||
| 	// F1 should be second.  | ||||
| 	func F1() | ||||
|  | ||||
| 	// F2 should be third.  | ||||
| 	func F2() | ||||
|  | ||||
|  | ||||
| TYPES | ||||
| 	// T0 should be first.  | ||||
| 	type T0 struct{} | ||||
|  | ||||
| 	// T1 should be second.  | ||||
| 	type T1 struct{} | ||||
|  | ||||
| 	// T2 should be third.  | ||||
| 	type T2 struct{} | ||||
|  | ||||
| 	// TG0 should be first.  | ||||
| 	type TG0 struct{} | ||||
|  | ||||
| 	// TG1 should be second.  | ||||
| 	type TG1 struct{} | ||||
|  | ||||
| 	// TG2 should be third.  | ||||
| 	type TG2 struct{} | ||||
|  | ||||
							
								
								
									
										57
									
								
								third_party/golang/go/doc/testdata/d1.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								third_party/golang/go/doc/testdata/d1.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // Test cases for sort order of declarations. | ||||
|  | ||||
| package d | ||||
|  | ||||
| // C2 should be third. | ||||
| const C2 = 2 | ||||
|  | ||||
| // V2 should be third. | ||||
| var V2 int | ||||
|  | ||||
| // CBx constants should appear before CAx constants. | ||||
| const ( | ||||
| 	CB2 = iota // before CB1 | ||||
| 	CB1        // before CB0 | ||||
| 	CB0        // at end | ||||
| ) | ||||
|  | ||||
| // VBx variables should appear before VAx variables. | ||||
| var ( | ||||
| 	VB2 int // before VB1 | ||||
| 	VB1 int // before VB0 | ||||
| 	VB0 int // at end | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// Single const declarations inside ()'s are considered ungrouped | ||||
| 	// and show up in sorted order. | ||||
| 	Cungrouped = 0 | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// Single var declarations inside ()'s are considered ungrouped | ||||
| 	// and show up in sorted order. | ||||
| 	Vungrouped = 0 | ||||
| ) | ||||
|  | ||||
| // T2 should be third. | ||||
| type T2 struct{} | ||||
|  | ||||
| // Grouped types are sorted nevertheless. | ||||
| type ( | ||||
| 	// TG2 should be third. | ||||
| 	TG2 struct{} | ||||
|  | ||||
| 	// TG1 should be second. | ||||
| 	TG1 struct{} | ||||
|  | ||||
| 	// TG0 should be first. | ||||
| 	TG0 struct{} | ||||
| ) | ||||
|  | ||||
| // F2 should be third. | ||||
| func F2() {} | ||||
							
								
								
									
										45
									
								
								third_party/golang/go/doc/testdata/d2.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								third_party/golang/go/doc/testdata/d2.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // Test cases for sort order of declarations. | ||||
|  | ||||
| package d | ||||
|  | ||||
| // C1 should be second. | ||||
| const C1 = 1 | ||||
|  | ||||
| // C0 should be first. | ||||
| const C0 = 0 | ||||
|  | ||||
| // V1 should be second. | ||||
| var V1 uint | ||||
|  | ||||
| // V0 should be first. | ||||
| var V0 uintptr | ||||
|  | ||||
| // CAx constants should appear after CBx constants. | ||||
| const ( | ||||
| 	CA2 = iota // before CA1 | ||||
| 	CA1        // before CA0 | ||||
| 	CA0        // at end | ||||
| ) | ||||
|  | ||||
| // VAx variables should appear after VBx variables. | ||||
| var ( | ||||
| 	VA2 int // before VA1 | ||||
| 	VA1 int // before VA0 | ||||
| 	VA0 int // at end | ||||
| ) | ||||
|  | ||||
| // T1 should be second. | ||||
| type T1 struct{} | ||||
|  | ||||
| // T0 should be first. | ||||
| type T0 struct{} | ||||
|  | ||||
| // F1 should be second. | ||||
| func F1() {} | ||||
|  | ||||
| // F0 should be first. | ||||
| func F0() {} | ||||
							
								
								
									
										109
									
								
								third_party/golang/go/doc/testdata/e.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								third_party/golang/go/doc/testdata/e.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| // The package e is a go/doc test for embedded methods.  | ||||
| PACKAGE e | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/e | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/e.go | ||||
|  | ||||
| TYPES | ||||
| 	// T1 has no embedded (level 1) M method due to conflict.  | ||||
| 	type T1 struct { | ||||
| 		// contains filtered or unexported fields | ||||
| 	} | ||||
|  | ||||
| 	// T2 has only M as top-level method.  | ||||
| 	type T2 struct { | ||||
| 		// contains filtered or unexported fields | ||||
| 	} | ||||
|  | ||||
| 	// T2.M should appear as method of T2.  | ||||
| 	func (T2) M() | ||||
|  | ||||
| 	// T3 has only M as top-level method.  | ||||
| 	type T3 struct { | ||||
| 		// contains filtered or unexported fields | ||||
| 	} | ||||
|  | ||||
| 	// T3.M should appear as method of T3.  | ||||
| 	func (T3) M() | ||||
|  | ||||
| 	//  | ||||
| 	type T4 struct{} | ||||
|  | ||||
| 	// T4.M should appear as method of T5 only if AllMethods is set.  | ||||
| 	func (*T4) M() | ||||
|  | ||||
| 	//  | ||||
| 	type T5 struct { | ||||
| 		T4 | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type U1 struct { | ||||
| 		*U1 | ||||
| 	} | ||||
|  | ||||
| 	// U1.M should appear as method of U1.  | ||||
| 	func (*U1) M() | ||||
|  | ||||
| 	//  | ||||
| 	type U2 struct { | ||||
| 		*U3 | ||||
| 	} | ||||
|  | ||||
| 	// U2.M should appear as method of U2 and as method of U3 only if ... | ||||
| 	func (*U2) M() | ||||
|  | ||||
| 	//  | ||||
| 	type U3 struct { | ||||
| 		*U2 | ||||
| 	} | ||||
|  | ||||
| 	// U3.N should appear as method of U3 and as method of U2 only if ... | ||||
| 	func (*U3) N() | ||||
|  | ||||
| 	//  | ||||
| 	type U4 struct { | ||||
| 		// contains filtered or unexported fields | ||||
| 	} | ||||
|  | ||||
| 	// U4.M should appear as method of U4.  | ||||
| 	func (*U4) M() | ||||
|  | ||||
| 	//  | ||||
| 	type V1 struct { | ||||
| 		*V2 | ||||
| 		*V5 | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type V2 struct { | ||||
| 		*V3 | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type V3 struct { | ||||
| 		*V4 | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type V4 struct { | ||||
| 		*V5 | ||||
| 	} | ||||
|  | ||||
| 	// V4.M should appear as method of V2 and V3 if AllMethods is set.  | ||||
| 	func (*V4) M() | ||||
|  | ||||
| 	//  | ||||
| 	type V5 struct { | ||||
| 		*V6 | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type V6 struct{} | ||||
|  | ||||
| 	// V6.M should appear as method of V1 and V5 if AllMethods is set.  | ||||
| 	func (*V6) M() | ||||
|  | ||||
							
								
								
									
										144
									
								
								third_party/golang/go/doc/testdata/e.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								third_party/golang/go/doc/testdata/e.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| // The package e is a go/doc test for embedded methods.  | ||||
| PACKAGE e | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/e | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/e.go | ||||
|  | ||||
| TYPES | ||||
| 	// T1 has no embedded (level 1) M method due to conflict.  | ||||
| 	type T1 struct { | ||||
| 		t1 | ||||
| 		t2 | ||||
| 	} | ||||
|  | ||||
| 	// T2 has only M as top-level method.  | ||||
| 	type T2 struct { | ||||
| 		t1 | ||||
| 	} | ||||
|  | ||||
| 	// T2.M should appear as method of T2.  | ||||
| 	func (T2) M() | ||||
|  | ||||
| 	// T3 has only M as top-level method.  | ||||
| 	type T3 struct { | ||||
| 		t1e | ||||
| 		t2e | ||||
| 	} | ||||
|  | ||||
| 	// T3.M should appear as method of T3.  | ||||
| 	func (T3) M() | ||||
|  | ||||
| 	//  | ||||
| 	type T4 struct{} | ||||
|  | ||||
| 	// T4.M should appear as method of T5 only if AllMethods is set.  | ||||
| 	func (*T4) M() | ||||
|  | ||||
| 	//  | ||||
| 	type T5 struct { | ||||
| 		T4 | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type U1 struct { | ||||
| 		*U1 | ||||
| 	} | ||||
|  | ||||
| 	// U1.M should appear as method of U1.  | ||||
| 	func (*U1) M() | ||||
|  | ||||
| 	//  | ||||
| 	type U2 struct { | ||||
| 		*U3 | ||||
| 	} | ||||
|  | ||||
| 	// U2.M should appear as method of U2 and as method of U3 only if ... | ||||
| 	func (*U2) M() | ||||
|  | ||||
| 	//  | ||||
| 	type U3 struct { | ||||
| 		*U2 | ||||
| 	} | ||||
|  | ||||
| 	// U3.N should appear as method of U3 and as method of U2 only if ... | ||||
| 	func (*U3) N() | ||||
|  | ||||
| 	//  | ||||
| 	type U4 struct { | ||||
| 		*u5 | ||||
| 	} | ||||
|  | ||||
| 	// U4.M should appear as method of U4.  | ||||
| 	func (*U4) M() | ||||
|  | ||||
| 	//  | ||||
| 	type V1 struct { | ||||
| 		*V2 | ||||
| 		*V5 | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type V2 struct { | ||||
| 		*V3 | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type V3 struct { | ||||
| 		*V4 | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type V4 struct { | ||||
| 		*V5 | ||||
| 	} | ||||
|  | ||||
| 	// V4.M should appear as method of V2 and V3 if AllMethods is set.  | ||||
| 	func (*V4) M() | ||||
|  | ||||
| 	//  | ||||
| 	type V5 struct { | ||||
| 		*V6 | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type V6 struct{} | ||||
|  | ||||
| 	// V6.M should appear as method of V1 and V5 if AllMethods is set.  | ||||
| 	func (*V6) M() | ||||
|  | ||||
| 	//  | ||||
| 	type t1 struct{} | ||||
|  | ||||
| 	// t1.M should not appear as method in a Tx type.  | ||||
| 	func (t1) M() | ||||
|  | ||||
| 	//  | ||||
| 	type t1e struct { | ||||
| 		t1 | ||||
| 	} | ||||
|  | ||||
| 	// t1.M should not appear as method in a Tx type.  | ||||
| 	func (t1e) M() | ||||
|  | ||||
| 	//  | ||||
| 	type t2 struct{} | ||||
|  | ||||
| 	// t2.M should not appear as method in a Tx type.  | ||||
| 	func (t2) M() | ||||
|  | ||||
| 	//  | ||||
| 	type t2e struct { | ||||
| 		t2 | ||||
| 	} | ||||
|  | ||||
| 	// t2.M should not appear as method in a Tx type.  | ||||
| 	func (t2e) M() | ||||
|  | ||||
| 	//  | ||||
| 	type u5 struct { | ||||
| 		*U4 | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										130
									
								
								third_party/golang/go/doc/testdata/e.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								third_party/golang/go/doc/testdata/e.2.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| // The package e is a go/doc test for embedded methods.  | ||||
| PACKAGE e | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/e | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/e.go | ||||
|  | ||||
| TYPES | ||||
| 	// T1 has no embedded (level 1) M method due to conflict.  | ||||
| 	type T1 struct { | ||||
| 		// contains filtered or unexported fields | ||||
| 	} | ||||
|  | ||||
| 	// T2 has only M as top-level method.  | ||||
| 	type T2 struct { | ||||
| 		// contains filtered or unexported fields | ||||
| 	} | ||||
|  | ||||
| 	// T2.M should appear as method of T2.  | ||||
| 	func (T2) M() | ||||
|  | ||||
| 	// T3 has only M as top-level method.  | ||||
| 	type T3 struct { | ||||
| 		// contains filtered or unexported fields | ||||
| 	} | ||||
|  | ||||
| 	// T3.M should appear as method of T3.  | ||||
| 	func (T3) M() | ||||
|  | ||||
| 	//  | ||||
| 	type T4 struct{} | ||||
|  | ||||
| 	// T4.M should appear as method of T5 only if AllMethods is set.  | ||||
| 	func (*T4) M() | ||||
|  | ||||
| 	//  | ||||
| 	type T5 struct { | ||||
| 		T4 | ||||
| 	} | ||||
|  | ||||
| 	// T4.M should appear as method of T5 only if AllMethods is set.  | ||||
| 	func (*T5) M() | ||||
|  | ||||
| 	//  | ||||
| 	type U1 struct { | ||||
| 		*U1 | ||||
| 	} | ||||
|  | ||||
| 	// U1.M should appear as method of U1.  | ||||
| 	func (*U1) M() | ||||
|  | ||||
| 	//  | ||||
| 	type U2 struct { | ||||
| 		*U3 | ||||
| 	} | ||||
|  | ||||
| 	// U2.M should appear as method of U2 and as method of U3 only if ... | ||||
| 	func (*U2) M() | ||||
|  | ||||
| 	// U3.N should appear as method of U3 and as method of U2 only if ... | ||||
| 	func (U2) N() | ||||
|  | ||||
| 	//  | ||||
| 	type U3 struct { | ||||
| 		*U2 | ||||
| 	} | ||||
|  | ||||
| 	// U2.M should appear as method of U2 and as method of U3 only if ... | ||||
| 	func (U3) M() | ||||
|  | ||||
| 	// U3.N should appear as method of U3 and as method of U2 only if ... | ||||
| 	func (*U3) N() | ||||
|  | ||||
| 	//  | ||||
| 	type U4 struct { | ||||
| 		// contains filtered or unexported fields | ||||
| 	} | ||||
|  | ||||
| 	// U4.M should appear as method of U4.  | ||||
| 	func (*U4) M() | ||||
|  | ||||
| 	//  | ||||
| 	type V1 struct { | ||||
| 		*V2 | ||||
| 		*V5 | ||||
| 	} | ||||
|  | ||||
| 	// V6.M should appear as method of V1 and V5 if AllMethods is set.  | ||||
| 	func (V1) M() | ||||
|  | ||||
| 	//  | ||||
| 	type V2 struct { | ||||
| 		*V3 | ||||
| 	} | ||||
|  | ||||
| 	// V4.M should appear as method of V2 and V3 if AllMethods is set.  | ||||
| 	func (V2) M() | ||||
|  | ||||
| 	//  | ||||
| 	type V3 struct { | ||||
| 		*V4 | ||||
| 	} | ||||
|  | ||||
| 	// V4.M should appear as method of V2 and V3 if AllMethods is set.  | ||||
| 	func (V3) M() | ||||
|  | ||||
| 	//  | ||||
| 	type V4 struct { | ||||
| 		*V5 | ||||
| 	} | ||||
|  | ||||
| 	// V4.M should appear as method of V2 and V3 if AllMethods is set.  | ||||
| 	func (*V4) M() | ||||
|  | ||||
| 	//  | ||||
| 	type V5 struct { | ||||
| 		*V6 | ||||
| 	} | ||||
|  | ||||
| 	// V6.M should appear as method of V1 and V5 if AllMethods is set.  | ||||
| 	func (V5) M() | ||||
|  | ||||
| 	//  | ||||
| 	type V6 struct{} | ||||
|  | ||||
| 	// V6.M should appear as method of V1 and V5 if AllMethods is set.  | ||||
| 	func (*V6) M() | ||||
|  | ||||
							
								
								
									
										147
									
								
								third_party/golang/go/doc/testdata/e.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								third_party/golang/go/doc/testdata/e.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| // Copyright 2012 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. | ||||
|  | ||||
| // The package e is a go/doc test for embedded methods. | ||||
| package e | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Conflicting methods M must not show up. | ||||
|  | ||||
| type t1 struct{} | ||||
|  | ||||
| // t1.M should not appear as method in a Tx type. | ||||
| func (t1) M() {} | ||||
|  | ||||
| type t2 struct{} | ||||
|  | ||||
| // t2.M should not appear as method in a Tx type. | ||||
| func (t2) M() {} | ||||
|  | ||||
| // T1 has no embedded (level 1) M method due to conflict. | ||||
| type T1 struct { | ||||
| 	t1 | ||||
| 	t2 | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Higher-level method M wins over lower-level method M. | ||||
|  | ||||
| // T2 has only M as top-level method. | ||||
| type T2 struct { | ||||
| 	t1 | ||||
| } | ||||
|  | ||||
| // T2.M should appear as method of T2. | ||||
| func (T2) M() {} | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Higher-level method M wins over lower-level conflicting methods M. | ||||
|  | ||||
| type t1e struct { | ||||
| 	t1 | ||||
| } | ||||
|  | ||||
| type t2e struct { | ||||
| 	t2 | ||||
| } | ||||
|  | ||||
| // T3 has only M as top-level method. | ||||
| type T3 struct { | ||||
| 	t1e | ||||
| 	t2e | ||||
| } | ||||
|  | ||||
| // T3.M should appear as method of T3. | ||||
| func (T3) M() {} | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Don't show conflicting methods M embedded via an exported and non-exported | ||||
| // type. | ||||
|  | ||||
| // T1 has no embedded (level 1) M method due to conflict. | ||||
| type T4 struct { | ||||
| 	t2 | ||||
| 	T2 | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Don't show embedded methods of exported anonymous fields unless AllMethods | ||||
| // is set. | ||||
|  | ||||
| type T4 struct{} | ||||
|  | ||||
| // T4.M should appear as method of T5 only if AllMethods is set. | ||||
| func (*T4) M() {} | ||||
|  | ||||
| type T5 struct { | ||||
| 	T4 | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Recursive type declarations must not lead to endless recursion. | ||||
|  | ||||
| type U1 struct { | ||||
| 	*U1 | ||||
| } | ||||
|  | ||||
| // U1.M should appear as method of U1. | ||||
| func (*U1) M() {} | ||||
|  | ||||
| type U2 struct { | ||||
| 	*U3 | ||||
| } | ||||
|  | ||||
| // U2.M should appear as method of U2 and as method of U3 only if AllMethods is set. | ||||
| func (*U2) M() {} | ||||
|  | ||||
| type U3 struct { | ||||
| 	*U2 | ||||
| } | ||||
|  | ||||
| // U3.N should appear as method of U3 and as method of U2 only if AllMethods is set. | ||||
| func (*U3) N() {} | ||||
|  | ||||
| type U4 struct { | ||||
| 	*u5 | ||||
| } | ||||
|  | ||||
| // U4.M should appear as method of U4. | ||||
| func (*U4) M() {} | ||||
|  | ||||
| type u5 struct { | ||||
| 	*U4 | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // A higher-level embedded type (and its methods) wins over the same type (and | ||||
| // its methods) embedded at a lower level. | ||||
|  | ||||
| type V1 struct { | ||||
| 	*V2 | ||||
| 	*V5 | ||||
| } | ||||
|  | ||||
| type V2 struct { | ||||
| 	*V3 | ||||
| } | ||||
|  | ||||
| type V3 struct { | ||||
| 	*V4 | ||||
| } | ||||
|  | ||||
| type V4 struct { | ||||
| 	*V5 | ||||
| } | ||||
|  | ||||
| type V5 struct { | ||||
| 	*V6 | ||||
| } | ||||
|  | ||||
| type V6 struct{} | ||||
|  | ||||
| // V4.M should appear as method of V2 and V3 if AllMethods is set. | ||||
| func (*V4) M() {} | ||||
|  | ||||
| // V6.M should appear as method of V1 and V5 if AllMethods is set. | ||||
| func (*V6) M() {} | ||||
							
								
								
									
										30
									
								
								third_party/golang/go/doc/testdata/error1.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								third_party/golang/go/doc/testdata/error1.0.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| //  | ||||
| PACKAGE error1 | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/error1 | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/error1.go | ||||
|  | ||||
| TYPES | ||||
| 	//  | ||||
| 	type I0 interface { | ||||
| 		// When embedded, the predeclared error interface | ||||
| 		// must remain visible in interface types. | ||||
| 		error | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type S0 struct { | ||||
| 		// contains filtered or unexported fields | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type T0 struct { | ||||
| 		ExportedField interface { | ||||
| 			// error should be visible | ||||
| 			error | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										32
									
								
								third_party/golang/go/doc/testdata/error1.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								third_party/golang/go/doc/testdata/error1.1.golden
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| //  | ||||
| PACKAGE error1 | ||||
|  | ||||
| IMPORTPATH | ||||
| 	testdata/error1 | ||||
|  | ||||
| FILENAMES | ||||
| 	testdata/error1.go | ||||
|  | ||||
| TYPES | ||||
| 	//  | ||||
| 	type I0 interface { | ||||
| 		// When embedded, the predeclared error interface | ||||
| 		// must remain visible in interface types. | ||||
| 		error | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type S0 struct { | ||||
| 		// In struct types, an embedded error must only be visible | ||||
| 		// if AllDecls is set. | ||||
| 		error | ||||
| 	} | ||||
|  | ||||
| 	//  | ||||
| 	type T0 struct { | ||||
| 		ExportedField interface { | ||||
| 			// error should be visible | ||||
| 			error | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 k8s-merge-robot
					k8s-merge-robot