blob: aa285e4c09447430597850e7e969cc529714799c [file]
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package api finds the API of a package: the set of exported
// symbols and their types.
package api
import (
"bytes"
"fmt"
"go/ast"
"go/printer"
"go/token"
"strings"
)
// typeString returns a string for the given type expression that represents the type.
// If two such strings are equal, then the corresponding types are equal.
// typeString returns "?" if typeExpr is nil.
func typeString(typeExpr ast.Expr) string {
switch t := typeExpr.(type) {
case nil:
return "?"
case *ast.FuncType:
return "func" + sigString(t)
default:
return nodeString(t)
}
}
// sigString returns a string representation of a function signature
// without parameter or return names (e.g., "(int, int) bool").
func sigString(ft *ast.FuncType) string {
if ft == nil {
return ""
}
paramTypes := fieldListTypes(ft.Params)
resTypes := fieldListTypes(ft.Results)
var buf strings.Builder
buf.WriteString("(")
buf.WriteString(strings.Join(paramTypes, ", "))
buf.WriteString(")")
if len(resTypes) == 1 {
buf.WriteString(" ")
buf.WriteString(resTypes[0])
} else if len(resTypes) > 1 {
buf.WriteString(" (")
buf.WriteString(strings.Join(resTypes, ", "))
buf.WriteString(")")
}
return buf.String()
}
// fieldListTypes returns the types of a field list, ignoring the field names.
// Note that "field" here means more than just a struct field: it could be
// the arguments or return values of a function.
func fieldListTypes(fl *ast.FieldList) []string {
if fl == nil {
return nil
}
var typeStrings []string
for _, f := range fl.List {
// convert "x, y, z T", to "T, T, T"
n := max(1, len(f.Names))
tstr := typeString(f.Type)
for i := 0; i < n; i++ {
typeStrings = append(typeStrings, tstr)
}
}
return typeStrings
}
// nodeString returns a string for node.
func nodeString(node ast.Node) string {
var buf bytes.Buffer
if err := printer.Fprint(&buf, token.NewFileSet(), node); err != nil {
return fmt.Sprintf("<ERROR:%s>", err)
}
return buf.String()
}