in src/go/cmd/pkg.go [108:213]
func (p *Pkg) indexFile(f *ast.File) {
// map import aliases to full import paths e.g. "shared" => "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared"
imports := map[string]string{}
for _, imp := range f.Imports {
p := strings.Trim(imp.Path.Value, `"`)
if imp.Name != nil {
imports[imp.Name.String()] = p
} else {
imports[filepath.Base(p)] = p
}
}
ast.Inspect(f, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.FuncDecl:
p.c.addFunc(*p, x, imports)
// children can't be exported, let's not inspect them
return false
case *ast.GenDecl:
if x.Tok == token.CONST || x.Tok == token.VAR {
// const or var declaration
for _, s := range x.Specs {
p.c.addGenDecl(*p, x.Tok, s.(*ast.ValueSpec), imports)
}
}
case *ast.TypeSpec:
switch t := x.Type.(type) {
case *ast.ArrayType:
// "type UUID [16]byte"
txt := p.getText(t.Pos(), t.End())
p.types[x.Name.Name] = typeDef{n: x, p: p}
p.c.addSimpleType(*p, x.Name.Name, p.Name(), txt, imports)
case *ast.FuncType:
// "type PolicyFunc func(*Request) (*http.Response, error)"
txt := p.getText(t.Pos(), t.End())
p.types[x.Name.Name] = typeDef{n: x, p: p}
p.c.addSimpleType(*p, x.Name.Name, p.Name(), txt, imports)
case *ast.Ident:
// "type ETag string"
p.types[x.Name.Name] = typeDef{n: x, p: p}
p.c.addSimpleType(*p, x.Name.Name, p.Name(), t.Name, imports)
case *ast.IndexExpr, *ast.IndexListExpr:
// "type Client GenericClient[BaseClient]"
// "type Client CompositeClient[BaseClient1, BaseClient2]"
txt := p.getText(t.Pos(), t.End())
p.types[x.Name.Name] = typeDef{n: x, p: p}
p.c.addSimpleType(*p, x.Name.Name, p.Name(), txt, imports)
case *ast.InterfaceType:
p.types[x.Name.Name] = typeDef{n: x, p: p}
in := p.c.addInterface(*p, x.Name.Name, p.Name(), t, imports)
if in.Sealed {
p.diagnostics = append(p.diagnostics, CodeDiagnostic{
TargetID: in.ID(),
Level: CodeDiagnosticLevelInfo,
Text: sealedInterface,
})
}
case *ast.MapType:
// "type opValues map[reflect.Type]interface{}"
txt := p.getText(t.Pos(), t.End())
p.c.addSimpleType(*p, x.Name.Name, p.Name(), txt, imports)
case *ast.SelectorExpr:
if ident, ok := t.X.(*ast.Ident); ok {
if impPath, ok := imports[ident.Name]; ok {
// alias in the same module could use type navigator directly
if _, _, found := strings.Cut(impPath, p.modulePath); found && !strings.Contains(impPath, "internal") {
expr := p.getText(t.Pos(), t.End())
p.c.addSimpleType(*p, x.Name.Name, p.Name(), expr, imports)
}
// This is a re-exported type e.g. "type TokenCredential = shared.TokenCredential".
// Track it as an alias so we can later hoist its definition into this package.
ta := TypeAlias{
Name: x.Name.Name,
Package: p,
QualifiedName: impPath + "." + t.Sel.Name,
}
p.TypeAliases = append(p.TypeAliases, &ta)
} else {
// Non-SDK underlying type e.g. "type EDMDateTime time.Time". Handle it like a simple type
// because we don't want to hoist its definition into this package.
expr := p.getText(t.Pos(), t.End())
p.c.addSimpleType(*p, x.Name.Name, p.Name(), expr, imports)
}
}
case *ast.StructType:
p.types[x.Name.Name] = typeDef{n: x, p: p}
s := p.c.addStruct(*p, x.Name.Name, p.Name(), x, imports)
for _, t := range s.AnonymousFields {
// if t contains "." it must be exported
if !strings.Contains(t, ".") && unicode.IsLower(rune(t[0])) {
p.diagnostics = append(p.diagnostics, CodeDiagnostic{
Level: CodeDiagnosticLevelError,
TargetID: s.ID(),
Text: embedsUnexportedStruct + t,
})
}
}
default:
txt := p.getText(x.Pos(), x.End())
fmt.Printf("unhandled node type %T: %s\n", t, txt)
}
}
return true
})
}