Remove no-longer-needed forked go/ast code

This commit is contained in:
Tim Hockin 2016-06-28 22:33:51 -07:00
parent 2950373959
commit b0a4b22e61
171 changed files with 11 additions and 45329 deletions

View File

@ -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"
)

View File

@ -20,17 +20,17 @@ import (
"bytes"
"errors"
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/printer"
"go/token"
"io/ioutil"
"os"
"reflect"
"strings"
customreflect "k8s.io/kubernetes/third_party/forked/reflect"
"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"
)
func rewriteFile(name string, header []byte, rewriteFn func(*token.FileSet, *ast.File) error) error {

View File

@ -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

View File

@ -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.

View File

@ -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 }

View File

@ -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)
}
}
}

View File

@ -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()
}

View File

@ -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.

View File

@ -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")
}

View File

@ -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}
}

View File

@ -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)
}
}

View File

@ -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() }

View File

@ -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)
}
}

View File

@ -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)
}
}
}

View File

@ -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()
}

View File

@ -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] }

View File

@ -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)
}

File diff suppressed because it is too large Load Diff

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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) })
}

View File

@ -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 "

View File

@ -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)
}
}
}

View File

@ -1,5 +0,0 @@
// Test data - not compiled.
package main
func main() {}

View File

@ -1,5 +0,0 @@
// Test data - not compiled.
package test_package
func init() {}

View File

@ -1,5 +0,0 @@
// Test data - not compiled.
package file
func F() {}

View File

@ -1,11 +0,0 @@
// Test data - not compiled.
package main
import (
"./file"
)
func main() {
file.F()
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -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))
}

View File

@ -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)
}
}
}
}

View File

@ -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

View File

@ -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("&ldquo;")
rdquo = []byte("&rdquo;")
)
// Escape comment text for HTML. If nice is set,
// also turn `` into &ldquo; and '' into &rdquo;.
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 &ldquo;
// and '' into &rdquo;).
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
}

View File

@ -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)
}
}
}

View File

@ -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),
}
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}
}
}

View File

@ -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]
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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,
}

View File

@ -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",
}

View File

@ -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)
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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 {}

View File

@ -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()
}

View File

@ -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
)

View File

@ -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
)

View File

@ -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
)

View File

@ -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)

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -1,5 +0,0 @@
package bugpara
// BUG(rsc): Sometimes bugs have multiple paragraphs.
//
// Like this one.

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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{}

View File

@ -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{}

View File

@ -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{}

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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()

View File

@ -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
}

View File

@ -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()

View File

@ -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() {}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -1,24 +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 error1
type I0 interface {
// When embedded, the predeclared error interface
// must remain visible in interface types.
error
}
type T0 struct {
ExportedField interface {
// error should be visible
error
}
}
type S0 struct {
// In struct types, an embedded error must only be visible
// if AllDecls is set.
error
}

View File

@ -1,27 +0,0 @@
//
PACKAGE error2
IMPORTPATH
testdata/error2
FILENAMES
testdata/error2.go
TYPES
//
type I0 interface {
// contains filtered or unexported methods
}
//
type S0 struct {
// contains filtered or unexported fields
}
//
type T0 struct {
ExportedField interface {
// contains filtered or unexported methods
}
}

View File

@ -1,37 +0,0 @@
//
PACKAGE error2
IMPORTPATH
testdata/error2
FILENAMES
testdata/error2.go
TYPES
//
type I0 interface {
// When embedded, the locally-declared error interface
// is only visible if all declarations are shown.
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 not be visible
error
}
}
// This error declaration shadows the predeclared error type.
type error interface {
Error() string
}

View File

@ -1,27 +0,0 @@
//
PACKAGE error2
IMPORTPATH
testdata/error2
FILENAMES
testdata/error2.go
TYPES
//
type I0 interface {
// contains filtered or unexported methods
}
//
type S0 struct {
// contains filtered or unexported fields
}
//
type T0 struct {
ExportedField interface {
// contains filtered or unexported methods
}
}

View File

@ -1,29 +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 error2
type I0 interface {
// When embedded, the locally-declared error interface
// is only visible if all declarations are shown.
error
}
type T0 struct {
ExportedField interface {
// error should not be visible
error
}
}
type S0 struct {
// In struct types, an embedded error must only be visible
// if AllDecls is set.
error
}
// This error declaration shadows the predeclared error type.
type error interface {
Error() string
}

View File

@ -1,81 +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 (
"bytes"
"fmt"
"io"
"os"
"strings"
"time"
)
type InternalExample struct {
Name string
F func()
Output string
}
func RunExamples(examples []InternalExample) (ok bool) {
ok = true
var eg InternalExample
stdout, stderr := os.Stdout, os.Stderr
defer func() {
os.Stdout, os.Stderr = stdout, stderr
if e := recover(); e != nil {
fmt.Printf("--- FAIL: %s\npanic: %v\n", eg.Name, e)
os.Exit(1)
}
}()
for _, eg = range examples {
if *chatty {
fmt.Printf("=== RUN: %s\n", eg.Name)
}
// capture stdout and stderr
r, w, err := os.Pipe()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
os.Stdout, os.Stderr = w, w
outC := make(chan string)
go func() {
buf := new(bytes.Buffer)
_, err := io.Copy(buf, r)
if err != nil {
fmt.Fprintf(stderr, "testing: copying pipe: %v\n", err)
os.Exit(1)
}
outC <- buf.String()
}()
// run example
t0 := time.Now()
eg.F()
dt := time.Now().Sub(t0)
// close pipe, restore stdout/stderr, get output
w.Close()
os.Stdout, os.Stderr = stdout, stderr
out := <-outC
// report any errors
tstr := fmt.Sprintf("(%.2f seconds)", dt.Seconds())
if g, e := strings.TrimSpace(out), strings.TrimSpace(eg.Output); g != e {
fmt.Printf("--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
eg.Name, tstr, g, e)
ok = false
} else if *chatty {
fmt.Printf("--- PASS: %s %s\n", eg.Name, tstr)
}
}
return
}

View File

@ -1,13 +0,0 @@
// The package f is a go/doc test for functions and factory ...
PACKAGE f
IMPORTPATH
testdata/f
FILENAMES
testdata/f.go
FUNCTIONS
// Exported must always be visible. Was issue 2824.
func Exported() private

View File

@ -1,16 +0,0 @@
// The package f is a go/doc test for functions and factory ...
PACKAGE f
IMPORTPATH
testdata/f
FILENAMES
testdata/f.go
TYPES
//
type private struct{}
// Exported must always be visible. Was issue 2824.
func Exported() private

View File

@ -1,13 +0,0 @@
// The package f is a go/doc test for functions and factory ...
PACKAGE f
IMPORTPATH
testdata/f
FILENAMES
testdata/f.go
FUNCTIONS
// Exported must always be visible. Was issue 2824.
func Exported() private

View File

@ -1,14 +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 f is a go/doc test for functions and factory methods.
package f
// ----------------------------------------------------------------------------
// Factory functions for non-exported types must not get lost.
type private struct{}
// Exported must always be visible. Was issue 2824.
func Exported() private {}

View File

@ -1,68 +0,0 @@
{{synopsis .Doc}}
PACKAGE {{.Name}}
IMPORTPATH
{{.ImportPath}}
{{with .Imports}}IMPORTS
{{range .}} {{.}}
{{end}}
{{end}}{{/*
*/}}FILENAMES
{{range .Filenames}} {{.}}
{{end}}{{/*
*/}}{{with .Consts}}
CONSTANTS
{{range .}} {{synopsis .Doc}}
{{node .Decl $.FSet}}
{{end}}{{end}}{{/*
*/}}{{with .Vars}}
VARIABLES
{{range .}} {{synopsis .Doc}}
{{node .Decl $.FSet}}
{{end}}{{end}}{{/*
*/}}{{with .Funcs}}
FUNCTIONS
{{range .}} {{synopsis .Doc}}
{{node .Decl $.FSet}}
{{end}}{{end}}{{/*
*/}}{{with .Types}}
TYPES
{{range .}} {{synopsis .Doc}}
{{node .Decl $.FSet}}
{{range .Consts}} {{synopsis .Doc}}
{{node .Decl $.FSet}}
{{end}}{{/*
*/}}{{range .Vars}} {{synopsis .Doc}}
{{node .Decl $.FSet}}
{{end}}{{/*
*/}}{{range .Funcs}} {{synopsis .Doc}}
{{node .Decl $.FSet}}
{{end}}{{/*
*/}}{{range .Methods}} {{synopsis .Doc}}
{{node .Decl $.FSet}}
{{end}}{{end}}{{end}}{{/*
*/}}{{with .Bugs}}
BUGS .Bugs is now deprecated, please use .Notes instead
{{range .}}{{indent "\t" .}}
{{end}}{{end}}{{with .Notes}}{{range $marker, $content := .}}
{{$marker}}S
{{range $content}}{{$marker}}({{.UID}}){{indent "\t" .Body}}
{{end}}{{end}}{{end}}

View File

@ -1,156 +0,0 @@
// Package testing provides support for automated testing of Go ...
PACKAGE testing
IMPORTPATH
testdata/testing
IMPORTS
bytes
flag
fmt
io
os
runtime
runtime/pprof
strconv
strings
time
FILENAMES
testdata/benchmark.go
testdata/example.go
testdata/testing.go
FUNCTIONS
// An internal function but exported because it is cross-package; ...
func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample)
// An internal function but exported because it is cross-package; ...
func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark)
//
func RunExamples(examples []InternalExample) (ok bool)
//
func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool)
// Short reports whether the -test.short flag is set.
func Short() bool
TYPES
// B is a type passed to Benchmark functions to manage benchmark ...
type B struct {
N int
// contains filtered or unexported fields
}
// Error is equivalent to Log() followed by Fail().
func (c *B) Error(args ...interface{})
// Errorf is equivalent to Logf() followed by Fail().
func (c *B) Errorf(format string, args ...interface{})
// Fail marks the function as having failed but continues ...
func (c *B) Fail()
// FailNow marks the function as having failed and stops its ...
func (c *B) FailNow()
// Failed reports whether the function has failed.
func (c *B) Failed() bool
// Fatal is equivalent to Log() followed by FailNow().
func (c *B) Fatal(args ...interface{})
// Fatalf is equivalent to Logf() followed by FailNow().
func (c *B) Fatalf(format string, args ...interface{})
// Log formats its arguments using default formatting, analogous ...
func (c *B) Log(args ...interface{})
// Logf formats its arguments according to the format, analogous ...
func (c *B) Logf(format string, args ...interface{})
// ResetTimer sets the elapsed benchmark time to zero. It does not ...
func (b *B) ResetTimer()
// SetBytes records the number of bytes processed in a single ...
func (b *B) SetBytes(n int64)
// StartTimer starts timing a test. This function is called ...
func (b *B) StartTimer()
// StopTimer stops timing a test. This can be used to pause the ...
func (b *B) StopTimer()
// 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.
}
// Benchmark benchmarks a single function. Useful for creating ...
func Benchmark(f func(b *B)) BenchmarkResult
//
func (r BenchmarkResult) NsPerOp() int64
//
func (r BenchmarkResult) String() string
// An internal type but exported because it is cross-package; part ...
type InternalBenchmark struct {
Name string
F func(b *B)
}
//
type InternalExample struct {
Name string
F func()
Output string
}
// An internal type but exported because it is cross-package; part ...
type InternalTest struct {
Name string
F func(*T)
}
// T is a type passed to Test functions to manage test state and ...
type T struct {
// contains filtered or unexported fields
}
// Error is equivalent to Log() followed by Fail().
func (c *T) Error(args ...interface{})
// Errorf is equivalent to Logf() followed by Fail().
func (c *T) Errorf(format string, args ...interface{})
// Fail marks the function as having failed but continues ...
func (c *T) Fail()
// FailNow marks the function as having failed and stops its ...
func (c *T) FailNow()
// Failed reports whether the function has failed.
func (c *T) Failed() bool
// Fatal is equivalent to Log() followed by FailNow().
func (c *T) Fatal(args ...interface{})
// Fatalf is equivalent to Logf() followed by FailNow().
func (c *T) Fatalf(format string, args ...interface{})
// Log formats its arguments using default formatting, analogous ...
func (c *T) Log(args ...interface{})
// Logf formats its arguments according to the format, analogous ...
func (c *T) Logf(format string, args ...interface{})
// Parallel signals that this test is to be run in parallel with ...
func (t *T) Parallel()

View File

@ -1,298 +0,0 @@
// Package testing provides support for automated testing of Go ...
PACKAGE testing
IMPORTPATH
testdata/testing
IMPORTS
bytes
flag
fmt
io
os
runtime
runtime/pprof
strconv
strings
time
FILENAMES
testdata/benchmark.go
testdata/example.go
testdata/testing.go
VARIABLES
//
var (
// The short flag requests that tests run more quickly, but its functionality
// is provided by test writers themselves. The testing package is just its
// home. The all.bash installation script sets it to make installation more
// efficient, but by default the flag is off so a plain "go test" will do a
// full test of the package.
short = flag.Bool("test.short", false, "run smaller test suite to save time")
// Report as tests are run; default is silent for success.
chatty = flag.Bool("test.v", false, "verbose: print additional output")
match = flag.String("test.run", "", "regular expression to select tests to run")
memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate")
cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
timeout = flag.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests")
cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
cpuList []int
)
//
var benchTime = flag.Duration("test.benchtime", 1*time.Second, "approximate run time for each benchmark")
//
var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run")
//
var timer *time.Timer
FUNCTIONS
// An internal function but exported because it is cross-package; ...
func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample)
// An internal function but exported because it is cross-package; ...
func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark)
//
func RunExamples(examples []InternalExample) (ok bool)
//
func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool)
// Short reports whether the -test.short flag is set.
func Short() bool
// after runs after all testing.
func after()
// alarm is called if the timeout expires.
func alarm()
// before runs before all testing.
func before()
// decorate inserts the final newline if needed and indentation ...
func decorate(s string, addFileLine bool) string
//
func max(x, y int) int
//
func min(x, y int) int
//
func parseCpuList()
// roundDown10 rounds a number down to the nearest power of 10.
func roundDown10(n int) int
// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
func roundUp(n int) int
// startAlarm starts an alarm if requested.
func startAlarm()
// stopAlarm turns off the alarm.
func stopAlarm()
//
func tRunner(t *T, test *InternalTest)
TYPES
// B is a type passed to Benchmark functions to manage benchmark ...
type B struct {
common
N int
benchmark InternalBenchmark
bytes int64
timerOn bool
result BenchmarkResult
}
// Error is equivalent to Log() followed by Fail().
func (c *B) Error(args ...interface{})
// Errorf is equivalent to Logf() followed by Fail().
func (c *B) Errorf(format string, args ...interface{})
// Fail marks the function as having failed but continues ...
func (c *B) Fail()
// FailNow marks the function as having failed and stops its ...
func (c *B) FailNow()
// Failed reports whether the function has failed.
func (c *B) Failed() bool
// Fatal is equivalent to Log() followed by FailNow().
func (c *B) Fatal(args ...interface{})
// Fatalf is equivalent to Logf() followed by FailNow().
func (c *B) Fatalf(format string, args ...interface{})
// Log formats its arguments using default formatting, analogous ...
func (c *B) Log(args ...interface{})
// Logf formats its arguments according to the format, analogous ...
func (c *B) Logf(format string, args ...interface{})
// ResetTimer sets the elapsed benchmark time to zero. It does not ...
func (b *B) ResetTimer()
// SetBytes records the number of bytes processed in a single ...
func (b *B) SetBytes(n int64)
// StartTimer starts timing a test. This function is called ...
func (b *B) StartTimer()
// StopTimer stops timing a test. This can be used to pause the ...
func (b *B) StopTimer()
// launch launches the benchmark function. It gradually increases ...
func (b *B) launch()
// log generates the output. It's always at the same stack depth.
func (c *B) log(s string)
//
func (b *B) nsPerOp() int64
// run times the benchmark function in a separate goroutine.
func (b *B) run() BenchmarkResult
// runN runs a single benchmark for the specified number of ...
func (b *B) runN(n int)
// trimOutput shortens the output from a benchmark, which can be ...
func (b *B) trimOutput()
// 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.
}
// Benchmark benchmarks a single function. Useful for creating ...
func Benchmark(f func(b *B)) BenchmarkResult
//
func (r BenchmarkResult) NsPerOp() int64
//
func (r BenchmarkResult) String() string
//
func (r BenchmarkResult) mbPerSec() float64
// An internal type but exported because it is cross-package; part ...
type InternalBenchmark struct {
Name string
F func(b *B)
}
//
type InternalExample struct {
Name string
F func()
Output string
}
// An internal type but exported because it is cross-package; part ...
type InternalTest struct {
Name string
F func(*T)
}
// T is a type passed to Test functions to manage test state and ...
type T struct {
common
name string // Name of test.
startParallel chan bool // Parallel tests will wait on this.
}
// Error is equivalent to Log() followed by Fail().
func (c *T) Error(args ...interface{})
// Errorf is equivalent to Logf() followed by Fail().
func (c *T) Errorf(format string, args ...interface{})
// Fail marks the function as having failed but continues ...
func (c *T) Fail()
// FailNow marks the function as having failed and stops its ...
func (c *T) FailNow()
// Failed reports whether the function has failed.
func (c *T) Failed() bool
// Fatal is equivalent to Log() followed by FailNow().
func (c *T) Fatal(args ...interface{})
// Fatalf is equivalent to Logf() followed by FailNow().
func (c *T) Fatalf(format string, args ...interface{})
// Log formats its arguments using default formatting, analogous ...
func (c *T) Log(args ...interface{})
// Logf formats its arguments according to the format, analogous ...
func (c *T) Logf(format string, args ...interface{})
// Parallel signals that this test is to be run in parallel with ...
func (t *T) Parallel()
// log generates the output. It's always at the same stack depth.
func (c *T) log(s string)
//
func (t *T) report()
// common holds the elements common between T and B and captures ...
type common struct {
output []byte // Output generated by test or benchmark.
failed bool // Test or benchmark has failed.
start time.Time // Time test or benchmark started
duration time.Duration
self interface{} // To be sent on signal channel when done.
signal chan interface{} // Output for serial tests.
}
// Error is equivalent to Log() followed by Fail().
func (c *common) Error(args ...interface{})
// Errorf is equivalent to Logf() followed by Fail().
func (c *common) Errorf(format string, args ...interface{})
// Fail marks the function as having failed but continues ...
func (c *common) Fail()
// FailNow marks the function as having failed and stops its ...
func (c *common) FailNow()
// Failed reports whether the function has failed.
func (c *common) Failed() bool
// Fatal is equivalent to Log() followed by FailNow().
func (c *common) Fatal(args ...interface{})
// Fatalf is equivalent to Logf() followed by FailNow().
func (c *common) Fatalf(format string, args ...interface{})
// Log formats its arguments using default formatting, analogous ...
func (c *common) Log(args ...interface{})
// Logf formats its arguments according to the format, analogous ...
func (c *common) Logf(format string, args ...interface{})
// log generates the output. It's always at the same stack depth.
func (c *common) log(s string)

View File

@ -1,156 +0,0 @@
// Package testing provides support for automated testing of Go ...
PACKAGE testing
IMPORTPATH
testdata/testing
IMPORTS
bytes
flag
fmt
io
os
runtime
runtime/pprof
strconv
strings
time
FILENAMES
testdata/benchmark.go
testdata/example.go
testdata/testing.go
FUNCTIONS
// An internal function but exported because it is cross-package; ...
func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample)
// An internal function but exported because it is cross-package; ...
func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark)
//
func RunExamples(examples []InternalExample) (ok bool)
//
func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool)
// Short reports whether the -test.short flag is set.
func Short() bool
TYPES
// B is a type passed to Benchmark functions to manage benchmark ...
type B struct {
N int
// contains filtered or unexported fields
}
// Error is equivalent to Log() followed by Fail().
func (c *B) Error(args ...interface{})
// Errorf is equivalent to Logf() followed by Fail().
func (c *B) Errorf(format string, args ...interface{})
// Fail marks the function as having failed but continues ...
func (c *B) Fail()
// FailNow marks the function as having failed and stops its ...
func (c *B) FailNow()
// Failed reports whether the function has failed.
func (c *B) Failed() bool
// Fatal is equivalent to Log() followed by FailNow().
func (c *B) Fatal(args ...interface{})
// Fatalf is equivalent to Logf() followed by FailNow().
func (c *B) Fatalf(format string, args ...interface{})
// Log formats its arguments using default formatting, analogous ...
func (c *B) Log(args ...interface{})
// Logf formats its arguments according to the format, analogous ...
func (c *B) Logf(format string, args ...interface{})
// ResetTimer sets the elapsed benchmark time to zero. It does not ...
func (b *B) ResetTimer()
// SetBytes records the number of bytes processed in a single ...
func (b *B) SetBytes(n int64)
// StartTimer starts timing a test. This function is called ...
func (b *B) StartTimer()
// StopTimer stops timing a test. This can be used to pause the ...
func (b *B) StopTimer()
// 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.
}
// Benchmark benchmarks a single function. Useful for creating ...
func Benchmark(f func(b *B)) BenchmarkResult
//
func (r BenchmarkResult) NsPerOp() int64
//
func (r BenchmarkResult) String() string
// An internal type but exported because it is cross-package; part ...
type InternalBenchmark struct {
Name string
F func(b *B)
}
//
type InternalExample struct {
Name string
F func()
Output string
}
// An internal type but exported because it is cross-package; part ...
type InternalTest struct {
Name string
F func(*T)
}
// T is a type passed to Test functions to manage test state and ...
type T struct {
// contains filtered or unexported fields
}
// Error is equivalent to Log() followed by Fail().
func (c *T) Error(args ...interface{})
// Errorf is equivalent to Logf() followed by Fail().
func (c *T) Errorf(format string, args ...interface{})
// Fail marks the function as having failed but continues ...
func (c *T) Fail()
// FailNow marks the function as having failed and stops its ...
func (c *T) FailNow()
// Failed reports whether the function has failed.
func (c *T) Failed() bool
// Fatal is equivalent to Log() followed by FailNow().
func (c *T) Fatal(args ...interface{})
// Fatalf is equivalent to Logf() followed by FailNow().
func (c *T) Fatalf(format string, args ...interface{})
// Log formats its arguments using default formatting, analogous ...
func (c *T) Log(args ...interface{})
// Logf formats its arguments according to the format, analogous ...
func (c *T) Logf(format string, args ...interface{})
// Parallel signals that this test is to be run in parallel with ...
func (t *T) Parallel()

View File

@ -1,404 +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 provides support for automated testing of Go packages.
// It is intended to be used in concert with the ``go test'' utility, which automates
// execution of any function of the form
// func TestXxx(*testing.T)
// where Xxx can be any alphanumeric string (but the first letter must not be in
// [a-z]) and serves to identify the test routine.
// These TestXxx routines should be declared within the package they are testing.
//
// Functions of the form
// func BenchmarkXxx(*testing.B)
// are considered benchmarks, and are executed by go test when the -test.bench
// flag is provided.
//
// A sample benchmark function looks like this:
// func BenchmarkHello(b *testing.B) {
// for i := 0; i < b.N; i++ {
// fmt.Sprintf("hello")
// }
// }
// The benchmark package will vary b.N until the benchmark function lasts
// long enough to be timed reliably. The output
// testing.BenchmarkHello 10000000 282 ns/op
// means that the loop ran 10000000 times at a speed of 282 ns per loop.
//
// If a benchmark needs some expensive setup before running, the timer
// may be stopped:
// func BenchmarkBigLen(b *testing.B) {
// b.StopTimer()
// big := NewBig()
// b.StartTimer()
// for i := 0; i < b.N; i++ {
// big.Len()
// }
// }
package testing
import (
"flag"
"fmt"
"os"
"runtime"
"runtime/pprof"
"strconv"
"strings"
"time"
)
var (
// The short flag requests that tests run more quickly, but its functionality
// is provided by test writers themselves. The testing package is just its
// home. The all.bash installation script sets it to make installation more
// efficient, but by default the flag is off so a plain "go test" will do a
// full test of the package.
short = flag.Bool("test.short", false, "run smaller test suite to save time")
// Report as tests are run; default is silent for success.
chatty = flag.Bool("test.v", false, "verbose: print additional output")
match = flag.String("test.run", "", "regular expression to select tests to run")
memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate")
cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
timeout = flag.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests")
cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
cpuList []int
)
// common holds the elements common between T and B and
// captures common methods such as Errorf.
type common struct {
output []byte // Output generated by test or benchmark.
failed bool // Test or benchmark has failed.
start time.Time // Time test or benchmark started
duration time.Duration
self interface{} // To be sent on signal channel when done.
signal chan interface{} // Output for serial tests.
}
// Short reports whether the -test.short flag is set.
func Short() bool {
return *short
}
// decorate inserts the final newline if needed and indentation tabs for formatting.
// If addFileLine is true, it also prefixes the string with the file and line of the call site.
func decorate(s string, addFileLine bool) string {
if addFileLine {
_, file, line, ok := runtime.Caller(3) // decorate + log + public function.
if ok {
// Truncate file name at last file name separator.
if index := strings.LastIndex(file, "/"); index >= 0 {
file = file[index+1:]
} else if index = strings.LastIndex(file, "\\"); index >= 0 {
file = file[index+1:]
}
} else {
file = "???"
line = 1
}
s = fmt.Sprintf("%s:%d: %s", file, line, s)
}
s = "\t" + s // Every line is indented at least one tab.
n := len(s)
if n > 0 && s[n-1] != '\n' {
s += "\n"
n++
}
for i := 0; i < n-1; i++ { // -1 to avoid final newline
if s[i] == '\n' {
// Second and subsequent lines are indented an extra tab.
return s[0:i+1] + "\t" + decorate(s[i+1:n], false)
}
}
return s
}
// T is a type passed to Test functions to manage test state and support formatted test logs.
// Logs are accumulated during execution and dumped to standard error when done.
type T struct {
common
name string // Name of test.
startParallel chan bool // Parallel tests will wait on this.
}
// Fail marks the function as having failed but continues execution.
func (c *common) Fail() { c.failed = true }
// Failed reports whether the function has failed.
func (c *common) Failed() bool { return c.failed }
// FailNow marks the function as having failed and stops its execution.
// Execution will continue at the next Test.
func (c *common) FailNow() {
c.Fail()
// Calling runtime.Goexit will exit the goroutine, which
// will run the deferred functions in this goroutine,
// which will eventually run the deferred lines in tRunner,
// which will signal to the test loop that this test is done.
//
// A previous version of this code said:
//
// c.duration = ...
// c.signal <- c.self
// runtime.Goexit()
//
// This previous version duplicated code (those lines are in
// tRunner no matter what), but worse the goroutine teardown
// implicit in runtime.Goexit was not guaranteed to complete
// before the test exited. If a test deferred an important cleanup
// function (like removing temporary files), there was no guarantee
// it would run on a test failure. Because we send on c.signal during
// a top-of-stack deferred function now, we know that the send
// only happens after any other stacked defers have completed.
runtime.Goexit()
}
// log generates the output. It's always at the same stack depth.
func (c *common) log(s string) {
c.output = append(c.output, decorate(s, true)...)
}
// Log formats its arguments using default formatting, analogous to Println(),
// and records the text in the error log.
func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
// Logf formats its arguments according to the format, analogous to Printf(),
// and records the text in the error log.
func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
// Error is equivalent to Log() followed by Fail().
func (c *common) Error(args ...interface{}) {
c.log(fmt.Sprintln(args...))
c.Fail()
}
// Errorf is equivalent to Logf() followed by Fail().
func (c *common) Errorf(format string, args ...interface{}) {
c.log(fmt.Sprintf(format, args...))
c.Fail()
}
// Fatal is equivalent to Log() followed by FailNow().
func (c *common) Fatal(args ...interface{}) {
c.log(fmt.Sprintln(args...))
c.FailNow()
}
// Fatalf is equivalent to Logf() followed by FailNow().
func (c *common) Fatalf(format string, args ...interface{}) {
c.log(fmt.Sprintf(format, args...))
c.FailNow()
}
// Parallel signals that this test is to be run in parallel with (and only with)
// other parallel tests in this CPU group.
func (t *T) Parallel() {
t.signal <- (*T)(nil) // Release main testing loop
<-t.startParallel // Wait for serial tests to finish
}
// An internal type but exported because it is cross-package; part of the implementation
// of go test.
type InternalTest struct {
Name string
F func(*T)
}
func tRunner(t *T, test *InternalTest) {
t.start = time.Now()
// When this goroutine is done, either because test.F(t)
// returned normally or because a test failure triggered
// a call to runtime.Goexit, record the duration and send
// a signal saying that the test is done.
defer func() {
t.duration = time.Now().Sub(t.start)
t.signal <- t
}()
test.F(t)
}
// An internal function but exported because it is cross-package; part of the implementation
// of go test.
func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
flag.Parse()
parseCpuList()
before()
startAlarm()
testOk := RunTests(matchString, tests)
exampleOk := RunExamples(examples)
if !testOk || !exampleOk {
fmt.Println("FAIL")
os.Exit(1)
}
fmt.Println("PASS")
stopAlarm()
RunBenchmarks(matchString, benchmarks)
after()
}
func (t *T) report() {
tstr := fmt.Sprintf("(%.2f seconds)", t.duration.Seconds())
format := "--- %s: %s %s\n%s"
if t.failed {
fmt.Printf(format, "FAIL", t.name, tstr, t.output)
} else if *chatty {
fmt.Printf(format, "PASS", t.name, tstr, t.output)
}
}
func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
ok = true
if len(tests) == 0 {
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
return
}
for _, procs := range cpuList {
runtime.GOMAXPROCS(procs)
// We build a new channel tree for each run of the loop.
// collector merges in one channel all the upstream signals from parallel tests.
// If all tests pump to the same channel, a bug can occur where a test
// kicks off a goroutine that Fails, yet the test still delivers a completion signal,
// which skews the counting.
var collector = make(chan interface{})
numParallel := 0
startParallel := make(chan bool)
for i := 0; i < len(tests); i++ {
matched, err := matchString(*match, tests[i].Name)
if err != nil {
fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
os.Exit(1)
}
if !matched {
continue
}
testName := tests[i].Name
if procs != 1 {
testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
}
t := &T{
common: common{
signal: make(chan interface{}),
},
name: testName,
startParallel: startParallel,
}
t.self = t
if *chatty {
fmt.Printf("=== RUN %s\n", t.name)
}
go tRunner(t, &tests[i])
out := (<-t.signal).(*T)
if out == nil { // Parallel run.
go func() {
collector <- <-t.signal
}()
numParallel++
continue
}
t.report()
ok = ok && !out.failed
}
running := 0
for numParallel+running > 0 {
if running < *parallel && numParallel > 0 {
startParallel <- true
running++
numParallel--
continue
}
t := (<-collector).(*T)
t.report()
ok = ok && !t.failed
running--
}
}
return
}
// before runs before all testing.
func before() {
if *memProfileRate > 0 {
runtime.MemProfileRate = *memProfileRate
}
if *cpuProfile != "" {
f, err := os.Create(*cpuProfile)
if err != nil {
fmt.Fprintf(os.Stderr, "testing: %s", err)
return
}
if err := pprof.StartCPUProfile(f); err != nil {
fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s", err)
f.Close()
return
}
// Could save f so after can call f.Close; not worth the effort.
}
}
// after runs after all testing.
func after() {
if *cpuProfile != "" {
pprof.StopCPUProfile() // flushes profile to disk
}
if *memProfile != "" {
f, err := os.Create(*memProfile)
if err != nil {
fmt.Fprintf(os.Stderr, "testing: %s", err)
return
}
if err = pprof.WriteHeapProfile(f); err != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s", *memProfile, err)
}
f.Close()
}
}
var timer *time.Timer
// startAlarm starts an alarm if requested.
func startAlarm() {
if *timeout > 0 {
timer = time.AfterFunc(*timeout, alarm)
}
}
// stopAlarm turns off the alarm.
func stopAlarm() {
if *timeout > 0 {
timer.Stop()
}
}
// alarm is called if the timeout expires.
func alarm() {
panic("test timed out")
}
func parseCpuList() {
if len(*cpuListStr) == 0 {
cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
} else {
for _, val := range strings.Split(*cpuListStr, ",") {
cpu, err := strconv.Atoi(val)
if err != nil || cpu <= 0 {
fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu", val)
os.Exit(1)
}
cpuList = append(cpuList, cpu)
}
}
}

View File

@ -1,182 +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 implements a parser test harness. The files in the testdata
// directory are parsed and the errors reported are compared against the
// error messages expected in the test files. The test files must end in
// .src rather than .go so that they are not disturbed by gofmt runs.
//
// Expected errors are indicated in the test files by putting a comment
// of the form /* ERROR "rx" */ immediately following an offending token.
// The harness will verify that an error matching the regular expression
// rx is reported at that source position.
//
// For instance, the following test file indicates that a "not declared"
// error should be reported for the undeclared variable x:
//
// package p
// func f() {
// _ = x /* ERROR "not declared" */ + 1
// }
package parser
import (
"io/ioutil"
"path/filepath"
"regexp"
"strings"
"testing"
"k8s.io/kubernetes/third_party/golang/go/scanner"
"k8s.io/kubernetes/third_party/golang/go/token"
)
const testdata = "testdata"
// getFile assumes that each filename occurs at most once
func getFile(fset *token.FileSet, filename string) (file *token.File) {
fset.Iterate(func(f *token.File) bool {
if f.Name() == filename {
if file != nil {
panic(filename + " used multiple times")
}
file = f
}
return true
})
return file
}
func getPos(fset *token.FileSet, filename string, offset int) token.Pos {
if f := getFile(fset, filename); f != nil {
return f.Pos(offset)
}
return token.NoPos
}
// ERROR comments must be of the form /* ERROR "rx" */ and rx is
// a regular expression that matches the expected error message.
// The special form /* ERROR HERE "rx" */ must be used for error
// messages that appear immediately after a token, rather than at
// a token's position.
//
var errRx = regexp.MustCompile(`^/\* *ERROR *(HERE)? *"([^"]*)" *\*/$`)
// expectedErrors collects the regular expressions of ERROR comments found
// in files and returns them as a map of error positions to error messages.
//
func expectedErrors(t *testing.T, fset *token.FileSet, filename string, src []byte) map[token.Pos]string {
errors := make(map[token.Pos]string)
var s scanner.Scanner
// file was parsed already - do not add it again to the file
// set otherwise the position information returned here will
// not match the position information collected by the parser
s.Init(getFile(fset, filename), src, nil, scanner.ScanComments)
var prev token.Pos // position of last non-comment, non-semicolon token
var here token.Pos // position immediately after the token at position prev
for {
pos, tok, lit := s.Scan()
switch tok {
case token.EOF:
return errors
case token.COMMENT:
s := errRx.FindStringSubmatch(lit)
if len(s) == 3 {
pos := prev
if s[1] == "HERE" {
pos = here
}
errors[pos] = string(s[2])
}
default:
prev = pos
var l int // token length
if tok.IsLiteral() {
l = len(lit)
} else {
l = len(tok.String())
}
here = prev + token.Pos(l)
}
}
}
// compareErrors compares the map of expected error messages with the list
// of found errors and reports discrepancies.
//
func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]string, found scanner.ErrorList) {
for _, error := range found {
// error.Pos is a token.Position, but we want
// a token.Pos so we can do a map lookup
pos := getPos(fset, error.Pos.Filename, error.Pos.Offset)
if msg, found := expected[pos]; found {
// we expect a message at pos; check if it matches
rx, err := regexp.Compile(msg)
if err != nil {
t.Errorf("%s: %v", error.Pos, err)
continue
}
if match := rx.MatchString(error.Msg); !match {
t.Errorf("%s: %q does not match %q", error.Pos, error.Msg, msg)
continue
}
// we have a match - eliminate this error
delete(expected, pos)
} else {
// To keep in mind when analyzing failed test output:
// If the same error position occurs multiple times in errors,
// this message will be triggered (because the first error at
// the position removes this position from the expected errors).
t.Errorf("%s: unexpected error: %s", error.Pos, error.Msg)
}
}
// there should be no expected errors left
if len(expected) > 0 {
t.Errorf("%d errors not reported:", len(expected))
for pos, msg := range expected {
t.Errorf("%s: %s\n", fset.Position(pos), msg)
}
}
}
func checkErrors(t *testing.T, filename string, input interface{}) {
src, err := readSource(filename, input)
if err != nil {
t.Error(err)
return
}
fset := token.NewFileSet()
_, err = ParseFile(fset, filename, src, DeclarationErrors|AllErrors)
found, ok := err.(scanner.ErrorList)
if err != nil && !ok {
t.Error(err)
return
}
found.RemoveMultiples()
// we are expecting the following errors
// (collect these after parsing a file so that it is found in the file set)
expected := expectedErrors(t, fset, filename, src)
// verify errors returned by the parser
compareErrors(t, fset, expected, found)
}
func TestErrors(t *testing.T) {
list, err := ioutil.ReadDir(testdata)
if err != nil {
t.Fatal(err)
}
for _, fi := range list {
name := fi.Name()
if !fi.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".src") {
checkErrors(t, filepath.Join(testdata, name), nil)
}
}
}

View File

@ -1,34 +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 parser_test
import (
"fmt"
"k8s.io/kubernetes/third_party/golang/go/parser"
"k8s.io/kubernetes/third_party/golang/go/token"
)
func ExampleParseFile() {
fset := token.NewFileSet() // positions are relative to fset
// Parse the file containing this very example
// but stop after processing the imports.
f, err := parser.ParseFile(fset, "example_test.go", nil, parser.ImportsOnly)
if err != nil {
fmt.Println(err)
return
}
// Print the imports from the file's AST.
for _, s := range f.Imports {
fmt.Println(s.Path.Value)
}
// output:
//
// "fmt"
// "k8s.io/kubernetes/third_party/golang/go/parser"
// "k8s.io/kubernetes/third_party/golang/go/token"
}

View File

@ -1,227 +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 contains the exported entry points for invoking the parser.
package parser
import (
"bytes"
"errors"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"k8s.io/kubernetes/third_party/golang/go/ast"
"k8s.io/kubernetes/third_party/golang/go/token"
)
// If src != nil, readSource converts src to a []byte if possible;
// otherwise it returns an error. If src == nil, readSource returns
// the result of reading the file specified by filename.
//
func readSource(filename string, src interface{}) ([]byte, error) {
if src != nil {
switch s := src.(type) {
case string:
return []byte(s), nil
case []byte:
return s, nil
case *bytes.Buffer:
// is io.Reader, but src is already available in []byte form
if s != nil {
return s.Bytes(), nil
}
case io.Reader:
var buf bytes.Buffer
if _, err := io.Copy(&buf, s); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
return nil, errors.New("invalid source")
}
return ioutil.ReadFile(filename)
}
// A Mode value is a set of flags (or 0).
// They control the amount of source code parsed and other optional
// parser functionality.
//
type Mode uint
const (
PackageClauseOnly Mode = 1 << iota // stop parsing after package clause
ImportsOnly // stop parsing after import declarations
ParseComments // parse comments and add them to AST
Trace // print a trace of parsed productions
DeclarationErrors // report declaration errors
SpuriousErrors // same as AllErrors, for backward-compatibility
AllErrors = SpuriousErrors // report all errors (not just the first 10 on different lines)
)
// ParseFile parses the source code of a single Go source file and returns
// the corresponding ast.File node. The source code may be provided via
// the filename of the source file, or via the src parameter.
//
// If src != nil, ParseFile parses the source from src and the filename is
// only used when recording position information. The type of the argument
// for the src parameter must be string, []byte, or io.Reader.
// If src == nil, ParseFile parses the file specified by filename.
//
// The mode parameter controls the amount of source text parsed and other
// optional parser functionality. Position information is recorded in the
// file set fset.
//
// If the source couldn't be read, the returned AST is nil and the error
// indicates the specific failure. If the source was read but syntax
// errors were found, the result is a partial AST (with ast.Bad* nodes
// representing the fragments of erroneous source code). Multiple errors
// are returned via a scanner.ErrorList which is sorted by file position.
//
func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (f *ast.File, err error) {
// get source
text, err := readSource(filename, src)
if err != nil {
return nil, err
}
var p parser
defer func() {
if e := recover(); e != nil {
// resume same panic if it's not a bailout
if _, ok := e.(bailout); !ok {
panic(e)
}
}
// set result values
if f == nil {
// source is not a valid Go source file - satisfy
// ParseFile API and return a valid (but) empty
// *ast.File
f = &ast.File{
Name: new(ast.Ident),
Scope: ast.NewScope(nil),
}
}
p.errors.Sort()
err = p.errors.Err()
}()
// parse source
p.init(fset, filename, text, mode)
f = p.parseFile()
return
}
// ParseDir calls ParseFile for all files with names ending in ".go" in the
// directory specified by path and returns a map of package name -> package
// AST with all the packages found.
//
// If filter != nil, only the files with os.FileInfo entries passing through
// the filter (and ending in ".go") are considered. The mode bits are passed
// to ParseFile unchanged. Position information is recorded in fset.
//
// If the directory couldn't be read, a nil map and the respective error are
// returned. If a parse error occurred, a non-nil but incomplete map and the
// first error encountered are returned.
//
func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, mode Mode) (pkgs map[string]*ast.Package, first error) {
fd, err := os.Open(path)
if err != nil {
return nil, err
}
defer fd.Close()
list, err := fd.Readdir(-1)
if err != nil {
return nil, err
}
pkgs = make(map[string]*ast.Package)
for _, d := range list {
if strings.HasSuffix(d.Name(), ".go") && (filter == nil || filter(d)) {
filename := filepath.Join(path, d.Name())
if src, err := ParseFile(fset, filename, nil, mode); err == nil {
name := src.Name.Name
pkg, found := pkgs[name]
if !found {
pkg = &ast.Package{
Name: name,
Files: make(map[string]*ast.File),
}
pkgs[name] = pkg
}
pkg.Files[filename] = src
} else if first == nil {
first = err
}
}
}
return
}
// ParseExprFrom is a convenience function for parsing an expression.
// The arguments have the same meaning as for Parse, but the source must
// be a valid Go (type or value) expression.
//
func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode Mode) (ast.Expr, error) {
// get source
text, err := readSource(filename, src)
if err != nil {
return nil, err
}
var p parser
defer func() {
if e := recover(); e != nil {
// resume same panic if it's not a bailout
if _, ok := e.(bailout); !ok {
panic(e)
}
}
p.errors.Sort()
err = p.errors.Err()
}()
// parse expr
p.init(fset, filename, text, mode)
// Set up pkg-level scopes to avoid nil-pointer errors.
// This is not needed for a correct expression x as the
// parser will be ok with a nil topScope, but be cautious
// in case of an erroneous x.
p.openScope()
p.pkgScope = p.topScope
e := p.parseRhsOrType()
p.closeScope()
assert(p.topScope == nil, "unbalanced scopes")
// If a semicolon was inserted, consume it;
// report an error if there's more tokens.
if p.tok == token.SEMICOLON && p.lit == "\n" {
p.next()
}
p.expect(token.EOF)
if p.errors.Len() > 0 {
p.errors.Sort()
return nil, p.errors.Err()
}
return e, nil
}
// ParseExpr is a convenience function for obtaining the AST of an expression x.
// The position information recorded in the AST is undefined. The filename used
// in error messages is the empty string.
//
func ParseExpr(x string) (ast.Expr, error) {
return ParseExprFrom(token.NewFileSet(), "", []byte(x), 0)
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More