// Expressions and types
// A Field represents a Field declaration list in a struct type,
-// a method in an interface type, or a parameter/result declaration
+// 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; nil if anonymous field
+ 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
StructType struct {
token.Position; // position of "struct" keyword
Lbrace token.Position; // position of "{"
- Fields []*Field; // list of field declarations; nil if forward declaration
+ Fields []*Field; // list of field declarations
Rbrace token.Position; // position of "}"
+ Incomplete bool; // true if (source) fields are missing in the Fields list
};
// Pointer types are represented via StarExpr nodes.
InterfaceType struct {
token.Position; // position of "interface" keyword
Lbrace token.Position; // position of "{"
- Methods []*Field; // list of methods; nil if forward declaration
+ Methods []*Field; // list of methods
Rbrace token.Position; // position of "}"
+ Incomplete bool; // true if (source) methods are missing in the Methods list
};
// A MapType node represents a map type.
package ast
-import (
- "go/token";
-)
+import "go/token";
func filterIdentList(list []*Ident) []*Ident {
}
-func filterFieldList(list []*Field) []*Field {
+func filterFieldList(list []*Field, incomplete *bool) []*Field {
j := 0;
for _, f := range list {
exported := false;
// type information.)
exported = isExportedType(f.Type);
} else {
+ n := len(f.Names);
f.Names = filterIdentList(f.Names);
+ if len(f.Names) < n {
+ *incomplete = true;
+ }
exported = len(f.Names) > 0;
}
if exported {
j++;
}
}
- if j > 0 && j < len(list) {
- // fields have been stripped but there is at least one left;
- // add a '...' anonymous field instead
- list[j] = &Field{nil, nil, &Ellipsis{}, nil, nil};
- j++;
+ if j < len(list) {
+ *incomplete = true;
}
return list[0 : j];
}
case *ArrayType:
filterType(t.Elt);
case *StructType:
- // don't change if empty struct
- if len(t.Fields) > 0 {
- t.Fields = filterFieldList(t.Fields);
- if len(t.Fields) == 0 {
- // all fields have been stripped - make look like forward-decl
- t.Lbrace = noPos;
- t.Fields = nil;
- t.Rbrace = noPos;
- }
- }
+ t.Fields = filterFieldList(t.Fields, &t.Incomplete);
case *FuncType:
filterParamList(t.Params);
filterParamList(t.Results);
case *InterfaceType:
- // don't change if empty interface
- if len(t.Methods) > 0 {
- t.Methods = filterFieldList(t.Methods);
- if len(t.Methods) == 0 {
- // all methods have been stripped - make look like forward-decl
- t.Lbrace = noPos;
- t.Methods = nil;
- t.Rbrace = noPos;
- }
- }
+ t.Methods = filterFieldList(t.Methods, &t.Incomplete);
case *MapType:
filterType(t.Key);
filterType(t.Value);
fields[i] = list.At(i).(*ast.Field);
}
- return &ast.StructType{pos, lbrace, fields, rbrace};
+ return &ast.StructType{pos, lbrace, fields, rbrace, false};
}
methods[i] = list.At(i).(*ast.Field);
}
- return &ast.InterfaceType{pos, lbrace, methods, rbrace};
+ return &ast.InterfaceType{pos, lbrace, methods, rbrace, false};
}
}
-func (p *printer) signature(params, result []*ast.Field) {
+// Returns true if a separating semicolon is optional.
+func (p *printer) signature(params, result []*ast.Field) (optSemi bool) {
p.parameters(params);
if result != nil {
p.print(blank);
// single anonymous result; no ()'s unless it's a function type
f := result[0];
if _, isFtyp := f.Type.(*ast.FuncType); !isFtyp {
- p.expr(f.Type);
+ optSemi = p.expr(f.Type);
return;
}
}
p.parameters(result);
}
+ return;
}
-// Returns true if the field list ends in a closing brace.
-func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isInterface bool) bool {
- if list == nil {
- // forward declaration
- // TODO(gri) remove this logic once godoc doesn't produce field
- // lists that resemble forward declarations anymore
- return false; // no {}'s
+func incompleteMsg(isInterface bool) string {
+ if isInterface {
+ return "// contains unexported methods";
}
+ return "// contains unexported fields";
+}
+
+func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isIncomplete, isInterface bool) {
if len(list) == 0 {
- // no blank between keyword and {} in this case
- p.print(lbrace, token.LBRACE, rbrace, token.RBRACE);
- return true; // empty list with {}'s
+ if isIncomplete {
+ // all entries were stripped
+ p.print(blank, lbrace, token.LBRACE, +1, newline, incompleteMsg(isInterface), -1, newline, rbrace, token.RBRACE);
+ } else {
+ // no blank between keyword and {} in this case
+ p.print(lbrace, token.LBRACE, rbrace, token.RBRACE);
+ }
+ return;
}
p.print(blank, lbrace, token.LBRACE, +1, newline);
p.print(token.SEMICOLON);
p.lineComment(lastComment);
- p.print(-1, formfeed, rbrace, token.RBRACE);
- return true; // field list with {}'s
+ if isIncomplete {
+ // at least one entry printed, but some entries were stripped
+ p.print(newline, incompleteMsg(isInterface));
+ }
+
+ p.print(-1, formfeed, rbrace, token.RBRACE);
}
}
+// Returns true if a separating semicolon is optional.
func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) {
p.print(expr.Pos());
case *ast.StarExpr:
p.print(token.MUL);
- p.expr(x.X);
+ optSemi = p.expr(x.X);
case *ast.UnaryExpr:
const prec = token.UnaryPrec;
p.expr(x.Len);
}
p.print(token.RBRACK);
- p.expr(x.Elt);
+ optSemi = p.expr(x.Elt);
case *ast.StructType:
p.print(token.STRUCT);
- optSemi = p.fieldList(x.Lbrace, x.Fields, x.Rbrace, false);
+ p.fieldList(x.Lbrace, x.Fields, x.Rbrace, x.Incomplete, false);
+ optSemi = true;
case *ast.FuncType:
p.print(token.FUNC);
- p.signature(x.Params, x.Results);
+ optSemi = p.signature(x.Params, x.Results);
case *ast.InterfaceType:
p.print(token.INTERFACE);
- optSemi = p.fieldList(x.Lbrace, x.Methods, x.Rbrace, true);
+ p.fieldList(x.Lbrace, x.Methods, x.Rbrace, x.Incomplete, true);
+ optSemi = true;
case *ast.MapType:
p.print(token.MAP, token.LBRACK);
p.expr(x.Key);
p.print(token.RBRACK);
- p.expr(x.Value);
+ optSemi = p.expr(x.Value);
case *ast.ChanType:
switch x.Dir {
p.print(token.CHAN, token.ARROW);
}
p.print(blank);
- p.expr(x.Value);
+ optSemi = p.expr(x.Value);
default:
panic("unreachable");
)
-// The T type.
-type T struct {
- a, b, c int // 3 fields
+// The SZ struct; it is empty.
+type SZ struct {}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+ int;
+ x, y, z int; // 3 unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+ S0;
+ A, B, C float; // 3 exported fields
+ D, b, c int; // 2 unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+ S1;
+ A, B, C float; // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface {}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+ f, g (x int) int; // 2 unexported methods
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+ I0;
+ F, G (x float) float; // 2 exported methods
+ H, g (x int) int; // 1 unexported method
+}
+
+// The I2 interface; all methods are exported.
+type I1 interface {
+ I0;
+ F, G (x float) float; // 2 exported methods
}
// This comment group should be separated
)
-// The T type.
-type T struct {
- a, b, c int; // 3 fields
+// The SZ struct; it is empty.
+type SZ struct{}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+ int;
+ x, y, z int; // 3 unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+ S0;
+ A, B, C float; // 3 exported fields
+ D, b, c int; // 2 unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+ S1;
+ A, B, C float; // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface{}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+ f, g (x int) int; // 2 unexported methods
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+ I0;
+ F, G (x float) float; // 2 exported methods
+ H, g (x int) int; // 1 unexported method
+}
+
+// The I2 interface; all methods are exported.
+type I1 interface {
+ I0;
+ F, G (x float) float; // 2 exported methods
}
// This comment group should be separated
//
package main
-// The T type.
-type T struct
+// The SZ struct; it is empty.
+type SZ struct{}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+ // contains unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+ S0;
+ A, B, C float; // 3 exported fields
+ D int; // 2 unexported fields
+ // contains unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+ S1;
+ A, B, C float; // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface{}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+ // contains unexported methods
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+ I0;
+ F, G (x float) float;
+ H (x int) int;
+ // contains unexported methods
+}
+
+// The I2 interface; all methods are exported.
+type I1 interface {
+ I0;
+ F, G (x float) float;
+}
import "io"
import (
- a "io"
+ _ "io"
)
-import a "io"
+import _ "io"
import (
"io";
c "i" "o";
)
+func _() {
+ // the following decls need a semicolon at the end
+ type _ int;
+ type _ *int;
+ type _ []int;
+ type _ map[string]int;
+ type _ chan int;
+ type _ func() int;
+
+ var _ int;
+ var _ *int;
+ var _ []int;
+ var _ map[string]int;
+ var _ chan int;
+ var _ func() int;
+
+ // the following decls don't need a semicolon at the end
+ type _ struct{}
+ type _ *struct{}
+ type _ []struct{}
+ type _ map[string]struct{}
+ type _ chan struct{}
+ type _ func() struct{}
+
+ type _ interface{}
+ type _ *interface{}
+ type _ []interface{}
+ type _ map[string]interface{}
+ type _ chan interface{}
+ type _ func() interface{}
+
+ var _ struct{}
+ var _ *struct{}
+ var _ []struct{}
+ var _ map[string]struct{}
+ var _ chan struct{}
+ var _ func() struct{}
+
+ var _ interface{}
+ var _ *interface{}
+ var _ []interface{}
+ var _ map[string]interface{}
+ var _ chan interface{}
+ var _ func() interface{}
+}
+
// TODO(gri) add more test cases
import "io"
import (
- a "io";
+ _ "io";
)
-import a "io"
+import _ "io"
import (
"io";
c "i" "o";
)
+func _() {
+ // the following decls need a semicolon at the end
+ type _ int;
+ type _ *int;
+ type _ []int;
+ type _ map[string]int;
+ type _ chan int;
+ type _ func() int;
+ var _ int;
+ var _ *int;
+ var _ []int;
+ var _ map[string]int;
+ var _ chan int;
+ var _ func() int;
+
+ // the following decls don't need a semicolon at the end
+ type _ struct{}
+ type _ *struct{}
+ type _ []struct{}
+ type _ map[string]struct{}
+ type _ chan struct{}
+ type _ func() struct{}
+ type _ interface{}
+ type _ *interface{}
+ type _ []interface{}
+ type _ map[string]interface{}
+ type _ chan interface{}
+ type _ func() interface{}
+ var _ struct{}
+ var _ *struct{}
+ var _ []struct{}
+ var _ map[string]struct{}
+ var _ chan struct{}
+ var _ func() struct{}
+ var _ interface{}
+ var _ *interface{}
+ var _ []interface{}
+ var _ map[string]interface{}
+ var _ chan interface{}
+ var _ func() interface{}
+}
+
// TODO(gri) add more test cases