Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ jobs:
Test:
strategy:
matrix:
go-version: [1.16.x, 1.17.x, 1.18.x, 1.19.x]
os: [ubuntu-latest, windows-latest, macos-11]
go-version: [1.25.x, 1.26.x, 1.27.x]
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}

Expand Down
32 changes: 32 additions & 0 deletions astview/_testdata/basic/generic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package fixture

type Integer interface {
~int | ~int64
}

type Pair[A, B any] struct {
First A
Second B
}

type List[T any] []T

type Alias[T any] = List[T]

type Combiner[T, U any] interface {
Combine(T, U) T
}

func Identity[T any](v T) T { return v }

func Map[T, U any](xs []T, f func(T) U) []U {
out := make([]U, len(xs))
for i, x := range xs {
out[i] = f(x)
}
return out
}

func (p Pair[A, B]) FirstValue() A { return p.First }

var _ = Pair[string, int]{First: "x", Second: 1}
14 changes: 14 additions & 0 deletions astview/_testdata/basic/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package fixture

// Box stores a value of any type.
type Box[T any] struct {
Value T
}

type Reader interface {
Read() string
}

type Record struct {
Name string
}
10 changes: 10 additions & 0 deletions astview/_testdata/basic/usage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package fixture

import "fmt"

func (b Box[T]) Get() T { return b.Value }

func Use() string {
b := Box[string]{Value: "ok"}
return fmt.Sprint(Record{Name: b.Get()})
}
29 changes: 29 additions & 0 deletions astview/_testdata/basic/want.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@_testdata/basic/generic.go
@_testdata/basic/types.go
@_testdata/basic/usage.go
0,p,fixture
1,+m,Imports
2,mm,fmt,2:3:8
1,+v,Variables
2,v,_,0:32:5
1,+f,Functions
2,f,Identity[T any],0:20:1@func(v T) T
2,f,Map[T any, U any],0:22:1@func(xs []T, f func(T) U) []U
2,f,Use,2:7:1@func() string
1,t,Alias[T any],0:14:1
1,s,Box[T any],1:4:1
2,tm,Get,2:5:1@func() T
2,tv,Value,1:5:2@T
1,i,Combiner[T any, U any],0:16:1
2,tm,Combine,0:17:9@Combine
1,i,Integer,0:3:1
2,t,~int | ~int64,0:4:2@~int | ~int64
1,t,List[T any],0:12:1
1,s,Pair[A any, B any],0:7:1
2,tm,FirstValue,0:30:1@func() A
2,tv,First,0:8:2@A
2,tv,Second,0:9:2@B
1,i,Reader,1:8:1
2,tm,Read,1:9:6@Read
1,s,Record,1:12:1
2,tv,Name,1:13:2@string
33 changes: 0 additions & 33 deletions astview/ast_go117.go

This file was deleted.

65 changes: 0 additions & 65 deletions astview/ast_go118.go

This file was deleted.

63 changes: 55 additions & 8 deletions astview/astview.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,53 @@ var (
astViewSep string
)

func docBaseTypeName(typ ast.Expr, showAll bool) string {
name, _ := recvTypeName(typ, showAll)
return name
}

func recvTypeName(typ ast.Expr, showAll bool) (string, bool) {
switch t := typ.(type) {
case *ast.Ident:
if showAll || t.IsExported() {
return t.Name, false
}
case *ast.StarExpr:
return docBaseTypeName(t.X, showAll), true
case *ast.IndexExpr:
return docBaseTypeName(t.X, showAll), false
case *ast.IndexListExpr:
return docBaseTypeName(t.X, showAll), false
}
return "", false
}

func typeName(d *ast.TypeSpec, showTypeParams bool) string {
if showTypeParams && d.TypeParams != nil {
var params []string
for _, field := range d.TypeParams.List {
for _, name := range field.Names {
params = append(params, name.String()+" "+types.ExprString(field.Type))
}
}
return d.Name.String() + "[" + strings.Join(params, ", ") + "]"
}
return d.Name.String()
}

func funcName(d *ast.FuncDecl, showTypeParams bool) string {
if showTypeParams && d.Type.TypeParams != nil {
var params []string
for _, field := range d.Type.TypeParams.List {
for _, name := range field.Names {
params = append(params, name.String()+" "+types.ExprString(field.Type))
}
}
return d.Name.String() + "[" + strings.Join(params, ", ") + "]"
}
return d.Name.String()
}

func init() {
Command.Flag.BoolVar(&astViewStdin, "stdin", false, "input from stdin")
Command.Flag.BoolVar(&astViewShowEndPos, "end", false, "show decl end pos")
Expand Down Expand Up @@ -138,10 +185,10 @@ func NewFilePackage(filename string) (*PackageView, error) {
}
m := make(map[string]*ast.File)
m[filename] = file
pkg, err := ast.NewPackage(p.fset, m, nil, nil)
if err != nil {
return nil, err
}
// ast.NewPackage reports predeclared identifiers such as `any` as
// undeclared when no universe scope is supplied. The documentation view
// only needs the parsed files, so avoid the deprecated resolver here.
pkg := &ast.Package{Name: file.Name.Name, Files: m}
p.pkg = pkg
p.pdoc = NewPackageDoc(pkg, pkg.Name, true)
return p, nil
Expand Down Expand Up @@ -221,10 +268,10 @@ func NewFilePackageSource(filename string, f io.Reader, expr bool) (*PackageView
}
m := make(map[string]*ast.File)
m[filename] = file
pkg, err := ast.NewPackage(p.fset, m, nil, nil)
if err != nil {
return nil, err
}
// ast.NewPackage reports predeclared identifiers such as `any` as
// undeclared when no universe scope is supplied. The documentation view
// only needs the parsed files, so avoid the deprecated resolver here.
pkg := &ast.Package{Name: file.Name.Name, Files: m}

p.pdoc = NewPackageDoc(pkg, pkg.Name, true)
return p, nil
Expand Down
52 changes: 52 additions & 0 deletions astview/astview_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//go:build go1.18
// +build go1.18

package astview

import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
)

func TestFiles(t *testing.T) {
dir := filepath.Join("_testdata", "basic")
files, err := filepath.Glob(filepath.Join(dir, "*.go"))
if err != nil {
t.Fatal(err)
}
if len(files) == 0 {
t.Fatal("no testdata Go files")
}
var got bytes.Buffer
AllFiles = nil
astViewShowTypeParams = true
defer func() { astViewShowTypeParams = false }()
if err := PrintFilesTree(files, &got, true); err != nil {
t.Fatalf("print files tree: %v", err)
}
want, err := os.ReadFile(filepath.Join(dir, "want.txt"))
if err != nil {
t.Fatal(err)
}
gotText := strings.ReplaceAll(strings.TrimSpace(got.String()), "\\", "/")
wantText := strings.TrimSpace(strings.ReplaceAll(strings.ReplaceAll(string(want), "\r\n", "\n"), "\\", "/"))
if gotText != wantText {
t.Fatalf("file tree mismatch\n got:\n%s\nwant:\n%s", got.String(), want)
}
}

func TestGenericSource(t *testing.T) {
src := strings.NewReader("package p\n\ntype Pair[A, B any] struct { A A; B B }\n")
view, err := NewFilePackageSource("stdin.go", src, true)
if err != nil {
t.Fatalf("parse generic source: %v", err)
}
var out strings.Builder
view.PrintTree(&out)
if !strings.Contains(out.String(), "Pair") {
t.Fatalf("generic type missing from output: %s", out.String())
}
}
18 changes: 18 additions & 0 deletions docview/_testdata/basic/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Package fixture demonstrates documentation extraction.
package fixture

import "fmt"

// Identity returns its argument.
func Identity[T any](v T) T { return v }

// Box stores one value.
type Box[T any] struct {
Value T
}

// Get returns the stored value.
func (b Box[T]) Get() T { return b.Value }

// Format formats a value.
func Format[T any](v T) string { return fmt.Sprint(v) }
10 changes: 10 additions & 0 deletions docview/_testdata/basic/extra.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package fixture

// Pair contains two values.
type Pair[A, B any] struct {
First A
Second B
}

// NewPair constructs a Pair.
func NewPair[A, B any](a A, b B) Pair[A, B] { return Pair[A, B]{a, b} }
9 changes: 9 additions & 0 deletions docview/_testdata/basic/want.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package|fixture
doc|Package fixture demonstrates documentation extraction.
import|fmt
type|Box|Box stores one value.
method|Box|Get|Get returns the stored value.
type|Pair|Pair contains two values.
func|Format|Format formats a value.
func|Identity|Identity returns its argument.
factory|Pair|NewPair|NewPair constructs a Pair.
Loading
Loading