func (p *exporter) field(f *types.Var) { // anonymous fields have "" name name := "" if !f.Anonymous() { name = f.Name() } // qualifiedName will always emit the field package for // anonymous fields because "" is not an exported name. p.qualifiedName(f.Pkg(), name) p.typ(f.Type()) }
// checkStructField checks that the field renaming will not cause // conflicts at its declaration, or ambiguity or changes to any selection. func (e *Export) checkStructField(from *types.Var, to string) { // Check that the struct declaration is free of field conflicts, // and field/method conflicts. t := getEnclosingStruct(from) if t != t.Underlying() { // This struct is also a named type. // We must check for direct (non-promoted) field/field // and method/field conflicts. _, indices, _ := types.LookupFieldOrMethod(t, true, e.u.pkgInfo.Pkg, to) if len(indices) == 1 { e.Conflicting = true return } } else { // This struct is not a named type. // We need only check for direct (non-promoted) field/field conflicts. T := t.Underlying().(*types.Struct) for i := 0; i < T.NumFields(); i++ { if prev := T.Field(i); prev.Name() == to { e.Conflicting = true return } } } // Renaming an anonymous field requires renaming the type too. e.g. // print(s.T) // if we rename T to U, // type T int // this and // var s struct {T} // this must change too. if from.Anonymous() { if named, ok := from.Type().(*types.Named); ok { e.check(named.Obj(), to) } else if named, ok := deref(from.Type()).(*types.Named); ok { e.check(named.Obj(), to) } } // Check integrity of existing (field and method) selections. e.checkSelections(from, to) }
// checkStructField checks that the field renaming will not cause // conflicts at its declaration, or ambiguity or changes to any selection. func (r *Unexporter) checkStructField(objsToUpdate map[types.Object]string, from *types.Var, to string) { // Check that the struct declaration is free of field conflicts, // and field/method conflicts. // go/types offers no easy way to get from a field (or interface // method) to its declaring struct (or interface), so we must // ascend the AST. info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos()) // path matches this pattern: // [Ident SelectorExpr? StarExpr? Field FieldList StructType ParenExpr* ... File] // Ascend to FieldList. var i int for { if _, ok := path[i].(*ast.FieldList); ok { break } i++ } i++ tStruct := path[i].(*ast.StructType) i++ // Ascend past parens (unlikely). for { _, ok := path[i].(*ast.ParenExpr) if !ok { break } i++ } if spec, ok := path[i].(*ast.TypeSpec); ok { // This struct is also a named type. // We must check for direct (non-promoted) field/field // and method/field conflicts. named := info.Defs[spec.Name].Type() prev, indices, _ := types.LookupFieldOrMethod(named, true, info.Pkg, to) if len(indices) == 1 { r.warn(from, r.errorf(from.Pos(), "renaming this field %q to %q", from.Name(), to), r.errorf(prev.Pos(), "\twould conflict with this %s", objectKind(prev))) return // skip checkSelections to avoid redundant errors } } else { // This struct is not a named type. // We need only check for direct (non-promoted) field/field conflicts. t := info.Types[tStruct].Type.Underlying().(*types.Struct) for i := 0; i < t.NumFields(); i++ { if prev := t.Field(i); prev.Name() == to { r.warn(from, r.errorf(from.Pos(), "renaming this field %q to %q", from.Name(), to), r.errorf(prev.Pos(), "\twould conflict with this field")) return // skip checkSelections to avoid redundant errors } } } // Renaming an anonymous field requires renaming the type too. e.g. // print(s.T) // if we rename T to U, // type T int // this and // var s struct {T} // this must change too. if from.Anonymous() { if named, ok := from.Type().(*types.Named); ok { r.check(objsToUpdate, named.Obj(), to) } else if named, ok := deref(from.Type()).(*types.Named); ok { r.check(objsToUpdate, named.Obj(), to) } } // Check integrity of existing (field and method) selections. r.checkSelections(objsToUpdate, from, to) }