internal/importers: skip unexported embedded fields
When determining if a Go struct embeds prefixed types, don't consider
unexported fields. This is important to avoid references cycles with the
Android databinding library; see the reverse example for details.
Change-Id: Ia820ca7ba4d1ec11a1f48651fac248eb753aad75
Reviewed-on: https://go-review.googlesource.com/35188
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/example/reverse/reverse/reverse.go b/example/reverse/reverse/reverse.go
index 501be71..8cc8b15 100644
--- a/example/reverse/reverse/reverse.go
+++ b/example/reverse/reverse/reverse.go
@@ -11,18 +11,25 @@
"Java/android/support/v7/app"
gopkg "Java/reverse"
rlayout "Java/reverse/R/layout"
+ "Java/reverse/databinding"
"Java/reverse/databinding/ActivityMainBinding"
)
type MainActivity struct {
app.AppCompatActivity
+ binding databinding.ActivityMainBinding
}
func (a *MainActivity) OnCreate(this gopkg.MainActivity, b os.Bundle) {
this.Super().OnCreate(b)
db := DataBindingUtil.SetContentView(this, rlayout.Activity_main)
- mainBind := ActivityMainBinding.Cast(db)
- mainBind.SetAct(this)
+ a.binding = ActivityMainBinding.Cast(db)
+ a.binding.SetAct(this)
+}
+
+func (a *MainActivity) OnDestroy(this gopkg.MainActivity) {
+ a.binding = nil // break reference cycle
+ this.Super().OnDestroy()
}
func (a *MainActivity) GetLabel() string {
diff --git a/internal/importers/ast.go b/internal/importers/ast.go
index 4a7b920..3c798c1 100644
--- a/internal/importers/ast.go
+++ b/internal/importers/ast.go
@@ -80,8 +80,9 @@
type refsSaver struct {
pkgPrefix string
- References
- refMap map[PkgRef]struct{}
+ *References
+ refMap map[PkgRef]struct{}
+ insideStruct bool
}
// AnalyzeFile scans the provided file for references to packages with the given
@@ -94,7 +95,7 @@
pkg, _ := ast.NewPackage(fset, files, visitor.importer(), nil)
ast.Walk(visitor, pkg)
visitor.findEmbeddingStructs(pkg)
- return &visitor.References, nil
+ return visitor.References, nil
}
// AnalyzePackages scans the provided packages for references to packages with the given
@@ -118,7 +119,7 @@
ast.Walk(visitor, astpkg)
visitor.findEmbeddingStructs(astpkg)
}
- return &visitor.References, nil
+ return visitor.References, nil
}
// findEmbeddingStructs finds all top level declarations embedding a prefixed type.
@@ -148,6 +149,9 @@
}
var refs []PkgRef
for _, f := range t.Fields.List {
+ if len(f.Names) > 0 && !f.Names[0].IsExported() {
+ continue
+ }
sel, ok := f.Type.(*ast.SelectorExpr)
if !ok {
continue
@@ -169,8 +173,9 @@
func newRefsSaver(pkgPrefix string) *refsSaver {
s := &refsSaver{
- pkgPrefix: pkgPrefix,
- refMap: make(map[PkgRef]struct{}),
+ pkgPrefix: pkgPrefix,
+ refMap: make(map[PkgRef]struct{}),
+ References: &References{},
}
s.Names = make(map[string]struct{})
return s
@@ -212,6 +217,17 @@
func (v *refsSaver) Visit(n ast.Node) ast.Visitor {
switch n := n.(type) {
+ case *ast.StructType:
+ // Use a copy of refsSaver that only accepts exported fields. It refers
+ // to the original refsSaver for collecting references.
+ v2 := *v
+ v2.insideStruct = true
+ return &v2
+ case *ast.Field:
+ if v.insideStruct && len(n.Names) == 1 && !n.Names[0].IsExported() {
+ return nil
+ }
+ return v
case *ast.SelectorExpr:
v.Names[n.Sel.Name] = struct{}{}
if ref, ok := v.parseRef(n); ok {
diff --git a/internal/importers/ast_test.go b/internal/importers/ast_test.go
index ee9bc8c..a26b3c3 100644
--- a/internal/importers/ast_test.go
+++ b/internal/importers/ast_test.go
@@ -16,6 +16,7 @@
type T struct {
Name.Type
+ hidden Name.Type2
}
`
fset := token.NewFileSet()
diff --git a/internal/importers/java/java.go b/internal/importers/java/java.go
index 68a3073..dfba7be 100644
--- a/internal/importers/java/java.go
+++ b/internal/importers/java/java.go
@@ -243,7 +243,7 @@
jpkg := strings.Replace(ref.Pkg, "/", ".", -1)
super := jpkg + "." + ref.Name
if _, exists := j.clsMap[super]; !exists {
- return nil, fmt.Errorf("class %q not found", super)
+ return nil, fmt.Errorf("failed to find Java class %s, embedded by %s", super, n)
}
cls.Supers = append(cls.Supers, super)
}