Merge pull request #28204 from thockin/cleanup-third_party
Automatic merge from submit-queue Cleanup third party (pt 2) Move forked-and-hacked golang code to the forked/ directory. Remove ast/build/parse code that is now in stdlib. Remove unused shell2junit
This commit is contained in:
commit
4da14c8a64
@ -18,14 +18,13 @@ package protobuf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/third_party/golang/go/ast"
|
||||
|
||||
"k8s.io/kubernetes/cmd/libs/go2idl/generator"
|
||||
"k8s.io/kubernetes/cmd/libs/go2idl/types"
|
||||
)
|
||||
|
@ -20,17 +20,17 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/parser"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/third_party/golang/go/ast"
|
||||
"k8s.io/kubernetes/third_party/golang/go/parser"
|
||||
"k8s.io/kubernetes/third_party/golang/go/printer"
|
||||
"k8s.io/kubernetes/third_party/golang/go/token"
|
||||
customreflect "k8s.io/kubernetes/third_party/golang/reflect"
|
||||
customreflect "k8s.io/kubernetes/third_party/forked/golang/reflect"
|
||||
)
|
||||
|
||||
func rewriteFile(name string, header []byte, rewriteFn func(*token.FileSet, *ast.File) error) error {
|
||||
|
@ -18,20 +18,19 @@ package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
tc "go/types"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"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"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/cmd/libs/go2idl/types"
|
||||
)
|
||||
|
||||
// Builder lets you add all the go files in all the packages that you care
|
||||
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||
package conversion
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/third_party/forked/reflect"
|
||||
"k8s.io/kubernetes/third_party/forked/golang/reflect"
|
||||
)
|
||||
|
||||
// The code for this type must be located in third_party, since it forks from
|
||||
|
@ -27,7 +27,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
hashutil "k8s.io/kubernetes/pkg/util/hash"
|
||||
"k8s.io/kubernetes/third_party/golang/expansion"
|
||||
"k8s.io/kubernetes/third_party/forked/golang/expansion"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
@ -97,7 +97,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates"
|
||||
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
|
||||
"k8s.io/kubernetes/third_party/golang/expansion"
|
||||
"k8s.io/kubernetes/third_party/forked/golang/expansion"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -32,7 +32,7 @@ import (
|
||||
apierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/util/httpstream"
|
||||
"k8s.io/kubernetes/third_party/golang/netutil"
|
||||
"k8s.io/kubernetes/third_party/forked/golang/netutil"
|
||||
)
|
||||
|
||||
// SpdyRoundTripper knows how to upgrade an HTTP request to one that supports
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/third_party/golang/template"
|
||||
"k8s.io/kubernetes/third_party/forked/golang/template"
|
||||
)
|
||||
|
||||
type JSONPath struct {
|
||||
|
@ -26,7 +26,7 @@ import (
|
||||
"github.com/golang/glog"
|
||||
|
||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||
"k8s.io/kubernetes/third_party/golang/netutil"
|
||||
"k8s.io/kubernetes/third_party/forked/golang/netutil"
|
||||
)
|
||||
|
||||
func DialURL(url *url.URL, transport http.RoundTripper) (net.Conn, error) {
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/json"
|
||||
forkedjson "k8s.io/kubernetes/third_party/forked/json"
|
||||
forkedjson "k8s.io/kubernetes/third_party/forked/golang/json"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/ghodss/yaml"
|
||||
|
27
third_party/forked/reflect/LICENSE
vendored
27
third_party/forked/reflect/LICENSE
vendored
@ -1,27 +0,0 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
third_party/golang/LICENSE
vendored
27
third_party/golang/LICENSE
vendored
@ -1,27 +0,0 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
15
third_party/golang/go/README.md
vendored
15
third_party/golang/go/README.md
vendored
@ -1,15 +0,0 @@
|
||||
# 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
999
third_party/golang/go/ast/ast.go
vendored
@ -1,999 +0,0 @@
|
||||
// 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
50
third_party/golang/go/ast/ast_test.go
vendored
@ -1,50 +0,0 @@
|
||||
// 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
332
third_party/golang/go/ast/commentmap.go
vendored
@ -1,332 +0,0 @@
|
||||
// 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
143
third_party/golang/go/ast/commentmap_test.go
vendored
@ -1,143 +0,0 @@
|
||||
// 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
210
third_party/golang/go/ast/example_test.go
vendored
@ -1,210 +0,0 @@
|
||||
// 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
465
third_party/golang/go/ast/filter.go
vendored
@ -1,465 +0,0 @@
|
||||
// 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
86
third_party/golang/go/ast/filter_test.go
vendored
@ -1,86 +0,0 @@
|
||||
// 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
196
third_party/golang/go/ast/import.go
vendored
@ -1,196 +0,0 @@
|
||||
// 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() }
|
252
third_party/golang/go/ast/print.go
vendored
252
third_party/golang/go/ast/print.go
vendored
@ -1,252 +0,0 @@
|
||||
// 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"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/kubernetes/third_party/golang/go/token"
|
||||
)
|
||||
|
||||
// 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
97
third_party/golang/go/ast/print_test.go
vendored
@ -1,97 +0,0 @@
|
||||
// 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
174
third_party/golang/go/ast/resolve.go
vendored
@ -1,174 +0,0 @@
|
||||
// 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()
|
||||
}
|
163
third_party/golang/go/ast/scope.go
vendored
163
third_party/golang/go/ast/scope.go
vendored
@ -1,163 +0,0 @@
|
||||
// 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
386
third_party/golang/go/ast/walk.go
vendored
@ -1,386 +0,0 @@
|
||||
// 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)
|
||||
}
|
1523
third_party/golang/go/build/build.go
vendored
1523
third_party/golang/go/build/build.go
vendored
File diff suppressed because it is too large
Load Diff
348
third_party/golang/go/build/build_test.go
vendored
348
third_party/golang/go/build/build_test.go
vendored
@ -1,348 +0,0 @@
|
||||
// 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 (
|
||||
"internal/testenv"
|
||||
"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) {
|
||||
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 != "go/build" {
|
||||
t.Fatalf("ImportPath=%q, want %q", p.ImportPath, "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) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellSafety(t *testing.T) {
|
||||
tests := []struct {
|
||||
input, srcdir, expected string
|
||||
result bool
|
||||
}{
|
||||
{"-I${SRCDIR}/../include", "/projects/src/issue 11868", "-I/projects/src/issue 11868/../include", true},
|
||||
{"-X${SRCDIR}/1,${SRCDIR}/2", "/projects/src/issue 11868", "-X/projects/src/issue 11868/1,/projects/src/issue 11868/2", true},
|
||||
{"-I/tmp -I/tmp", "/tmp2", "-I/tmp -I/tmp", false},
|
||||
{"-I/tmp", "/tmp/[0]", "-I/tmp", true},
|
||||
{"-I${SRCDIR}/dir", "/tmp/[0]", "-I/tmp/[0]/dir", false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
output, ok := expandSrcDir(test.input, test.srcdir)
|
||||
if ok != test.result {
|
||||
t.Errorf("Expected %t while %q expands to %q with SRCDIR=%q; got %t", test.result, test.input, output, test.srcdir, ok)
|
||||
}
|
||||
if output != test.expected {
|
||||
t.Errorf("Expected %q while %q expands with SRCDIR=%q; got %q", test.expected, test.input, test.srcdir, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportVendor(t *testing.T) {
|
||||
t.Skip("skipping; hpack has moved to internal for now; golang.org/issue/14047")
|
||||
testenv.MustHaveGoBuild(t) // really must just have source
|
||||
ctxt := Default
|
||||
ctxt.GOPATH = ""
|
||||
p, err := ctxt.Import("golang.org/x/net/http2/hpack", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot find vendored golang.org/x/net/http2/hpack from net/http directory: %v", err)
|
||||
}
|
||||
want := "vendor/golang.org/x/net/http2/hpack"
|
||||
if p.ImportPath != want {
|
||||
t.Fatalf("Import succeeded but found %q, want %q", p.ImportPath, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportVendorFailure(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t) // really must just have source
|
||||
ctxt := Default
|
||||
ctxt.GOPATH = ""
|
||||
p, err := ctxt.Import("x.com/y/z", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
|
||||
if err == nil {
|
||||
t.Fatalf("found made-up package x.com/y/z in %s", p.Dir)
|
||||
}
|
||||
|
||||
e := err.Error()
|
||||
if !strings.Contains(e, " (vendor tree)") {
|
||||
t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportVendorParentFailure(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t) // really must just have source
|
||||
ctxt := Default
|
||||
ctxt.GOPATH = ""
|
||||
// This import should fail because the vendor/golang.org/x/net/http2 directory has no source code.
|
||||
p, err := ctxt.Import("golang.org/x/net/http2", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
|
||||
if err == nil {
|
||||
t.Fatalf("found empty parent in %s", p.Dir)
|
||||
}
|
||||
if p != nil && p.Dir != "" {
|
||||
t.Fatalf("decided to use %s", p.Dir)
|
||||
}
|
||||
e := err.Error()
|
||||
if !strings.Contains(e, " (vendor tree)") {
|
||||
t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
|
||||
}
|
||||
}
|
525
third_party/golang/go/build/deps_test.go
vendored
525
third_party/golang/go/build/deps_test.go
vendored
@ -1,525 +0,0 @@
|
||||
// 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", "runtime/internal/atomic", "runtime/internal/sys"},
|
||||
"runtime/internal/sys": {},
|
||||
"runtime/internal/atomic": {"unsafe", "runtime/internal/sys"},
|
||||
"internal/race": {"runtime", "unsafe"},
|
||||
"sync": {"internal/race", "runtime", "sync/atomic", "unsafe"},
|
||||
"sync/atomic": {"unsafe"},
|
||||
"unsafe": {},
|
||||
|
||||
"L0": {
|
||||
"errors",
|
||||
"io",
|
||||
"runtime",
|
||||
"runtime/internal/atomic",
|
||||
"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", "internal/race", "internal/syscall/windows/sysdll", "unicode/utf16"},
|
||||
"internal/syscall/unix": {"L0", "syscall"},
|
||||
"internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll"},
|
||||
"internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "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"},
|
||||
|
||||
// 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/debug", "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", "compress/zlib"},
|
||||
"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.
|
||||
// If you add a dependency on CGO, you must add the package to
|
||||
// cgoPackages in cmd/dist/test.go.
|
||||
"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/MSan uses cgo.
|
||||
"runtime/race": {"C"},
|
||||
"runtime/msan": {"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 L0+basic os.
|
||||
"net": {"L0", "CGO", "math/rand", "os", "sort", "syscall", "time", "internal/syscall/windows", "internal/singleflight", "internal/race"},
|
||||
|
||||
// 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"},
|
||||
|
||||
// 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", "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",
|
||||
"internal/golang.org/x/net/http2/hpack",
|
||||
},
|
||||
"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/internal"},
|
||||
"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) {
|
||||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
141
third_party/golang/go/build/doc.go
vendored
141
third_party/golang/go/build/doc.go
vendored
@ -1,141 +0,0 @@
|
||||
// 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
|
||||
// - "go1.6", from Go version 1.6 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
246
third_party/golang/go/build/read.go
vendored
@ -1,246 +0,0 @@
|
||||
// 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
226
third_party/golang/go/build/read_test.go
vendored
@ -1,226 +0,0 @@
|
||||
// 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
8
third_party/golang/go/build/syslist.go
vendored
@ -1,8 +0,0 @@
|
||||
// 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
62
third_party/golang/go/build/syslist_test.go
vendored
@ -1,62 +0,0 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
// Test data - not compiled.
|
||||
|
||||
package main
|
||||
|
||||
func main() {}
|
@ -1,5 +0,0 @@
|
||||
// Test data - not compiled.
|
||||
|
||||
package test_package
|
||||
|
||||
func init() {}
|
@ -1,5 +0,0 @@
|
||||
// Test data - not compiled.
|
||||
|
||||
package file
|
||||
|
||||
func F() {}
|
@ -1,11 +0,0 @@
|
||||
// Test data - not compiled.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"./file"
|
||||
)
|
||||
|
||||
func main() {
|
||||
file.F()
|
||||
}
|
24
third_party/golang/go/constant/go13.go
vendored
24
third_party/golang/go/constant/go13.go
vendored
@ -1,24 +0,0 @@
|
||||
// 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
13
third_party/golang/go/constant/go14.go
vendored
@ -1,13 +0,0 @@
|
||||
// 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
925
third_party/golang/go/constant/value.go
vendored
@ -1,925 +0,0 @@
|
||||
// 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
375
third_party/golang/go/constant/value_test.go
vendored
@ -1,375 +0,0 @@
|
||||
// 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
7
third_party/golang/go/doc/Makefile
vendored
@ -1,7 +0,0 @@
|
||||
# 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
480
third_party/golang/go/doc/comment.go
vendored
@ -1,480 +0,0 @@
|
||||
// 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
207
third_party/golang/go/doc/comment_test.go
vendored
@ -1,207 +0,0 @@
|
||||
// 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
112
third_party/golang/go/doc/doc.go
vendored
@ -1,112 +0,0 @@
|
||||
// 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),
|
||||
}
|
||||
}
|
147
third_party/golang/go/doc/doc_test.go
vendored
147
third_party/golang/go/doc/doc_test.go
vendored
@ -1,147 +0,0 @@
|
||||
// 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"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"k8s.io/kubernetes/third_party/golang/go/parser"
|
||||
"k8s.io/kubernetes/third_party/golang/go/printer"
|
||||
"k8s.io/kubernetes/third_party/golang/go/token"
|
||||
)
|
||||
|
||||
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
355
third_party/golang/go/doc/example.go
vendored
@ -1,355 +0,0 @@
|
||||
// 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
191
third_party/golang/go/doc/example_test.go
vendored
@ -1,191 +0,0 @@
|
||||
// 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
252
third_party/golang/go/doc/exports.go
vendored
@ -1,252 +0,0 @@
|
||||
// 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
105
third_party/golang/go/doc/filter.go
vendored
@ -1,105 +0,0 @@
|
||||
// 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
114
third_party/golang/go/doc/headscan.go
vendored
@ -1,114 +0,0 @@
|
||||
// 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
853
third_party/golang/go/doc/reader.go
vendored
@ -1,853 +0,0 @@
|
||||
// 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
82
third_party/golang/go/doc/synopsis.go
vendored
@ -1,82 +0,0 @@
|
||||
// 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
51
third_party/golang/go/doc/synopsis_test.go
vendored
@ -1,51 +0,0 @@
|
||||
// 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
52
third_party/golang/go/doc/testdata/a.0.golden
vendored
@ -1,52 +0,0 @@
|
||||
// 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
52
third_party/golang/go/doc/testdata/a.1.golden
vendored
@ -1,52 +0,0 @@
|
||||
// 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
52
third_party/golang/go/doc/testdata/a.2.golden
vendored
@ -1,52 +0,0 @@
|
||||
// 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
40
third_party/golang/go/doc/testdata/a0.go
vendored
@ -1,40 +0,0 @@
|
||||
// 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
12
third_party/golang/go/doc/testdata/a1.go
vendored
@ -1,12 +0,0 @@
|
||||
// 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
71
third_party/golang/go/doc/testdata/b.0.golden
vendored
@ -1,71 +0,0 @@
|
||||
//
|
||||
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
83
third_party/golang/go/doc/testdata/b.1.golden
vendored
@ -1,83 +0,0 @@
|
||||
//
|
||||
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
71
third_party/golang/go/doc/testdata/b.2.golden
vendored
@ -1,71 +0,0 @@
|
||||
//
|
||||
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
58
third_party/golang/go/doc/testdata/b.go
vendored
@ -1,58 +0,0 @@
|
||||
// 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
293
third_party/golang/go/doc/testdata/benchmark.go
vendored
@ -1,293 +0,0 @@
|
||||
// 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()
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
// 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
|
||||
)
|
||||
|
@ -1,75 +0,0 @@
|
||||
// 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
|
||||
)
|
||||
|
@ -1,55 +0,0 @@
|
||||
// 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
67
third_party/golang/go/doc/testdata/blank.go
vendored
@ -1,67 +0,0 @@
|
||||
// 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)
|
@ -1,20 +0,0 @@
|
||||
//
|
||||
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.
|
||||
|
@ -1,20 +0,0 @@
|
||||
//
|
||||
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.
|
||||
|
@ -1,20 +0,0 @@
|
||||
//
|
||||
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.
|
||||
|
@ -1,5 +0,0 @@
|
||||
package bugpara
|
||||
|
||||
// BUG(rsc): Sometimes bugs have multiple paragraphs.
|
||||
//
|
||||
// Like this one.
|
48
third_party/golang/go/doc/testdata/c.0.golden
vendored
48
third_party/golang/go/doc/testdata/c.0.golden
vendored
@ -1,48 +0,0 @@
|
||||
//
|
||||
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
48
third_party/golang/go/doc/testdata/c.1.golden
vendored
@ -1,48 +0,0 @@
|
||||
//
|
||||
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
48
third_party/golang/go/doc/testdata/c.2.golden
vendored
@ -1,48 +0,0 @@
|
||||
//
|
||||
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
62
third_party/golang/go/doc/testdata/c.go
vendored
@ -1,62 +0,0 @@
|
||||
// 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
104
third_party/golang/go/doc/testdata/d.0.golden
vendored
@ -1,104 +0,0 @@
|
||||
//
|
||||
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
104
third_party/golang/go/doc/testdata/d.1.golden
vendored
@ -1,104 +0,0 @@
|
||||
//
|
||||
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
104
third_party/golang/go/doc/testdata/d.2.golden
vendored
@ -1,104 +0,0 @@
|
||||
//
|
||||
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
57
third_party/golang/go/doc/testdata/d1.go
vendored
@ -1,57 +0,0 @@
|
||||
// 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
45
third_party/golang/go/doc/testdata/d2.go
vendored
@ -1,45 +0,0 @@
|
||||
// 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
109
third_party/golang/go/doc/testdata/e.0.golden
vendored
@ -1,109 +0,0 @@
|
||||
// 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
144
third_party/golang/go/doc/testdata/e.1.golden
vendored
@ -1,144 +0,0 @@
|
||||
// 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
130
third_party/golang/go/doc/testdata/e.2.golden
vendored
@ -1,130 +0,0 @@
|
||||
// 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
147
third_party/golang/go/doc/testdata/e.go
vendored
@ -1,147 +0,0 @@
|
||||
// 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() {}
|
@ -1,30 +0,0 @@
|
||||
//
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
//
|
||||
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
Loading…
Reference in New Issue
Block a user