]> Cypherpunks repositories - gostls13.git/commitdiff
- don't add "..." anonymous field to structs/interfaces if entries are stripped
authorRobert Griesemer <gri@golang.org>
Thu, 17 Sep 2009 16:12:14 +0000 (09:12 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 17 Sep 2009 16:12:14 +0000 (09:12 -0700)
- don't print any optional semicolons after declarations inside functions
- indicate non-exported fields/methods in exported types with a comment
  so that the "exported source" is legal Go code
- more tests

R=rsc
DELTA=300  (227 added, 25 deleted, 48 changed)
OCL=34697
CL=34730

src/pkg/go/ast/ast.go
src/pkg/go/ast/filter.go
src/pkg/go/parser/parser.go
src/pkg/go/printer/printer.go
src/pkg/go/printer/testdata/comments.go
src/pkg/go/printer/testdata/comments.golden
src/pkg/go/printer/testdata/comments.x
src/pkg/go/printer/testdata/declarations.go
src/pkg/go/printer/testdata/declarations.golden

index cc48dcc7443c3707d267423c0558b24f4a17343b..8861049aaf30f81d4397a9ae2d18858e73b27267 100644 (file)
@@ -83,12 +83,12 @@ type CommentGroup struct {
 // 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
@@ -249,8 +249,9 @@ type (
        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.
@@ -266,8 +267,9 @@ type (
        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.
index 16bcdb9d7e9624a900cd5b83c40487a28b59c5c1..467f772be84f375ae9cc5ac2940e70b09bc35599 100644 (file)
@@ -4,9 +4,7 @@
 
 package ast
 
-import (
-       "go/token";
-)
+import "go/token";
 
 
 func filterIdentList(list []*Ident) []*Ident {
@@ -38,7 +36,7 @@ func isExportedType(typ Expr) bool {
 }
 
 
-func filterFieldList(list []*Field) []*Field {
+func filterFieldList(list []*Field, incomplete *bool) []*Field {
        j := 0;
        for _, f := range list {
                exported := false;
@@ -51,7 +49,11 @@ func filterFieldList(list []*Field) []*Field {
                        // 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 {
@@ -60,11 +62,8 @@ func filterFieldList(list []*Field) []*Field {
                        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];
 }
@@ -84,30 +83,12 @@ func filterType(typ Expr) {
        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);
index 76682db950703530eb7d6f7619236b0b40597494..e8a981e8df45605563afc3041704282752c71d70 100644 (file)
@@ -512,7 +512,7 @@ func (p *parser) parseStructType() *ast.StructType {
                fields[i] = list.At(i).(*ast.Field);
        }
 
-       return &ast.StructType{pos, lbrace, fields, rbrace};
+       return &ast.StructType{pos, lbrace, fields, rbrace, false};
 }
 
 
@@ -720,7 +720,7 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
                methods[i] = list.At(i).(*ast.Field);
        }
 
-       return &ast.InterfaceType{pos, lbrace, methods, rbrace};
+       return &ast.InterfaceType{pos, lbrace, methods, rbrace, false};
 }
 
 
index 7cd3c493bf447689690e95e857bef219d5a9b79d..5ee428ca1c48f462f8ce414d44bd8e2fabc54999 100644 (file)
@@ -550,7 +550,8 @@ func (p *printer) parameters(list []*ast.Field) {
 }
 
 
-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);
@@ -559,29 +560,35 @@ func (p *printer) signature(params, result []*ast.Field) {
                        // 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);
@@ -636,9 +643,13 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
 
        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);
 }
 
 
@@ -715,6 +726,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1 int) {
 }
 
 
+// Returns true if a separating semicolon is optional.
 func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) {
        p.print(expr.Pos());
 
@@ -735,7 +747,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) {
 
        case *ast.StarExpr:
                p.print(token.MUL);
-               p.expr(x.X);
+               optSemi = p.expr(x.X);
 
        case *ast.UnaryExpr:
                const prec = token.UnaryPrec;
@@ -823,25 +835,27 @@ func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) {
                        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 {
@@ -853,7 +867,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) {
                        p.print(token.CHAN, token.ARROW);
                }
                p.print(blank);
-               p.expr(x.Value);
+               optSemi = p.expr(x.Value);
 
        default:
                panic("unreachable");
index 212d064406a5ba98c02ec943b745aa5f4dff17fe..690da6bbef7d9a49dd20b192ce2e4bf3f5016bad 100644 (file)
@@ -15,9 +15,47 @@ const (
 )
 
 
-// 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
index 877a7357a1ab907f4e8f4e96c62b28350db0f476..af11771afa322ddb2f71f879a907f28f7bffc120 100644 (file)
@@ -15,9 +15,47 @@ const (
 )
 
 
-// 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
index 4ebb6ec67005d018a3891e135d30fc4f881841ec..d8aa0fceebcf4c3a46ec58e726fe119f36feb984 100644 (file)
@@ -2,5 +2,46 @@
 //
 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;
+}
index 309caf3b616788feb7a597ba9173302f32cd43d2..3865a4319adb3724e1a3a531e901314ed4191f70 100644 (file)
@@ -7,10 +7,10 @@ package imports
 import "io"
 
 import (
-       a "io"
+       _ "io"
 )
 
-import a "io"
+import _ "io"
 
 import (
        "io";
@@ -25,4 +25,50 @@ import (
        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
index 21c3c2b930d1790d38ee723014e9e495001319b4..131841c9435f9fd8be3dd85246a39b6552f939ea 100644 (file)
@@ -7,10 +7,10 @@ package imports
 import "io"
 
 import (
-       a "io";
+       _ "io";
 )
 
-import a "io"
+import _ "io"
 
 import (
        "io";
@@ -25,4 +25,46 @@ import (
        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