Merge pull request #28204 from thockin/cleanup-third_party

Automatic merge from submit-queue

Cleanup third party (pt 2)

Move forked-and-hacked golang code to the forked/ directory.  Remove ast/build/parse code that is now in stdlib.  Remove unused shell2junit
This commit is contained in:
k8s-merge-robot 2016-07-07 12:13:14 -07:00 committed by GitHub
commit 4da14c8a64
191 changed files with 19 additions and 45391 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"
"k8s.io/kubernetes/third_party/golang/go/ast"
"k8s.io/kubernetes/third_party/golang/go/parser"
"k8s.io/kubernetes/third_party/golang/go/printer"
"k8s.io/kubernetes/third_party/golang/go/token"
customreflect "k8s.io/kubernetes/third_party/golang/reflect"
customreflect "k8s.io/kubernetes/third_party/forked/golang/reflect"
)
func rewriteFile(name string, header []byte, rewriteFn func(*token.FileSet, *ast.File) error) error {

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

@ -17,7 +17,7 @@ limitations under the License.
package conversion
import (
"k8s.io/kubernetes/third_party/forked/reflect"
"k8s.io/kubernetes/third_party/forked/golang/reflect"
)
// The code for this type must be located in third_party, since it forks from

View File

@ -27,7 +27,7 @@ import (
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/types"
hashutil "k8s.io/kubernetes/pkg/util/hash"
"k8s.io/kubernetes/third_party/golang/expansion"
"k8s.io/kubernetes/third_party/forked/golang/expansion"
"github.com/golang/glog"
)

View File

@ -97,7 +97,7 @@ import (
"k8s.io/kubernetes/pkg/watch"
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates"
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
"k8s.io/kubernetes/third_party/golang/expansion"
"k8s.io/kubernetes/third_party/forked/golang/expansion"
)
const (

View File

@ -32,7 +32,7 @@ import (
apierrors "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/util/httpstream"
"k8s.io/kubernetes/third_party/golang/netutil"
"k8s.io/kubernetes/third_party/forked/golang/netutil"
)
// SpdyRoundTripper knows how to upgrade an HTTP request to one that supports

View File

@ -23,7 +23,7 @@ import (
"reflect"
"strings"
"k8s.io/kubernetes/third_party/golang/template"
"k8s.io/kubernetes/third_party/forked/golang/template"
)
type JSONPath struct {

View File

@ -26,7 +26,7 @@ import (
"github.com/golang/glog"
utilnet "k8s.io/kubernetes/pkg/util/net"
"k8s.io/kubernetes/third_party/golang/netutil"
"k8s.io/kubernetes/third_party/forked/golang/netutil"
)
func DialURL(url *url.URL, transport http.RoundTripper) (net.Conn, error) {

View File

@ -22,7 +22,7 @@ import (
"sort"
"k8s.io/kubernetes/pkg/util/json"
forkedjson "k8s.io/kubernetes/third_party/forked/json"
forkedjson "k8s.io/kubernetes/third_party/forked/golang/json"
"github.com/davecgh/go-spew/spew"
"github.com/ghodss/yaml"

View File

@ -1,27 +0,0 @@
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,27 +0,0 @@
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

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

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