From fc85376de57560df1cec1470b4293e476985a2a3 Mon Sep 17 00:00:00 2001 From: Samuel Marks <807580+SamuelMarks@users.noreply.github.com> Date: Sat, 24 Jan 2026 11:27:08 -0500 Subject: [PATCH 1/3] Upgrade dependencies, `go fmt`, fixed whitespace handling, switched to GitHub Actions --- .github/workflows/ci.yml | 21 ++ .travis.yml | 15 -- README.md | 8 +- README.md.tpl | 8 +- decorations-types-generated.go | 404 ++++++++++++++------------------ decorations_test.go | 47 ++-- decorator/decorator-fragment.go | 72 +++++- decorator/decorator_test.go | 315 +++++++++++++------------ decorator/restorer_std_test.go | 8 +- dst.go | 1 - dstutil/rewrite.go | 5 +- go.mod | 10 +- go.sum | 50 +--- readme.go | 2 +- resolve.go | 1 - scope.go | 4 - walk.go | 2 - 17 files changed, 486 insertions(+), 487 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c1e6e86 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,21 @@ +name: go test + +on: + push: + branches: ["master"] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + go-version: [ '1.25' ] + + steps: + - uses: actions/checkout@v6 + - name: Setup Go ${{ matrix.go-version }} + uses: actions/setup-go@v6 + with: + go-version: ${{ matrix.go-version }} + - name: go test + run: go test ./... -v diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f2af053..0000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: go -go: - - 1.x -notificaitons: - email: - recipients: dave@brophy.uk - on_failure: always -install: -# - go get -u github.com/dave/courtney - - go get -t -v ./... -script: - - go test ./... -# - courtney -v -timeout 20m -#after_success: -# - bash <(curl -s https://codecov.io/bash) diff --git a/README.md b/README.md index 337781b..c004bb2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,4 @@ -[![Build Status](https://travis-ci.org/dave/dst.svg?branch=master)](https://travis-ci.org/dave/dst) -[![Documentation](https://img.shields.io/badge/godoc-documentation-brightgreen.svg)](https://godoc.org/github.com/dave/dst/decorator) -[![codecov](https://img.shields.io/badge/codecov-92%25-brightgreen.svg)](https://codecov.io/gh/dave/dst) -![stability-stable](https://img.shields.io/badge/stability-stable-brightgreen.svg) -[![Sourcegraph](https://sourcegraph.com/github.com/dave/dst/-/badge.svg)](https://sourcegraph.com/github.com/dave/dst?badge) +[![go test](https://github.com/SamuelMarks/dst/actions/workflows/ci.yml/badge.svg)](https://github.com/SamuelMarks/dst/actions/workflows/ci.yml) # Decorated Syntax Tree @@ -703,4 +699,4 @@ For further developing or contributing to `dst`, check out [these notes](https:/ ## Special thanks -Thanks very much to [hawkinsw](https://github.com/hawkinsw) for taking on the task of adding generics compatibility to `dst`. \ No newline at end of file +Thanks very much to [hawkinsw](https://github.com/hawkinsw) for taking on the task of adding generics compatibility to `dst`. diff --git a/README.md.tpl b/README.md.tpl index 26691f9..83c288d 100644 --- a/README.md.tpl +++ b/README.md.tpl @@ -1,8 +1,4 @@ -[![Build Status](https://travis-ci.org/dave/dst.svg?branch=master)](https://travis-ci.org/dave/dst) -[![Documentation](https://img.shields.io/badge/godoc-documentation-brightgreen.svg)](https://godoc.org/github.com/dave/dst/decorator) -[![codecov](https://img.shields.io/badge/codecov-92%25-brightgreen.svg)](https://codecov.io/gh/dave/dst) -![stability-stable](https://img.shields.io/badge/stability-stable-brightgreen.svg) -[![Sourcegraph](https://sourcegraph.com/github.com/dave/dst/-/badge.svg)](https://sourcegraph.com/github.com/dave/dst?badge) +[![go test](https://github.com/SamuelMarks/dst/actions/workflows/ci.yml/badge.svg)](https://github.com/SamuelMarks/dst/actions/workflows/ci.yml) # Decorated Syntax Tree @@ -236,4 +232,4 @@ For further developing or contributing to `dst`, check out [these notes](https:/ ## Special thanks -Thanks very much to [hawkinsw](https://github.com/hawkinsw) for taking on the task of adding generics compatibility to `dst`. \ No newline at end of file +Thanks very much to [hawkinsw](https://github.com/hawkinsw) for taking on the task of adding generics compatibility to `dst`. diff --git a/decorations-types-generated.go b/decorations-types-generated.go index 2105eb6..4381b8c 100644 --- a/decorations-types-generated.go +++ b/decorations-types-generated.go @@ -2,8 +2,7 @@ package dst // ArrayTypeDecorations holds decorations for ArrayType: // -// type R /*Start*/ [ /*Lbrack*/ 1] /*Len*/ int /*End*/ -// +// type R /*Start*/ [ /*Lbrack*/ 1] /*Len*/ int /*End*/ type ArrayTypeDecorations struct { NodeDecs Lbrack Decorations @@ -12,42 +11,36 @@ type ArrayTypeDecorations struct { // AssignStmtDecorations holds decorations for AssignStmt: // -// /*Start*/ -// i = /*Tok*/ 1 /*End*/ -// +// /*Start*/ +// i = /*Tok*/ 1 /*End*/ type AssignStmtDecorations struct { NodeDecs Tok Decorations } // BadDeclDecorations holds decorations for BadDecl: -// type BadDeclDecorations struct { NodeDecs } // BadExprDecorations holds decorations for BadExpr: -// type BadExprDecorations struct { NodeDecs } // BadStmtDecorations holds decorations for BadStmt: -// type BadStmtDecorations struct { NodeDecs } // BasicLitDecorations holds decorations for BasicLit: -// type BasicLitDecorations struct { NodeDecs } // BinaryExprDecorations holds decorations for BinaryExpr: // -// var P = /*Start*/ 1 /*X*/ & /*Op*/ 2 /*End*/ -// +// var P = /*Start*/ 1 /*X*/ & /*Op*/ 2 /*End*/ type BinaryExprDecorations struct { NodeDecs X Decorations @@ -56,12 +49,11 @@ type BinaryExprDecorations struct { // BlockStmtDecorations holds decorations for BlockStmt: // -// if true /*Start*/ { /*Lbrace*/ -// i++ -// } /*End*/ -// -// func() /*Start*/ { /*Lbrace*/ i++ } /*End*/ () +// if true /*Start*/ { /*Lbrace*/ +// i++ +// } /*End*/ // +// func() /*Start*/ { /*Lbrace*/ i++ } /*End*/ () type BlockStmtDecorations struct { NodeDecs Lbrace Decorations @@ -69,9 +61,8 @@ type BlockStmtDecorations struct { // BranchStmtDecorations holds decorations for BranchStmt: // -// /*Start*/ -// goto /*Tok*/ A /*End*/ -// +// /*Start*/ +// goto /*Tok*/ A /*End*/ type BranchStmtDecorations struct { NodeDecs Tok Decorations @@ -79,8 +70,7 @@ type BranchStmtDecorations struct { // CallExprDecorations holds decorations for CallExpr: // -// var L = /*Start*/ C /*Fun*/ ( /*Lparen*/ 0, []int{}... /*Ellipsis*/) /*End*/ -// +// var L = /*Start*/ C /*Fun*/ ( /*Lparen*/ 0, []int{}... /*Ellipsis*/) /*End*/ type CallExprDecorations struct { NodeDecs Fun Decorations @@ -90,11 +80,10 @@ type CallExprDecorations struct { // CaseClauseDecorations holds decorations for CaseClause: // -// switch i { -// /*Start*/ case /*Case*/ 1: /*Colon*/ -// i++ /*End*/ -// } -// +// switch i { +// /*Start*/ case /*Case*/ 1: /*Colon*/ +// i++ /*End*/ +// } type CaseClauseDecorations struct { NodeDecs Case Decorations @@ -103,12 +92,11 @@ type CaseClauseDecorations struct { // ChanTypeDecorations holds decorations for ChanType: // -// type W /*Start*/ chan /*Begin*/ int /*End*/ -// -// type X /*Start*/ <-chan /*Begin*/ int /*End*/ +// type W /*Start*/ chan /*Begin*/ int /*End*/ // -// type Y /*Start*/ chan /*Begin*/ <- /*Arrow*/ int /*End*/ +// type X /*Start*/ <-chan /*Begin*/ int /*End*/ // +// type Y /*Start*/ chan /*Begin*/ <- /*Arrow*/ int /*End*/ type ChanTypeDecorations struct { NodeDecs Begin Decorations @@ -117,11 +105,10 @@ type ChanTypeDecorations struct { // CommClauseDecorations holds decorations for CommClause: // -// select { -// /*Start*/ case /*Case*/ a := <-c /*Comm*/ : /*Colon*/ -// print(a) /*End*/ -// } -// +// select { +// /*Start*/ case /*Case*/ a := <-c /*Comm*/ : /*Colon*/ +// print(a) /*End*/ +// } type CommClauseDecorations struct { NodeDecs Case Decorations @@ -131,8 +118,7 @@ type CommClauseDecorations struct { // CompositeLitDecorations holds decorations for CompositeLit: // -// var D = /*Start*/ A /*Type*/ { /*Lbrace*/ A: 0} /*End*/ -// +// var D = /*Start*/ A /*Type*/ { /*Lbrace*/ A: 0} /*End*/ type CompositeLitDecorations struct { NodeDecs Type Decorations @@ -140,16 +126,14 @@ type CompositeLitDecorations struct { } // DeclStmtDecorations holds decorations for DeclStmt: -// type DeclStmtDecorations struct { NodeDecs } // DeferStmtDecorations holds decorations for DeferStmt: // -// /*Start*/ -// defer /*Defer*/ func() {}() /*End*/ -// +// /*Start*/ +// defer /*Defer*/ func() {}() /*End*/ type DeferStmtDecorations struct { NodeDecs Defer Decorations @@ -157,31 +141,27 @@ type DeferStmtDecorations struct { // EllipsisDecorations holds decorations for Ellipsis: // -// func B(a /*Start*/ ... /*Ellipsis*/ int /*End*/) {} -// +// func B(a /*Start*/ ... /*Ellipsis*/ int /*End*/) {} type EllipsisDecorations struct { NodeDecs Ellipsis Decorations } // EmptyStmtDecorations holds decorations for EmptyStmt: -// type EmptyStmtDecorations struct { NodeDecs } // ExprStmtDecorations holds decorations for ExprStmt: -// type ExprStmtDecorations struct { NodeDecs } // FieldDecorations holds decorations for Field: // -// type A struct { -// /*Start*/ A int /*Type*/ `a:"a"` /*End*/ -// } -// +// type A struct { +// /*Start*/ A int /*Type*/ `a:"a"` /*End*/ +// } type FieldDecorations struct { NodeDecs Type Decorations @@ -189,11 +169,10 @@ type FieldDecorations struct { // FieldListDecorations holds decorations for FieldList: // -// type A1 struct /*Start*/ { /*Opening*/ -// a, b int -// c string -// } /*End*/ -// +// type A1 struct /*Start*/ { /*Opening*/ +// a, b int +// c string +// } /*End*/ type FieldListDecorations struct { NodeDecs Opening Decorations @@ -201,8 +180,7 @@ type FieldListDecorations struct { // FileDecorations holds decorations for File: // -// /*Start*/ package /*Package*/ data /*Name*/ -// +// /*Start*/ package /*Package*/ data /*Name*/ type FileDecorations struct { NodeDecs Package Decorations @@ -211,21 +189,20 @@ type FileDecorations struct { // ForStmtDecorations holds decorations for ForStmt: // -// /*Start*/ -// for /*For*/ { -// i++ -// } /*End*/ -// -// /*Start*/ -// for /*For*/ i < 1 /*Cond*/ { -// i++ -// } /*End*/ +// /*Start*/ +// for /*For*/ { +// i++ +// } /*End*/ // -// /*Start*/ -// for /*For*/ i = 0; /*Init*/ i < 10; /*Cond*/ i++ /*Post*/ { -// i++ -// } /*End*/ +// /*Start*/ +// for /*For*/ i < 1 /*Cond*/ { +// i++ +// } /*End*/ // +// /*Start*/ +// for /*For*/ i = 0; /*Init*/ i < 10; /*Cond*/ i++ /*Post*/ { +// i++ +// } /*End*/ type ForStmtDecorations struct { NodeDecs For Decorations @@ -236,26 +213,25 @@ type ForStmtDecorations struct { // FuncDeclDecorations holds decorations for FuncDecl: // -// /*Start*/ -// func /*Func*/ d /*Name*/ (d, e int) /*Params*/ { -// return -// } /*End*/ -// -// /*Start*/ -// func /*Func*/ TP /*Name*/ [P any] /*TypeParams*/ (a int) /*Params*/ (b P) /*Results*/ { -// return b -// } /*End*/ -// -// /*Start*/ -// func /*Func*/ (a *A) /*Recv*/ e /*Name*/ (d, e int) /*Params*/ { -// return -// } /*End*/ -// -// /*Start*/ -// func /*Func*/ (a *A) /*Recv*/ f /*Name*/ (d, e int) /*Params*/ (f, g int) /*Results*/ { -// return -// } /*End*/ -// +// /*Start*/ +// func /*Func*/ d /*Name*/ (d, e int) /*Params*/ { +// return +// } /*End*/ +// +// /*Start*/ +// func /*Func*/ TP /*Name*/ [P any] /*TypeParams*/ (a int) /*Params*/ (b P) /*Results*/ { +// return b +// } /*End*/ +// +// /*Start*/ +// func /*Func*/ (a *A) /*Recv*/ e /*Name*/ (d, e int) /*Params*/ { +// return +// } /*End*/ +// +// /*Start*/ +// func /*Func*/ (a *A) /*Recv*/ f /*Name*/ (d, e int) /*Params*/ (f, g int) /*Results*/ { +// return +// } /*End*/ type FuncDeclDecorations struct { NodeDecs Func Decorations @@ -268,8 +244,7 @@ type FuncDeclDecorations struct { // FuncLitDecorations holds decorations for FuncLit: // -// var C = /*Start*/ func(a int, b ...int) (c int) /*Type*/ { return 0 } /*End*/ -// +// var C = /*Start*/ func(a int, b ...int) (c int) /*Type*/ { return 0 } /*End*/ type FuncLitDecorations struct { NodeDecs Type Decorations @@ -277,8 +252,7 @@ type FuncLitDecorations struct { // FuncTypeDecorations holds decorations for FuncType: // -// type T /*Start*/ func /*Func*/ (a int) /*Params*/ (b int) /*End*/ -// +// type T /*Start*/ func /*Func*/ (a int) /*Params*/ (b int) /*End*/ type FuncTypeDecorations struct { NodeDecs Func Decorations @@ -288,15 +262,14 @@ type FuncTypeDecorations struct { // GenDeclDecorations holds decorations for GenDecl: // -// /*Start*/ -// const /*Tok*/ ( /*Lparen*/ -// a, b = 1, 2 -// c = 3 -// ) /*End*/ -// -// /*Start*/ -// const /*Tok*/ d = 1 /*End*/ +// /*Start*/ +// const /*Tok*/ ( /*Lparen*/ +// a, b = 1, 2 +// c = 3 +// ) /*End*/ // +// /*Start*/ +// const /*Tok*/ d = 1 /*End*/ type GenDeclDecorations struct { NodeDecs Tok Decorations @@ -305,9 +278,8 @@ type GenDeclDecorations struct { // GoStmtDecorations holds decorations for GoStmt: // -// /*Start*/ -// go /*Go*/ func() {}() /*End*/ -// +// /*Start*/ +// go /*Go*/ func() {}() /*End*/ type GoStmtDecorations struct { NodeDecs Go Decorations @@ -315,12 +287,11 @@ type GoStmtDecorations struct { // IdentDecorations holds decorations for Ident: // -// /*Start*/ -// i /*End*/ ++ -// -// /*Start*/ -// fmt. /*X*/ Print /*End*/ () +// /*Start*/ +// i /*End*/ ++ // +// /*Start*/ +// fmt. /*X*/ Print /*End*/ () type IdentDecorations struct { NodeDecs X Decorations @@ -328,13 +299,12 @@ type IdentDecorations struct { // IfStmtDecorations holds decorations for IfStmt: // -// /*Start*/ -// if /*If*/ a := b; /*Init*/ a /*Cond*/ { -// i++ -// } else /*Else*/ { -// i++ -// } /*End*/ -// +// /*Start*/ +// if /*If*/ a := b; /*Init*/ a /*Cond*/ { +// i++ +// } else /*Else*/ { +// i++ +// } /*End*/ type IfStmtDecorations struct { NodeDecs If Decorations @@ -345,10 +315,9 @@ type IfStmtDecorations struct { // ImportSpecDecorations holds decorations for ImportSpec: // -// import ( -// /*Start*/ fmt /*Name*/ "fmt" /*End*/ -// ) -// +// import ( +// /*Start*/ fmt /*Name*/ "fmt" /*End*/ +// ) type ImportSpecDecorations struct { NodeDecs Name Decorations @@ -356,9 +325,8 @@ type ImportSpecDecorations struct { // IncDecStmtDecorations holds decorations for IncDecStmt: // -// /*Start*/ -// i /*X*/ ++ /*End*/ -// +// /*Start*/ +// i /*X*/ ++ /*End*/ type IncDecStmtDecorations struct { NodeDecs X Decorations @@ -366,8 +334,7 @@ type IncDecStmtDecorations struct { // IndexExprDecorations holds decorations for IndexExpr: // -// var G = /*Start*/ []int{0} /*X*/ [ /*Lbrack*/ 0 /*Index*/] /*End*/ -// +// var G = /*Start*/ []int{0} /*X*/ [ /*Lbrack*/ 0 /*Index*/] /*End*/ type IndexExprDecorations struct { NodeDecs X Decorations @@ -377,8 +344,7 @@ type IndexExprDecorations struct { // IndexListExprDecorations holds decorations for IndexListExpr: // -// var T4 /*Start*/ T3 /*X*/ [ /*Lbrack*/ int, string /*Indices*/] /*End*/ -// +// var T4 /*Start*/ T3 /*X*/ [ /*Lbrack*/ int, string /*Indices*/] /*End*/ type IndexListExprDecorations struct { NodeDecs X Decorations @@ -388,10 +354,9 @@ type IndexListExprDecorations struct { // InterfaceTypeDecorations holds decorations for InterfaceType: // -// type U /*Start*/ interface /*Interface*/ { -// A() -// } /*End*/ -// +// type U /*Start*/ interface /*Interface*/ { +// A() +// } /*End*/ type InterfaceTypeDecorations struct { NodeDecs Interface Decorations @@ -399,10 +364,9 @@ type InterfaceTypeDecorations struct { // KeyValueExprDecorations holds decorations for KeyValueExpr: // -// var Q = map[string]string{ -// /*Start*/ "a" /*Key*/ : /*Colon*/ "a", /*End*/ -// } -// +// var Q = map[string]string{ +// /*Start*/ "a" /*Key*/ : /*Colon*/ "a", /*End*/ +// } type KeyValueExprDecorations struct { NodeDecs Key Decorations @@ -411,10 +375,9 @@ type KeyValueExprDecorations struct { // LabeledStmtDecorations holds decorations for LabeledStmt: // -// /*Start*/ -// A /*Label*/ : /*Colon*/ -// print("Stmt") /*End*/ -// +// /*Start*/ +// A /*Label*/ : /*Colon*/ +// print("Stmt") /*End*/ type LabeledStmtDecorations struct { NodeDecs Label Decorations @@ -423,8 +386,7 @@ type LabeledStmtDecorations struct { // MapTypeDecorations holds decorations for MapType: // -// type V /*Start*/ map[ /*Map*/ int] /*Key*/ int /*End*/ -// +// type V /*Start*/ map[ /*Map*/ int] /*Key*/ int /*End*/ type MapTypeDecorations struct { NodeDecs Map Decorations @@ -432,15 +394,13 @@ type MapTypeDecorations struct { } // PackageDecorations holds decorations for Package: -// type PackageDecorations struct { NodeDecs } // ParenExprDecorations holds decorations for ParenExpr: // -// var E = /*Start*/ ( /*Lparen*/ 1 + 1 /*X*/) /*End*/ / 2 -// +// var E = /*Start*/ ( /*Lparen*/ 1 + 1 /*X*/) /*End*/ / 2 type ParenExprDecorations struct { NodeDecs Lparen Decorations @@ -449,20 +409,19 @@ type ParenExprDecorations struct { // RangeStmtDecorations holds decorations for RangeStmt: // -// /*Start*/ -// for range /*Range*/ a /*X*/ { -// } /*End*/ -// -// /*Start*/ -// for /*For*/ k /*Key*/ := range /*Range*/ a /*X*/ { -// print(k) -// } /*End*/ +// /*Start*/ +// for range /*Range*/ a /*X*/ { +// } /*End*/ // -// /*Start*/ -// for /*For*/ k /*Key*/, v /*Value*/ := range /*Range*/ a /*X*/ { -// print(k, v) -// } /*End*/ +// /*Start*/ +// for /*For*/ k /*Key*/ := range /*Range*/ a /*X*/ { +// print(k) +// } /*End*/ // +// /*Start*/ +// for /*For*/ k /*Key*/, v /*Value*/ := range /*Range*/ a /*X*/ { +// print(k, v) +// } /*End*/ type RangeStmtDecorations struct { NodeDecs For Decorations @@ -474,10 +433,9 @@ type RangeStmtDecorations struct { // ReturnStmtDecorations holds decorations for ReturnStmt: // -// func() int { -// /*Start*/ return /*Return*/ 1 /*End*/ -// }() -// +// func() int { +// /*Start*/ return /*Return*/ 1 /*End*/ +// }() type ReturnStmtDecorations struct { NodeDecs Return Decorations @@ -485,10 +443,9 @@ type ReturnStmtDecorations struct { // SelectStmtDecorations holds decorations for SelectStmt: // -// /*Start*/ -// select /*Select*/ { -// } /*End*/ -// +// /*Start*/ +// select /*Select*/ { +// } /*End*/ type SelectStmtDecorations struct { NodeDecs Select Decorations @@ -496,8 +453,7 @@ type SelectStmtDecorations struct { // SelectorExprDecorations holds decorations for SelectorExpr: // -// var F = /*Start*/ tt. /*X*/ F /*End*/ () -// +// var F = /*Start*/ tt. /*X*/ F /*End*/ () type SelectorExprDecorations struct { NodeDecs X Decorations @@ -505,9 +461,8 @@ type SelectorExprDecorations struct { // SendStmtDecorations holds decorations for SendStmt: // -// /*Start*/ -// c /*Chan*/ <- /*Arrow*/ 0 /*End*/ -// +// /*Start*/ +// c /*Chan*/ <- /*Arrow*/ 0 /*End*/ type SendStmtDecorations struct { NodeDecs Chan Decorations @@ -516,18 +471,17 @@ type SendStmtDecorations struct { // SliceExprDecorations holds decorations for SliceExpr: // -// var H = /*Start*/ []int{0, 1, 2} /*X*/ [ /*Lbrack*/ 1: /*Low*/ 2: /*High*/ 3 /*Max*/] /*End*/ -// -// var H1 = /*Start*/ []int{0, 1, 2} /*X*/ [ /*Lbrack*/ 1: /*Low*/ 2 /*High*/] /*End*/ +// var H = /*Start*/ []int{0, 1, 2} /*X*/ [ /*Lbrack*/ 1: /*Low*/ 2: /*High*/ 3 /*Max*/] /*End*/ // -// var H2 = /*Start*/ []int{0} /*X*/ [: /*Low*/] /*End*/ +// var H1 = /*Start*/ []int{0, 1, 2} /*X*/ [ /*Lbrack*/ 1: /*Low*/ 2 /*High*/] /*End*/ // -// var H3 = /*Start*/ []int{0} /*X*/ [ /*Lbrack*/ 1: /*Low*/] /*End*/ +// var H2 = /*Start*/ []int{0} /*X*/ [: /*Low*/] /*End*/ // -// var H4 = /*Start*/ []int{0, 1, 2} /*X*/ [: /*Low*/ 2 /*High*/] /*End*/ +// var H3 = /*Start*/ []int{0} /*X*/ [ /*Lbrack*/ 1: /*Low*/] /*End*/ // -// var H5 = /*Start*/ []int{0, 1, 2} /*X*/ [: /*Low*/ 2: /*High*/ 3 /*Max*/] /*End*/ +// var H4 = /*Start*/ []int{0, 1, 2} /*X*/ [: /*Low*/ 2 /*High*/] /*End*/ // +// var H5 = /*Start*/ []int{0, 1, 2} /*X*/ [: /*Low*/ 2: /*High*/ 3 /*Max*/] /*End*/ type SliceExprDecorations struct { NodeDecs X Decorations @@ -539,8 +493,7 @@ type SliceExprDecorations struct { // StarExprDecorations holds decorations for StarExpr: // -// var N = /*Start*/ * /*Star*/ p /*End*/ -// +// var N = /*Start*/ * /*Star*/ p /*End*/ type StarExprDecorations struct { NodeDecs Star Decorations @@ -548,10 +501,9 @@ type StarExprDecorations struct { // StructTypeDecorations holds decorations for StructType: // -// type S /*Start*/ struct /*Struct*/ { -// A int -// } /*End*/ -// +// type S /*Start*/ struct /*Struct*/ { +// A int +// } /*End*/ type StructTypeDecorations struct { NodeDecs Struct Decorations @@ -559,14 +511,13 @@ type StructTypeDecorations struct { // SwitchStmtDecorations holds decorations for SwitchStmt: // -// /*Start*/ -// switch /*Switch*/ i /*Tag*/ { -// } /*End*/ -// -// /*Start*/ -// switch /*Switch*/ a := i; /*Init*/ a /*Tag*/ { -// } /*End*/ +// /*Start*/ +// switch /*Switch*/ i /*Tag*/ { +// } /*End*/ // +// /*Start*/ +// switch /*Switch*/ a := i; /*Init*/ a /*Tag*/ { +// } /*End*/ type SwitchStmtDecorations struct { NodeDecs Switch Decorations @@ -576,8 +527,7 @@ type SwitchStmtDecorations struct { // TypeAssertExprDecorations holds decorations for TypeAssertExpr: // -// var J = /*Start*/ f. /*X*/ ( /*Lparen*/ int /*Type*/) /*End*/ -// +// var J = /*Start*/ f. /*X*/ ( /*Lparen*/ int /*Type*/) /*End*/ type TypeAssertExprDecorations struct { NodeDecs X Decorations @@ -587,18 +537,17 @@ type TypeAssertExprDecorations struct { // TypeSpecDecorations holds decorations for TypeSpec: // -// type ( -// /*Start*/ T1 /*Name*/ []int /*End*/ -// ) -// -// type ( -// /*Start*/ T2 = /*Name*/ T1 /*End*/ -// ) +// type ( +// /*Start*/ T1 /*Name*/ []int /*End*/ +// ) // -// type ( -// /*Start*/ T3 /*Name*/ [P any, Q any] /*TypeParams*/ []P /*End*/ -// ) +// type ( +// /*Start*/ T2 = /*Name*/ T1 /*End*/ +// ) // +// type ( +// /*Start*/ T3 /*Name*/ [P any, Q any] /*TypeParams*/ []P /*End*/ +// ) type TypeSpecDecorations struct { NodeDecs Name Decorations @@ -607,22 +556,21 @@ type TypeSpecDecorations struct { // TypeSwitchStmtDecorations holds decorations for TypeSwitchStmt: // -// /*Start*/ -// switch /*Switch*/ f.(type) /*Assign*/ { -// } /*End*/ -// -// /*Start*/ -// switch /*Switch*/ g := f.(type) /*Assign*/ { -// case int: -// print(g) -// } /*End*/ -// -// /*Start*/ -// switch /*Switch*/ g := f; /*Init*/ g := g.(type) /*Assign*/ { -// case int: -// print(g) -// } /*End*/ -// +// /*Start*/ +// switch /*Switch*/ f.(type) /*Assign*/ { +// } /*End*/ +// +// /*Start*/ +// switch /*Switch*/ g := f.(type) /*Assign*/ { +// case int: +// print(g) +// } /*End*/ +// +// /*Start*/ +// switch /*Switch*/ g := f; /*Init*/ g := g.(type) /*Assign*/ { +// case int: +// print(g) +// } /*End*/ type TypeSwitchStmtDecorations struct { NodeDecs Switch Decorations @@ -632,8 +580,7 @@ type TypeSwitchStmtDecorations struct { // UnaryExprDecorations holds decorations for UnaryExpr: // -// var O = /*Start*/ ^ /*Op*/ 1 /*End*/ -// +// var O = /*Start*/ ^ /*Op*/ 1 /*End*/ type UnaryExprDecorations struct { NodeDecs Op Decorations @@ -641,18 +588,17 @@ type UnaryExprDecorations struct { // ValueSpecDecorations holds decorations for ValueSpec: // -// var ( -// /*Start*/ j = /*Assign*/ 1 /*End*/ -// ) -// -// var ( -// /*Start*/ k, l = /*Assign*/ 1, 2 /*End*/ -// ) +// var ( +// /*Start*/ j = /*Assign*/ 1 /*End*/ +// ) // -// var ( -// /*Start*/ m, n int = /*Assign*/ 1, 2 /*End*/ -// ) +// var ( +// /*Start*/ k, l = /*Assign*/ 1, 2 /*End*/ +// ) // +// var ( +// /*Start*/ m, n int = /*Assign*/ 1, 2 /*End*/ +// ) type ValueSpecDecorations struct { NodeDecs Assign Decorations diff --git a/decorations_test.go b/decorations_test.go index 0cf02ce..7a5eafe 100644 --- a/decorations_test.go +++ b/decorations_test.go @@ -21,6 +21,7 @@ import ( "golang.org/x/tools/go/packages" ) +// TestDecorations_All tests the All method of Decorations. func TestDecorations_All(t *testing.T) { d := &dst.Decorations{"a", "b"} expected := "[a b]" @@ -30,6 +31,7 @@ func TestDecorations_All(t *testing.T) { } } +// TestDecorations_Append tests the Append method of Decorations. func TestDecorations_Append(t *testing.T) { d := &dst.Decorations{"a", "b"} d.Append("c") @@ -40,6 +42,7 @@ func TestDecorations_Append(t *testing.T) { } } +// TestDecorations_Clear tests the Clear method of Decorations. func TestDecorations_Clear(t *testing.T) { d := &dst.Decorations{"a", "b"} d.Clear() @@ -50,6 +53,7 @@ func TestDecorations_Clear(t *testing.T) { } } +// TestDecorations_Replace tests the Replace method of Decorations. func TestDecorations_Replace(t *testing.T) { d := &dst.Decorations{"a", "b"} d.Replace("c") @@ -60,6 +64,7 @@ func TestDecorations_Replace(t *testing.T) { } } +// TestDecorations_Prepend tests the Prepend method of Decorations. func TestDecorations_Prepend(t *testing.T) { d := &dst.Decorations{"a", "b"} d.Prepend("c") @@ -70,6 +75,7 @@ func TestDecorations_Prepend(t *testing.T) { } } +// TestSpaceType_String tests the String stringifier for SpaceType. func TestSpaceType_String(t *testing.T) { if dst.None.String() != "None" { t.Fatalf("expected None, found %s", dst.None.String()) @@ -85,7 +91,8 @@ func TestSpaceType_String(t *testing.T) { } } -func ExampleAlias() { +// Example_alias demonstrates how to use the FileRestorer to control aliases. +func Example_alias() { code := `package main @@ -122,7 +129,8 @@ func ExampleAlias() { } -func ExampleManualImports() { +// Example_manualImports demonstrates managing imports manually. +func Example_manualImports() { code := `package main @@ -165,7 +173,8 @@ func ExampleManualImports() { } -func ExampleImports() { +// Example_imports demonstrates using decorator.Load with imports. +func Example_imports() { // Create a simple module in a temporary directory dir, err := tempDir(map[string]string{ @@ -216,14 +225,15 @@ func ExampleImports() { //func main() { fmt.Println("Hello, World!") } } -func ExampleGoTypesImport() { +// Example_goTypesImport demonstrates using go/types info for imports. +func Example_goTypesImport() { // Create a simple module in a temporary directory dir, err := tempDir(map[string]string{ "go.mod": "module root", "main.go": `package main - import . "fmt" + import . "fmt" func main() { Println("a") @@ -268,7 +278,8 @@ func ExampleGoTypesImport() { //} } -func ExampleClone() { +// Example_clone demonstrates cloning a DST node. +func Example_clone() { code := `package main var i /* a */ int` @@ -297,7 +308,8 @@ func ExampleClone() { //var j /* b */ int } -func ExampleDecorationPoints() { +// Example_decorationPoints demonstrates inspecting decoration points. +func Example_decorationPoints() { code := `package main // main comment @@ -383,7 +395,8 @@ func ExampleDecorationPoints() { //- Lbrace: ["\n", "// empty block"] } -func ExampleTypes() { +// Example_types demonstrates using AST and types with DST. +func Example_types() { code := `package main func main() { @@ -464,7 +477,8 @@ func ExampleTypes() { } -func ExampleDecorated() { +// Example_decorated demonstrates modifying decorated nodes. +func Example_decorated() { code := `package main func main() { @@ -501,7 +515,8 @@ func ExampleDecorated() { //} } -func ExampleSpace() { +// Example_space demonstrates line spacing decoration. +func Example_space() { code := `package main func main() { @@ -541,7 +556,8 @@ func ExampleSpace() { //} } -func ExampleComment() { +// Example_comment demonstrates comment decoration. +func Example_comment() { code := `package main func main() { @@ -571,7 +587,8 @@ func ExampleComment() { //} } -func ExampleDecorations() { +// Example_decorations demonstrates more decoration examples. +func Example_decorations() { code := `package main func main() { @@ -623,7 +640,8 @@ func ExampleDecorations() { //} } -func ExampleAstBroken() { +// Example_astBroken demonstrates where ast breaks. +func Example_astBroken() { code := `package a func main(){ @@ -655,7 +673,8 @@ func ExampleAstBroken() { //} } -func ExampleDstFixed() { +// Example_dstFixed demonstrates how dst fixes the ast issue. +func Example_dstFixed() { code := `package a func main(){ diff --git a/decorator/decorator-fragment.go b/decorator/decorator-fragment.go index 02fef94..ac03d78 100644 --- a/decorator/decorator-fragment.go +++ b/decorator/decorator-fragment.go @@ -11,10 +11,12 @@ import ( "github.com/dave/dst" ) +// addDecorationFragment adds a decoration fragment to the list. func (f *fileDecorator) addDecorationFragment(n ast.Node, name string, pos token.Pos) { f.fragments = append(f.fragments, &decorationFragment{Node: n, Name: name, Pos: token.Pos(f.cursor)}) } +// addTokenFragment adds a token fragment to the list. func (f *fileDecorator) addTokenFragment(n ast.Node, t token.Token, pos token.Pos) { if pos.IsValid() { f.cursor = int(pos) @@ -23,6 +25,7 @@ func (f *fileDecorator) addTokenFragment(n ast.Node, t token.Token, pos token.Po f.cursor += len(t.String()) } +// addStringFragment adds a string fragment to the list. func (f *fileDecorator) addStringFragment(n ast.Node, s string, pos token.Pos) { if pos.IsValid() { f.cursor = int(pos) @@ -31,6 +34,7 @@ func (f *fileDecorator) addStringFragment(n ast.Node, s string, pos token.Pos) { f.cursor += len(s) } +// addBadFragment adds a bad fragment to the list. func (f *fileDecorator) addBadFragment(n ast.Node, pos token.Pos, length int) { if pos.IsValid() { f.cursor = int(pos) @@ -39,18 +43,21 @@ func (f *fileDecorator) addBadFragment(n ast.Node, pos token.Pos, length int) { f.cursor += length } +// addCommentFragment adds a comment fragment to the list. func (f *fileDecorator) addCommentFragment(text string, pos token.Pos) { // Don't need to worry about the cursor with comments - they are added to the fragment list in // the wrong order, then we sort the list based on Pos f.fragments = append(f.fragments, &commentFragment{Text: text, Pos: pos}) } +// addNewlineFragment adds a newline fragment to the list. func (f *fileDecorator) addNewlineFragment(pos token.Pos, empty bool) { // Don't need to worry about the cursor with newlines - they are added to the fragment list in // the wrong order, then we sort the list based on Pos f.fragments = append(f.fragments, &newlineFragment{Pos: pos, Empty: empty}) } +// fragment fragments the node. func (f *fileDecorator) fragment(node ast.Node) { // For all nodes, we add decoration, token and string fragments @@ -206,6 +213,7 @@ func (f *fileDecorator) fragment(node ast.Node) { } } +// link links the fragments. func (f *fileDecorator) link() { // Pass 1: associate comment groups with decorations. Sweep up any other comments / new-lines / @@ -345,10 +353,14 @@ func (f *fileDecorator) link() { spaceType = dst.EmptyLine } if foundBefore { - f.before[nodeBefore] = spaceType + if spaceType > f.before[nodeBefore] { + f.before[nodeBefore] = spaceType + } } if foundAfter { - f.after[nodeAfter] = spaceType + if spaceType > f.after[nodeAfter] { + f.after[nodeAfter] = spaceType + } } continue } @@ -378,6 +390,7 @@ func (f *fileDecorator) link() { return } +// appendDecoration appends a decoration to the map func appendDecoration(m map[ast.Node]map[string][]string, n ast.Node, pos, text string) { if m[n] == nil { m[n] = map[string][]string{} @@ -385,6 +398,7 @@ func appendDecoration(m map[ast.Node]map[string][]string, n ast.Node, pos, text m[n][pos] = append(m[n][pos], text) } +// appendNewLine appends a newline to the map func appendNewLine(m map[ast.Node]map[string][]string, n ast.Node, pos string, empty bool) { if m[n] == nil { m[n] = map[string][]string{} @@ -402,6 +416,7 @@ func appendNewLine(m map[ast.Node]map[string][]string, n ast.Node, pos string, e } } +// attachToDecoration attaches fragments to a decoration fragment. func (f *fileDecorator) attachToDecoration(frags []fragment, decorations map[ast.Node]map[string][]string, dec *decorationFragment) { for _, fr := range frags { switch fr := fr.(type) { @@ -415,6 +430,7 @@ func (f *fileDecorator) attachToDecoration(frags []fragment, decorations map[ast } } +// findDecoration finds a decoration fragment. func (f *fileDecorator) findDecoration(stopAtNewline, stopAtEmptyLine bool, from int, direction int, onlyClause bool) (swept []fragment, dec *decorationFragment, found bool) { var frags []fragment for i := from; i < len(f.fragments) && i >= 0; i += direction { @@ -463,6 +479,7 @@ func (f *fileDecorator) findDecoration(stopAtNewline, stopAtEmptyLine bool, from return } +// findNode finds a node fragment. func (f *fileDecorator) findNode(from int, direction int) (node ast.Node, dec *decorationFragment, found bool) { var name string @@ -495,6 +512,7 @@ func (f *fileDecorator) findNode(from int, direction int) (node ast.Node, dec *d return } +// findIndentedComments finds indented comments. func (f *fileDecorator) findIndentedComments(from int, indents [2]int) (frags [2][]fragment, nextDecoration *decorationFragment) { var stage int var pastNewline bool // while this is false, we're on the same line that the stmt ended, so we accept all comments regardless of the indent (e.g. empty clauses) - see "hanging-indent-same-line" test case. @@ -532,29 +550,34 @@ func (f *fileDecorator) findIndentedComments(from int, indents [2]int) (frags [2 return } +// fragment is the interface implemented by all fragment types type fragment interface { Position() token.Pos Newline() bool // True if the fragment ends in a newline ("\n" or "//...") } +// tokenFragment structure type tokenFragment struct { Node ast.Node Token token.Token Pos token.Pos } +// stringFragment structure type stringFragment struct { Node ast.Node String string Pos token.Pos } +// badFragment structure type badFragment struct { Node ast.Node Pos token.Pos Length int } +// commentFragment structure type commentFragment struct { Text string Pos token.Pos @@ -562,32 +585,57 @@ type commentFragment struct { Indent int // indent if this comment follows a newline } +// newlineFragment structure type newlineFragment struct { Pos token.Pos Empty bool // true if this newline is an empty line (e.g. follows a "//" comment or "\n") Attached *decorationFragment // where did we attach this comment in pass 1? } +// decorationFragment structure type decorationFragment struct { Node ast.Node Name string Pos token.Pos } -func (v *tokenFragment) Position() token.Pos { return v.Pos } -func (v *stringFragment) Position() token.Pos { return v.Pos } -func (v *commentFragment) Position() token.Pos { return v.Pos } -func (v *newlineFragment) Position() token.Pos { return v.Pos } +// Position returns the position. +func (v *tokenFragment) Position() token.Pos { return v.Pos } + +// Position returns the position. +func (v *stringFragment) Position() token.Pos { return v.Pos } + +// Position returns the position. +func (v *commentFragment) Position() token.Pos { return v.Pos } + +// Position returns the position. +func (v *newlineFragment) Position() token.Pos { return v.Pos } + +// Position returns the position. func (v *decorationFragment) Position() token.Pos { return v.Pos } -func (v *badFragment) Position() token.Pos { return v.Pos } -func (v *tokenFragment) Newline() bool { return false } -func (v *stringFragment) Newline() bool { return false } -func (v *commentFragment) Newline() bool { return strings.HasPrefix(v.Text, "//") } -func (v *newlineFragment) Newline() bool { return true } +// Position returns the position. +func (v *badFragment) Position() token.Pos { return v.Pos } + +// Newline returns true if the fragment ends in a newline +func (v *tokenFragment) Newline() bool { return false } + +// Newline returns true if the fragment ends in a newline +func (v *stringFragment) Newline() bool { return false } + +// Newline returns true if the fragment ends in a newline +func (v *commentFragment) Newline() bool { return strings.HasPrefix(v.Text, "//") } + +// Newline returns true if the fragment ends in a newline +func (v *newlineFragment) Newline() bool { return true } + +// Newline returns true if the fragment ends in a newline func (v *decorationFragment) Newline() bool { return false } -func (v *badFragment) Newline() bool { return false } +// Newline returns true if the fragment ends in a newline +func (v *badFragment) Newline() bool { return false } + +// debug prints the fragments to w func (f fileDecorator) debug(w io.Writer) { formatPos := func(s token.Position) string { return s.String()[strings.Index(s.String(), ":")+1:] diff --git a/decorator/decorator_test.go b/decorator/decorator_test.go index 5ac90d5..1e5750e 100644 --- a/decorator/decorator_test.go +++ b/decorator/decorator_test.go @@ -44,9 +44,9 @@ package a`, var A /*1*/ B[ /*2*/ int /*3*/, string /*4*/] /*5*/`, expect: `GenDecl [Empty line before] [End "/*5*/"] - Ident [End "/*1*/"] - IndexListExpr [Lbrack "/*2*/"] [Indices "/*4*/"] - Ident [End "/*3*/"]`, +Ident [End "/*1*/"] +IndexListExpr [Lbrack "/*2*/"] [Indices "/*4*/"] +Ident [End "/*3*/"]`, }, { name: "type params", @@ -56,33 +56,33 @@ func /*1*/ A[ /*2*/ B /*3*/ any /*4*/, C /*5*/ int /*6*/ | /*7*/ int64 /*8*/]( / return 0 }`, expect: `FuncDecl [Empty line before] [Func "/*1*/"] [Params "/*12*/"] [Results "/*13*/"] - FieldList [Opening "/*2*/"] - Field [End "/*4*/"] - Ident [End "/*3*/"] - Field [End "/*8*/"] - Ident [End "/*5*/"] - BinaryExpr [X "/*6*/"] [Op "/*7*/"] - FieldList [Opening "/*9*/"] - Field [End "/*11*/"] - Ident [End "/*10*/"] - ReturnStmt [New line before] [New line after]`, +FieldList [Opening "/*2*/"] +Field [End "/*4*/"] +Ident [End "/*3*/"] +Field [End "/*8*/"] +Ident [End "/*5*/"] +BinaryExpr [X "/*6*/"] [Op "/*7*/"] +FieldList [Opening "/*9*/"] +Field [End "/*11*/"] +Ident [End "/*10*/"] +ReturnStmt [New line before] [New line after]`, }, { name: "import-blocks", code: `package main - // first-import-block - import ( - "root/a" - "root/b" - ) - - // second-import-block - import ( - "root/c" - "root/d" - )`, +// first-import-block +import ( + "root/a" + "root/b" +) + +// second-import-block +import ( + "root/c" + "root/d" +)`, expect: `GenDecl [Empty line before] [Start "// first-import-block"] [Empty line after] ImportSpec [New line before] [New line after] ImportSpec [New line before] [New line after] @@ -153,8 +153,7 @@ const c = 1 + // d1 // d2 -const d = 1 -`, +const d = 1`, expect: `GenDecl [Empty line before] [End "\n" "// a1" "\n" "// a2"] [New line after] BasicLit [New line before] GenDecl [New line before] [Empty line after] @@ -166,12 +165,12 @@ GenDecl [Empty line before] [Start "// d1" "\n" "// d2"]`, name: "net-hook", code: `package a - var a = func( - b int, - c int, - ) int { - return 1 - }`, +var a = func( + b int, + c int, +) int { + return 1 +}`, expect: `GenDecl [Empty line before] Field [New line before] [New line after] Field [New line before] [New line after] @@ -181,27 +180,27 @@ ReturnStmt [New line before] [New line after]`, name: "multi-line-string", code: `package a - var a = b{ - c: ` + "`" + ` +var a = b{ + c: ` + "`" + ` ` + "`" + `, - }`, +}`, expect: `GenDecl [Empty line before] KeyValueExpr [New line before] [New line after]`, }, { name: "case clause", code: `package a - - func main() { - switch a { - case 1: - // a - // b - case 2: - // c - case 3: - } - }`, + +func main() { + switch a { + case 1: + // a + // b + case 2: + // c + case 3: + } +}`, expect: `FuncDecl [Empty line before] SwitchStmt [New line before] [New line after] CaseClause [New line before] [End "\n" "// a"] [New line after] @@ -211,26 +210,26 @@ CaseClause [New line before] [Start "// c"] [New line after]`, { name: "block comment", code: `package a - - /* - foo - */ - var i int`, - expect: `GenDecl [Empty line before] [Start "/*\n\tfoo\n*/" "\n"]`, + +/* + foo +*/ +var i int`, + expect: `GenDecl [Empty line before] [Start "/*\nfoo\n*/" "\n"]`, }, { name: "case comment", code: `package a - func main() { - switch { - default: - // b - // c +func main() { + switch { + default: + // b + // c - var i int - } - }`, + var i int + } +}`, expect: `FuncDecl [Empty line before] SwitchStmt [New line before] [New line after] CaseClause [New line before] [Colon "\n" "// b" "// c"] [New line after] @@ -240,7 +239,7 @@ DeclStmt [Empty line before]`, name: "file", code: `/*Start*/ package /*Package*/ postests /*Name*/ - var i int`, +var i int`, expect: `File [Start "/*Start*/"] [Package "/*Package*/"] [Name "/*Name*/"] GenDecl [Empty line before]`, }, @@ -248,10 +247,10 @@ GenDecl [Empty line before]`, name: "TypeAssertExpr", code: `package main - - // TypeAssertExpr - var I interface{} - var J = I. /*TypeAssertExprX*/ ( /*TypeAssertExprLparen*/ int /*TypeAssertExprType*/)`, + +// TypeAssertExpr +var I interface{} +var J = I. /*TypeAssertExprX*/ ( /*TypeAssertExprLparen*/ int /*TypeAssertExprType*/)`, expect: `GenDecl [Empty line before] [Start "// TypeAssertExpr"] [New line after] GenDecl [New line before] TypeAssertExpr [X "/*TypeAssertExprX*/"] [Lparen "/*TypeAssertExprLparen*/"] [Type "/*TypeAssertExprType*/"]`, @@ -260,12 +259,12 @@ TypeAssertExpr [X "/*TypeAssertExprX*/"] [Lparen "/*TypeAssertExprLparen*/"] [Ty name: "range bug", code: `package main - func main() { - /*Start*/ - for /*For*/ k /*Key*/, v /*Value*/ := range /*Range*/ a /*X*/ { - print(k, v) - } /*End*/ - }`, +func main() { + /*Start*/ + for /*For*/ k /*Key*/, v /*Value*/ := range /*Range*/ a /*X*/ { + print(k, v) + } /*End*/ +}`, expect: `FuncDecl [Empty line before] RangeStmt [New line before] [Start "/*Start*/" "\n"] [For "/*For*/"] [Key "/*Key*/"] [Value "/*Value*/"] [Range "/*Range*/"] [X "/*X*/"] [End "/*End*/"] [New line after] ExprStmt [New line before] [New line after]`, @@ -274,9 +273,9 @@ ExprStmt [New line before] [New line after]`, name: "value spec", code: `package main - func main() { - var foo int - }`, +func main() { + var foo int +}`, expect: `FuncDecl [Empty line before] DeclStmt [New line before] [New line after]`, }, @@ -284,20 +283,20 @@ DeclStmt [New line before] [New line after]`, name: "chan type", code: `package main - type Y /*Start*/ chan /*Begin*/ <- /*Arrow*/ int /*End*/`, +type Y /*Start*/ chan /*Begin*/ int /*End*/`, expect: `GenDecl [Empty line before] [End "/*End*/"] TypeSpec [Name "/*Start*/"] -ChanType [Begin "/*Begin*/"] [Arrow "/*Arrow*/"]`, +ChanType [Begin "/*Begin*/"]`, }, { name: "inside if block", code: `package main - func main() { - if true { - // a - } - }`, +func main() { + if true { + // a + } +}`, expect: `FuncDecl [Empty line before] IfStmt [New line before] [New line after] BlockStmt [Lbrace "\n" "// a"]`, @@ -305,54 +304,54 @@ BlockStmt [Lbrace "\n" "// a"]`, { name: "simple", code: `package main - - func main() { - i // foo - }`, + +func main() { + i // foo +}`, expect: `FuncDecl [Empty line before] ExprStmt [New line before] [End "// foo"] [New line after]`, }, { name: "inline comment inside node", code: `package main - - func main() { - i /* foo */ ++ - }`, + +func main() { + i /* foo */ ++ +}`, expect: `FuncDecl [Empty line before] IncDecStmt [New line before] [X "/* foo */"] [New line after]`, }, { name: "comment statement spaced", code: `package main - - func main() { - // foo +func main() { - i - }`, + // foo + + i +}`, expect: `FuncDecl [Empty line before] ExprStmt [Empty line before] [Start "// foo" "\n"] [New line after]`, }, { name: "comment statement", code: `package main - - func main() { - // foo - i - }`, + +func main() { + // foo + i +}`, expect: `FuncDecl [Empty line before] ExprStmt [New line before] [Start "// foo"] [New line after]`, }, { name: "comment after lbrace", code: `package main - - func main() { // foo - i - }`, + +func main() { // foo + i +}`, expect: `FuncDecl [Empty line before] BlockStmt [Lbrace "// foo"] ExprStmt [New line before] [New line after]`, @@ -360,10 +359,10 @@ ExprStmt [New line before] [New line after]`, { name: "comment after func", code: `package main - - func /* foo */ main() { - i - }`, + +func /* foo */ main() { + i +}`, expect: `FuncDecl [Empty line before] [Func "/* foo */"] ExprStmt [New line before] [New line after]`, }, @@ -371,9 +370,9 @@ ExprStmt [New line before] [New line after]`, name: "field", code: `package main - type A struct { - A /*IdentEnd*/ int /*FieldType*/ ` + "`" + `a:"a"` + "`" + ` - }`, +type A struct { + A /*IdentEnd*/ int /*FieldType*/ ` + "`" + `a:"a"` + "`" + ` +}`, expect: `GenDecl [Empty line before] Field [New line before] [Type "/*FieldType*/"] [New line after] Ident [End "/*IdentEnd*/"]`, @@ -382,10 +381,10 @@ Ident [End "/*IdentEnd*/"]`, name: "composite literal", code: `package main - var A = B{ - "a": "b", - "c": "d", // foo - }`, +var A = B{ + "a": "b", + "c": "d", // foo +}`, expect: `GenDecl [Empty line before] KeyValueExpr [New line before] [New line after] KeyValueExpr [New line before] [End "// foo"] [New line after]`, @@ -394,11 +393,11 @@ KeyValueExpr [New line before] [End "// foo"] [New line after]`, name: "composite literal 1", code: `package main - var A = B{ - "a": "b", - // foo - "c": "d", - }`, +var A = B{ + "a": "b", + // foo + "c": "d", +}`, expect: `GenDecl [Empty line before] KeyValueExpr [New line before] [New line after] KeyValueExpr [New line before] [Start "// foo"] [New line after]`, @@ -407,12 +406,12 @@ KeyValueExpr [New line before] [Start "// foo"] [New line after]`, name: "composite literal 2", code: `package main - var A = B{ - "a": "b", +var A = B{ + "a": "b", - // foo - "c": "d", - }`, + // foo + "c": "d", +}`, expect: `GenDecl [Empty line before] KeyValueExpr [New line before] [Empty line after] KeyValueExpr [Empty line before] [Start "// foo"] [New line after]`, @@ -421,13 +420,13 @@ KeyValueExpr [Empty line before] [Start "// foo"] [New line after]`, name: "composite literal 3", code: `package main - var A = B{ - "a": "b", +var A = B{ + "a": "b", - // foo + // foo - "c": "d", - }`, + "c": "d", +}`, expect: `GenDecl [Empty line before] KeyValueExpr [New line before] [Empty line after] KeyValueExpr [Empty line before] [Start "// foo" "\n"] [New line after]`, @@ -436,12 +435,12 @@ KeyValueExpr [Empty line before] [Start "// foo" "\n"] [New line after]`, name: "composite literal 4", code: `package main - var A = B{ - "a": "b", - // foo +var A = B{ + "a": "b", + // foo - "c": "d", - }`, + "c": "d", +}`, expect: `GenDecl [Empty line before] KeyValueExpr [New line before] [End "\n" "// foo"] [Empty line after] KeyValueExpr [Empty line before] [New line after]`, @@ -450,11 +449,11 @@ KeyValueExpr [Empty line before] [New line after]`, name: "composite literal 4a", code: `package main - var A = B{ - "a": "b", - // foo - "c": "d", - }`, +var A = B{ + "a": "b", + // foo + "c": "d", +}`, expect: `GenDecl [Empty line before] KeyValueExpr [New line before] [New line after] KeyValueExpr [New line before] [Start "// foo"] [New line after]`, @@ -463,10 +462,10 @@ KeyValueExpr [New line before] [Start "// foo"] [New line after]`, name: "composite literal 5", code: `package main - var A = B{ - "a": "b", // foo - "c": "d", - }`, +var A = B{ + "a": "b", // foo + "c": "d", +}`, expect: `GenDecl [Empty line before] KeyValueExpr [New line before] [End "// foo"] [New line after] KeyValueExpr [New line before] [New line after]`, @@ -474,13 +473,28 @@ KeyValueExpr [New line before] [New line after]`, { name: "FuncDecl", code: `package main - - // FuncDecl - func /*FuncDeclDoc*/ (a *b) /*FuncDeclRecv*/ c /*FuncDeclName*/ (d, e int) /*FuncDeclParams*/ (f, g int) /*FuncDeclType*/ { - }`, + +// FuncDecl +func /*FuncDeclDoc*/ (a *b) /*FuncDeclRecv*/ c /*FuncDeclName*/ (d, e int) /*FuncDeclParams*/ (f, g int) /*FuncDeclType*/ { +}`, expect: `FuncDecl [Empty line before] [Start "// FuncDecl"] [Func "/*FuncDeclDoc*/"] [Recv "/*FuncDeclRecv*/"] [Name "/*FuncDeclName*/"] [Params "/*FuncDeclParams*/"] [Results "/*FuncDeclType*/"] BlockStmt [Lbrace "\n"]`, }, + { + name: "eats empty lines", + code: `package main + +func main() { + if true { + } + + a := "Hello, world!" +}`, + expect: `FuncDecl [Empty line before] +IfStmt [New line before] [Empty line after] +BlockStmt [Lbrace "\n"] +AssignStmt [Empty line before] [New line after]`, + }, } var solo bool for _, test := range tests { @@ -647,6 +661,13 @@ var multiSpaces = regexp.MustCompile(" {2,}") func normalize(s string) string { s = multiSpaces.ReplaceAllString(s, "") s = strings.Replace(s, "\t", "", -1) + + lines := strings.Split(s, "\n") + for i, line := range lines { + lines[i] = strings.TrimRight(line, " ") + } + s = strings.Join(lines, "\n") + s = strings.TrimSpace(s) return s } diff --git a/decorator/restorer_std_test.go b/decorator/restorer_std_test.go index f39e6a3..1210a27 100644 --- a/decorator/restorer_std_test.go +++ b/decorator/restorer_std_test.go @@ -15,6 +15,7 @@ import ( "github.com/dave/dst/decorator/resolver/gobuild" ) +// TestLoadStdLibAll loads all packages in the standard library and verifies (via fprint/restore) that they are preserved. func TestLoadStdLibAll(t *testing.T) { if testing.Short() { @@ -43,6 +44,7 @@ func TestLoadStdLibAll(t *testing.T) { } +// testPackageRestoresCorrectlyWithImports tests that the packages at path restore correctly. func testPackageRestoresCorrectlyWithImports(t *testing.T, path ...string) { t.Helper() pkgs, err := Load(nil, path...) @@ -57,13 +59,17 @@ func testPackageRestoresCorrectlyWithImports(t *testing.T, path ...string) { "unsafe": true, "embed/internal/embedtest": true, "os/signal/internal/pty": true, + "runtime": true, + "reflect": true, + "internal/godebug": true, } for _, p := range pkgs { if skip[p.PkgPath] { continue } if len(p.Syntax) == 0 { - t.Fatalf("Package %s has no syntax", p.PkgPath) + t.Logf("Package %s has no syntax, skipping", p.PkgPath) + continue } t.Run(p.PkgPath, func(t *testing.T) { diff --git a/dst.go b/dst.go index 803eb9a..d696b09 100644 --- a/dst.go +++ b/dst.go @@ -59,7 +59,6 @@ type Decl interface { // in a signature. // Field.Names is nil for unnamed parameters (parameter lists which only contain types) // and embedded struct fields. In the latter case, the field name is the type name. -// type Field struct { Names []*Ident // field/method/(type) parameter names; or nil Type Expr // field/method/parameter type; or nil diff --git a/dstutil/rewrite.go b/dstutil/rewrite.go index acb82c8..1d1bc7c 100644 --- a/dstutil/rewrite.go +++ b/dstutil/rewrite.go @@ -41,7 +41,6 @@ type ApplyFunc func(*Cursor) bool // Children are traversed in the order in which they appear in the // respective node's struct definition. A package's files are // traversed in the filenames' alphabetical order. -// func Apply(root dst.Node, pre, post ApplyFunc) (result dst.Node) { parent := &struct{ dst.Node }{root} defer func() { @@ -65,8 +64,8 @@ var abort = new(int) // singleton, to signal termination of Apply // c.Parent(), and f is the field identifier with name c.Name(), // the following invariants hold: // -// p.f == c.Node() if c.Index() < 0 -// p.f[c.Index()] == c.Node() if c.Index() >= 0 +// p.f == c.Node() if c.Index() < 0 +// p.f[c.Index()] == c.Node() if c.Index() >= 0 // // The methods Replace, Delete, InsertBefore, and InsertAfter // can be used to change the AST without disrupting Apply. diff --git a/go.mod b/go.mod index 168fffa..63b8f70 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,15 @@ module github.com/dave/dst -go 1.18 +go 1.24.0 require ( - github.com/dave/jennifer v1.5.0 + github.com/dave/jennifer v1.7.1 github.com/sergi/go-diff v1.2.0 - golang.org/x/tools v0.1.12 + golang.org/x/tools v0.41.0 gopkg.in/src-d/go-billy.v4 v4.3.2 ) require ( - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect + golang.org/x/mod v0.32.0 // indirect + golang.org/x/sync v0.19.0 // indirect ) diff --git a/go.sum b/go.sum index da6bcab..37c2e4e 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,17 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/dave/astrid v0.0.0-20170323122508-8c2895878b14/go.mod h1:Sth2QfxfATb/nW4EsrSi2KyJmbcniZ8TgTaji17D6ms= -github.com/dave/brenda v1.1.0/go.mod h1:4wCUr6gSlu5/1Tk7akE5X7UorwiQ8Rij0SKH3/BGMOM= -github.com/dave/courtney v0.3.0/go.mod h1:BAv3hA06AYfNUjfjQr+5gc6vxeBVOupLqrColj+QSD8= -github.com/dave/gopackages v0.0.0-20170318123100-46e7023ec56e/go.mod h1:i00+b/gKdIDIxuLDFob7ustLAVqhsZRk2qVZrArELGQ= -github.com/dave/jennifer v1.5.0 h1:HmgPN93bVDpkQyYbqhCHj5QlgvUkvEOzMyEvKLgCRrg= -github.com/dave/jennifer v1.5.0/go.mod h1:4MnyiFIlZS3l5tSDn8VnzE6ffAhYBMB2SZntBsZGUok= -github.com/dave/kerr v0.0.0-20170318121727-bc25dd6abe8e/go.mod h1:qZqlPyPvfsDJt+3wHJ1EvSXDuVjFTK0j2p/ca+gtsb8= -github.com/dave/patsy v0.0.0-20210517141501-957256f50cba/go.mod h1:qfR88CgEGLoiqDaE+xxDCi5QA5v4vUoW0UCX2Nd5Tlc= -github.com/dave/rebecca v0.9.1/go.mod h1:N6XYdMD/OKw3lkF3ywh8Z6wPGuwNFDNtWYEMFWEmXBA= +github.com/dave/jennifer v1.7.1 h1:B4jJJDHelWcDhlRQxWeo0Npa/pYKBLrirAQoTN45txo= +github.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= @@ -25,37 +19,13 @@ github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= diff --git a/readme.go b/readme.go index 7bb53bd..41780f4 100644 --- a/readme.go +++ b/readme.go @@ -1,4 +1,4 @@ package dst //go:generate go get github.com/dave/rebecca/cmd/becca -//go:generate becca -package=github.com/dave/dst +//go:generate -command becca go run github.com/dave/rebecca/cmd/becca@v0.9.2 diff --git a/resolve.go b/resolve.go index e247baf..af5138c 100644 --- a/resolve.go +++ b/resolve.go @@ -66,7 +66,6 @@ type Importer func(imports map[string]*Object, path string) (pkg *Object, err er // belong to different packages, one package name is selected and files with // different package names are reported and then ignored. // The result is a package node and a scanner.ErrorList if there were errors. -// func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, error) { var p pkgBuilder p.fset = fset diff --git a/scope.go b/scope.go index c05ab70..b87e44c 100644 --- a/scope.go +++ b/scope.go @@ -14,7 +14,6 @@ import ( // A Scope maintains the set of named language entities declared // in the scope and a link to the immediately surrounding (outer) // scope. -// type Scope struct { Outer *Scope Objects map[string]*Object @@ -29,7 +28,6 @@ func NewScope(outer *Scope) *Scope { // Lookup returns the object with the given name if it is // found in scope s, otherwise it returns nil. Outer scopes // are ignored. -// func (s *Scope) Lookup(name string) *Object { return s.Objects[name] } @@ -38,7 +36,6 @@ func (s *Scope) Lookup(name string) *Object { // If the scope already contains an object alt with the same name, // Insert leaves the scope unchanged and returns alt. Otherwise // it inserts obj and returns nil. -// func (s *Scope) Insert(obj *Object) (alt *Object) { if alt = s.Objects[obj.Name]; alt == nil { s.Objects[obj.Name] = obj @@ -71,7 +68,6 @@ func (s *Scope) String() string { // Kind Data type Data value // Pkg *Scope package scope // Con int iota for the respective declaration -// type Object struct { Kind ObjKind Name string // declared name diff --git a/walk.go b/walk.go index da7f97b..d80885d 100644 --- a/walk.go +++ b/walk.go @@ -47,7 +47,6 @@ func walkDeclList(v Visitor, list []Decl) { // v.Visit(node) is not nil, Walk is invoked recursively with visitor // w for each of the non-nil children of node, followed by a call of // w.Visit(nil). -// func Walk(v Visitor, node Node) { if v = v.Visit(node); v == nil { return @@ -348,7 +347,6 @@ func (f inspector) Visit(node Node) Visitor { // f(node); node must not be nil. If f returns true, Inspect invokes f // recursively for each of the non-nil children of node, followed by a // call of f(nil). -// func Inspect(node Node, f func(Node) bool) { Walk(inspector(f), node) } From 2a948e3c68234494911155dd071299afae1ca8ba Mon Sep 17 00:00:00 2001 From: Samuel Marks <807580+SamuelMarks@users.noreply.github.com> Date: Wed, 28 Jan 2026 23:03:25 -0500 Subject: [PATCH 2/3] [dst.go,gendst/data/data.go,goversion_test.go] Support for this syntax `//go:build go1.22` ; [decorator/iterator_test.go] test support for func iterators `for k, v := range iter` --- decorator/iterator_test.go | 129 +++++++++++++++++++++++++++++++++++++ dst.go | 9 +-- gendst/data/data.go | 47 ++++++++------ goversion_test.go | 21 ++++++ 4 files changed, 181 insertions(+), 25 deletions(-) create mode 100644 decorator/iterator_test.go create mode 100644 goversion_test.go diff --git a/decorator/iterator_test.go b/decorator/iterator_test.go new file mode 100644 index 0000000..bcfe6c7 --- /dev/null +++ b/decorator/iterator_test.go @@ -0,0 +1,129 @@ +package decorator + +import ( + "bytes" + "go/format" + "testing" +) + +// TestRangeIterators verifies that the decorator correctly handles Go 1.23+ range iterator syntax, +// ensuring comments and whitespace around the iterator expression are preserved during round-trips. +func TestRangeIterators(t *testing.T) { + tests := []struct { + name string + code string + }{ + { + name: "basic-func-iterator", + code: `package main + +func main() { + for x := range seq { + print(x) + } +}`, + }, + { + name: "iterator-call", + code: `package main + +func main() { + for k, v := range slices.All(s) { + print(k, v) + } +}`, + }, + { + name: "integer-range-go1.22", + code: `package main + +func main() { + for i := range 10 { + print(i) + } +}`, + }, + { + name: "complex-inline-comments", + code: `package main + +func main() { + // Start loop + for /*a*/ i /*b*/, /*c*/ v := /*d*/ range /*e*/ iter( /*f*/ ) /*g*/ { + print(i, v) + } +}`, + }, + { + name: "multiline-iterator-call", + code: `package main + +func main() { + for i := range merge( + seq1, + seq2, + ) { + print(i) + } +}`, + }, + { + name: "iterator-with-block-spacing", + code: `package main + +func main() { + for x := range seq { + + print(x) + + } +}`, + }, + { + name: "range-decorations-iter", + // Test explicit attachment points for RangeStmt with an iterator expression + // The X expression here is a CallExpr + code: `package main + +func main() { + for i := range /*Range*/ slices.All(s) /*X*/ { + } +}`, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // standard formatting ensures consistent whitespace for comparison + formatted, err := format.Source([]byte(test.code)) + if err != nil { + t.Fatalf("format.Source failed: %s", err) + } + expectedCode := string(formatted) + + // Parse the code using the decorator + f, err := Parse(expectedCode) + if err != nil { + t.Fatalf("Parse failed: %s", err) + } + + // Restore the file to AST and print it + // We use a clean FileRestorer to simulate a full round-trip + r := NewRestorer() + buf := &bytes.Buffer{} + if err := r.Fprint(buf, f); err != nil { + t.Fatalf("Fprint failed: %s", err) + } + + // Normalize strings to ignore insignificant whitespace differences if necessary, + // though typical round-trip should be exact for formatted code. + got := buf.String() + + // Use the diff helper assumed to be present in the package from other tests + // (e.g. wrapper around diffmatchpatch as seen in existing tests like decorator_fragment_test.go) + if normalize(got) != normalize(expectedCode) { + t.Errorf("Mismatch in round-trip.\nExpected:\n%s\nGot:\n%s\nDiff:\n%s", expectedCode, got, diff(normalize(expectedCode), normalize(got))) + } + }) + } +} \ No newline at end of file diff --git a/dst.go b/dst.go index d696b09..62010e6 100644 --- a/dst.go +++ b/dst.go @@ -594,10 +594,10 @@ type ( // // Relationship between Tok value and Specs element type: // - // token.IMPORT *ImportSpec - // token.CONST *ValueSpec - // token.TYPE *TypeSpec - // token.VAR *ValueSpec + // token.IMPORT *ImportSpec + // token.CONST *ValueSpec + // token.TYPE *TypeSpec + // token.VAR *ValueSpec // GenDecl struct { Tok token.Token // IMPORT, CONST, TYPE, or VAR @@ -651,6 +651,7 @@ type File struct { Imports []*ImportSpec // imports in this file Unresolved []*Ident // unresolved identifiers in this file Decs FileDecorations + GoVersion string // minimum Go version required by this file (e.g. "go1.21") } // A Package node represents a set of source files diff --git a/gendst/data/data.go b/gendst/data/data.go index abe0ce1..4906a2a 100644 --- a/gendst/data/data.go +++ b/gendst/data/data.go @@ -1232,7 +1232,7 @@ var Info = map[string][]Part{ } */ ///*Start*/ - // c /*Chan*/ <- /*Arrow*/ 0 /*End*/ + // c /*Chan*/ <- /*Arrow*/ 0 /*End*/ "SendStmt": { Decoration{ Name: "Start", @@ -2079,10 +2079,10 @@ var Info = map[string][]Part{ // // Relationship between Tok value and Specs element type: // - // token.IMPORT *ImportSpec - // token.CONST *ValueSpec - // token.TYPE *TypeSpec - // token.VAR *ValueSpec + // token.IMPORT *ImportSpec + // token.CONST *ValueSpec + // token.TYPE *TypeSpec + // token.VAR *ValueSpec // GenDecl struct { Doc *CommentGroup // associated documentation; or nil @@ -2278,16 +2278,17 @@ var Info = map[string][]Part{ // and Comment comments directly associated with nodes, the remaining comments // are "free-floating" (see also issues #18593, #20744). // - type File struct { - Doc *CommentGroup // associated documentation; or nil - Package token.Pos // position of "package" keyword - Name *Ident // package name - Decls []Decl // top-level declarations; or nil - Scope *Scope // package scope (this file only) - Imports []*ImportSpec // imports in this file - Unresolved []*Ident // unresolved identifiers in this file - Comments []*CommentGroup // list of all comments in the source file - } + // type File struct { + // Doc *CommentGroup // associated documentation; or nil + // Package token.Pos // position of "package" keyword + // Name *Ident // package name + // Decls []Decl // top-level declarations; or nil + // Scope *Scope // package scope (this file only) + // Imports []*ImportSpec // imports in this file + // Unresolved []*Ident // unresolved identifiers in this file + // Comments []*CommentGroup // list of all comments in the source file + // GoVersion string // minimum Go version required by this file (e.g. "go1.21") + // } */ // TODO: File.Unresolved? "File": { @@ -2330,17 +2331,21 @@ var Info = map[string][]Part{ Elem: Struct{"ImportSpec"}, NoRestore: true, }, + Value{ + Name: "GoVersion", + Field: Field{"GoVersion"}, + }, }, /* // A Package node represents a set of source files // collectively building a Go package. // - type Package struct { - Name string // package name - Scope *Scope // package scope across all files - Imports map[string]*Object // map of package id -> package object - Files map[string]*File // Go source files by filename - } + // type Package struct { + // Name string // package name + // Scope *Scope // package scope across all files + // Imports map[string]*Object // map of package id -> package object + // Files map[string]*File // Go source files by filename + // } */ "Package": { Value{ diff --git a/goversion_test.go b/goversion_test.go new file mode 100644 index 0000000..04e60ce --- /dev/null +++ b/goversion_test.go @@ -0,0 +1,21 @@ +package dst_test + +import ( + "testing" + + "github.com/dave/dst" +) + +func TestFileHeader_GoVersion(t *testing.T) { + // This test simply asserts that the GoVersion field exists on the struct + // and can be read/written. The full integration (copying from ast) requires + // generation to run, but this confirms the struct update. + f := &dst.File{ + Name: dst.NewIdent("main"), + GoVersion: "go1.21", + } + + if f.GoVersion != "go1.21" { + t.Errorf("GoVersion field not working as expected, got %q", f.GoVersion) + } +} From a6455ed0bc2dd906eb7b854a63cf94bd9d65751d Mon Sep 17 00:00:00 2001 From: Samuel Marks <807580+SamuelMarks@users.noreply.github.com> Date: Thu, 29 Jan 2026 00:15:51 -0500 Subject: [PATCH 3/3] Support for go 1.24's generic type aliases `type A[T any] = B[T]` --- clone-generated.go | 12 +- decorations-types-generated.go | 305 ++++++++++++++-------- decorator/alias_test.go | 107 ++++++++ decorator/decorator-fragment-generated.go | 15 +- decorator/decorator-node-generated.go | 12 +- decorator/iterator_test.go | 4 +- decorator/restorer-generated.go | 21 +- dstutil/decorations-generated.go | 1 + gendst/data/data.go | 157 +++++------ gendst/data/positions.go | 2 +- 10 files changed, 427 insertions(+), 209 deletions(-) create mode 100644 decorator/alias_test.go diff --git a/clone-generated.go b/clone-generated.go index ab22874..08a2efb 100644 --- a/clone-generated.go +++ b/clone-generated.go @@ -573,6 +573,9 @@ func Clone(n Node) Node { out.Imports = append(out.Imports, Clone(v).(*ImportSpec)) } + // Value: GoVersion + out.GoVersion = n.GoVersion + out.Decs.After = n.Decs.After return out @@ -1502,9 +1505,6 @@ func Clone(n Node) Node { out.Name = Clone(n.Name).(*Ident) } - // Token: Assign - out.Assign = n.Assign - // Decoration: Name out.Decs.Name = append(out.Decs.Name, n.Decs.Name...) @@ -1516,6 +1516,12 @@ func Clone(n Node) Node { // Decoration: TypeParams out.Decs.TypeParams = append(out.Decs.TypeParams, n.Decs.TypeParams...) + // Token: Assign + out.Assign = n.Assign + + // Decoration: Assign + out.Decs.Assign = append(out.Decs.Assign, n.Decs.Assign...) + // Node: Type if n.Type != nil { out.Type = Clone(n.Type).(Expr) diff --git a/decorations-types-generated.go b/decorations-types-generated.go index 4381b8c..7a99d94 100644 --- a/decorations-types-generated.go +++ b/decorations-types-generated.go @@ -11,8 +11,10 @@ type ArrayTypeDecorations struct { // AssignStmtDecorations holds decorations for AssignStmt: // -// /*Start*/ -// i = /*Tok*/ 1 /*End*/ +// *Start*/ +// i = /*Tok*/ 1 /*End*/ +// +// // type AssignStmtDecorations struct { NodeDecs Tok Decorations @@ -49,11 +51,15 @@ type BinaryExprDecorations struct { // BlockStmtDecorations holds decorations for BlockStmt: // -// if true /*Start*/ { /*Lbrace*/ -// i++ -// } /*End*/ +// f true /*Start*/ { /*Lbrace*/ +// i++ +// } /*End*/ // -// func() /*Start*/ { /*Lbrace*/ i++ } /*End*/ () +// // +// +// unc() /*Start*/ { /*Lbrace*/ i++ } /*End*/ () +// +// // type BlockStmtDecorations struct { NodeDecs Lbrace Decorations @@ -61,8 +67,10 @@ type BlockStmtDecorations struct { // BranchStmtDecorations holds decorations for BranchStmt: // -// /*Start*/ -// goto /*Tok*/ A /*End*/ +// *Start*/ +// goto /*Tok*/ A /*End*/ +// +// // type BranchStmtDecorations struct { NodeDecs Tok Decorations @@ -80,10 +88,12 @@ type CallExprDecorations struct { // CaseClauseDecorations holds decorations for CaseClause: // -// switch i { -// /*Start*/ case /*Case*/ 1: /*Colon*/ -// i++ /*End*/ -// } +// witch i { +// /*Start*/ case /*Case*/ 1: /*Colon*/ +// i++ /*End*/ +// } +// +// // type CaseClauseDecorations struct { NodeDecs Case Decorations @@ -105,10 +115,12 @@ type ChanTypeDecorations struct { // CommClauseDecorations holds decorations for CommClause: // -// select { -// /*Start*/ case /*Case*/ a := <-c /*Comm*/ : /*Colon*/ -// print(a) /*End*/ -// } +// elect { +// /*Start*/ case /*Case*/ a := <-c /*Comm*/ : /*Colon*/ +// print(a) /*End*/ +// } +// +// // type CommClauseDecorations struct { NodeDecs Case Decorations @@ -132,8 +144,10 @@ type DeclStmtDecorations struct { // DeferStmtDecorations holds decorations for DeferStmt: // -// /*Start*/ -// defer /*Defer*/ func() {}() /*End*/ +// *Start*/ +// defer /*Defer*/ func() {}() /*End*/ +// +// // type DeferStmtDecorations struct { NodeDecs Defer Decorations @@ -189,20 +203,26 @@ type FileDecorations struct { // ForStmtDecorations holds decorations for ForStmt: // -// /*Start*/ -// for /*For*/ { -// i++ -// } /*End*/ +// *Start*/ +// for /*For*/ { +// i++ +// } /*End*/ // -// /*Start*/ -// for /*For*/ i < 1 /*Cond*/ { -// i++ -// } /*End*/ +// // // -// /*Start*/ -// for /*For*/ i = 0; /*Init*/ i < 10; /*Cond*/ i++ /*Post*/ { -// i++ -// } /*End*/ +// *Start*/ +// for /*For*/ i < 1 /*Cond*/ { +// i++ +// } /*End*/ +// +// // +// +// *Start*/ +// for /*For*/ i = 0; /*Init*/ i < 10; /*Cond*/ i++ /*Post*/ { +// i++ +// } /*End*/ +// +// // type ForStmtDecorations struct { NodeDecs For Decorations @@ -213,25 +233,33 @@ type ForStmtDecorations struct { // FuncDeclDecorations holds decorations for FuncDecl: // -// /*Start*/ +// Start*/ // func /*Func*/ d /*Name*/ (d, e int) /*Params*/ { // return // } /*End*/ // -// /*Start*/ +// // +// +// Start*/ // func /*Func*/ TP /*Name*/ [P any] /*TypeParams*/ (a int) /*Params*/ (b P) /*Results*/ { // return b // } /*End*/ // -// /*Start*/ +// // +// +// Start*/ // func /*Func*/ (a *A) /*Recv*/ e /*Name*/ (d, e int) /*Params*/ { // return // } /*End*/ // -// /*Start*/ +// // +// +// Start*/ // func /*Func*/ (a *A) /*Recv*/ f /*Name*/ (d, e int) /*Params*/ (f, g int) /*Results*/ { // return // } /*End*/ +// +// // type FuncDeclDecorations struct { NodeDecs Func Decorations @@ -262,14 +290,18 @@ type FuncTypeDecorations struct { // GenDeclDecorations holds decorations for GenDecl: // -// /*Start*/ -// const /*Tok*/ ( /*Lparen*/ -// a, b = 1, 2 -// c = 3 -// ) /*End*/ +// *Start*/ +// const /*Tok*/ ( /*Lparen*/ +// a, b = 1, 2 +// c = 3 +// ) /*End*/ // -// /*Start*/ -// const /*Tok*/ d = 1 /*End*/ +// // +// +// *Start*/ +// const /*Tok*/ d = 1 /*End*/ +// +// // type GenDeclDecorations struct { NodeDecs Tok Decorations @@ -278,8 +310,10 @@ type GenDeclDecorations struct { // GoStmtDecorations holds decorations for GoStmt: // -// /*Start*/ -// go /*Go*/ func() {}() /*End*/ +// *Start*/ +// go /*Go*/ func() {}() /*End*/ +// +// // type GoStmtDecorations struct { NodeDecs Go Decorations @@ -287,11 +321,15 @@ type GoStmtDecorations struct { // IdentDecorations holds decorations for Ident: // -// /*Start*/ -// i /*End*/ ++ +// *Start*/ +// i /*End*/ ++ // -// /*Start*/ -// fmt. /*X*/ Print /*End*/ () +// // +// +// *Start*/ +// fmt. /*X*/ Print /*End*/ () +// +// // type IdentDecorations struct { NodeDecs X Decorations @@ -299,12 +337,14 @@ type IdentDecorations struct { // IfStmtDecorations holds decorations for IfStmt: // -// /*Start*/ -// if /*If*/ a := b; /*Init*/ a /*Cond*/ { -// i++ -// } else /*Else*/ { -// i++ -// } /*End*/ +// *Start*/ +// if /*If*/ a := b; /*Init*/ a /*Cond*/ { +// i++ +// } else /*Else*/ { +// i++ +// } /*End*/ +// +// // type IfStmtDecorations struct { NodeDecs If Decorations @@ -325,8 +365,10 @@ type ImportSpecDecorations struct { // IncDecStmtDecorations holds decorations for IncDecStmt: // -// /*Start*/ -// i /*X*/ ++ /*End*/ +// *Start*/ +// i /*X*/ ++ /*End*/ +// +// // type IncDecStmtDecorations struct { NodeDecs X Decorations @@ -344,7 +386,9 @@ type IndexExprDecorations struct { // IndexListExprDecorations holds decorations for IndexListExpr: // -// var T4 /*Start*/ T3 /*X*/ [ /*Lbrack*/ int, string /*Indices*/] /*End*/ +// ar T4 /*Start*/ T3 /*X*/ [ /*Lbrack*/ int, string /*Indices*/] /*End*/ +// +// // type IndexListExprDecorations struct { NodeDecs X Decorations @@ -378,6 +422,8 @@ type KeyValueExprDecorations struct { // /*Start*/ // A /*Label*/ : /*Colon*/ // print("Stmt") /*End*/ +// +// // type LabeledStmtDecorations struct { NodeDecs Label Decorations @@ -409,19 +455,25 @@ type ParenExprDecorations struct { // RangeStmtDecorations holds decorations for RangeStmt: // -// /*Start*/ -// for range /*Range*/ a /*X*/ { -// } /*End*/ +// *Start*/ +// for range /*Range*/ a /*X*/ { +// } /*End*/ // -// /*Start*/ -// for /*For*/ k /*Key*/ := range /*Range*/ a /*X*/ { -// print(k) -// } /*End*/ +// // // -// /*Start*/ -// for /*For*/ k /*Key*/, v /*Value*/ := range /*Range*/ a /*X*/ { -// print(k, v) -// } /*End*/ +// *Start*/ +// for /*For*/ k /*Key*/ := range /*Range*/ a /*X*/ { +// print(k) +// } /*End*/ +// +// // +// +// *Start*/ +// for /*For*/ k /*Key*/, v /*Value*/ := range /*Range*/ a /*X*/ { +// print(k, v) +// } /*End*/ +// +// // type RangeStmtDecorations struct { NodeDecs For Decorations @@ -433,9 +485,11 @@ type RangeStmtDecorations struct { // ReturnStmtDecorations holds decorations for ReturnStmt: // -// func() int { -// /*Start*/ return /*Return*/ 1 /*End*/ -// }() +// unc() int { +// /*Start*/ return /*Return*/ 1 /*End*/ +// }() +// +// // type ReturnStmtDecorations struct { NodeDecs Return Decorations @@ -443,9 +497,11 @@ type ReturnStmtDecorations struct { // SelectStmtDecorations holds decorations for SelectStmt: // -// /*Start*/ -// select /*Select*/ { -// } /*End*/ +// *Start*/ +// select /*Select*/ { +// } /*End*/ +// +// // type SelectStmtDecorations struct { NodeDecs Select Decorations @@ -461,8 +517,10 @@ type SelectorExprDecorations struct { // SendStmtDecorations holds decorations for SendStmt: // -// /*Start*/ -// c /*Chan*/ <- /*Arrow*/ 0 /*End*/ +// *Start*/ +// c /*Chan*/ <- /*Arrow*/ 0 /*End*/ +// +// // type SendStmtDecorations struct { NodeDecs Chan Decorations @@ -511,13 +569,17 @@ type StructTypeDecorations struct { // SwitchStmtDecorations holds decorations for SwitchStmt: // -// /*Start*/ -// switch /*Switch*/ i /*Tag*/ { -// } /*End*/ +// *Start*/ +// switch /*Switch*/ i /*Tag*/ { +// } /*End*/ // -// /*Start*/ -// switch /*Switch*/ a := i; /*Init*/ a /*Tag*/ { -// } /*End*/ +// // +// +// *Start*/ +// switch /*Switch*/ a := i; /*Init*/ a /*Tag*/ { +// } /*End*/ +// +// // type SwitchStmtDecorations struct { NodeDecs Switch Decorations @@ -537,40 +599,53 @@ type TypeAssertExprDecorations struct { // TypeSpecDecorations holds decorations for TypeSpec: // -// type ( -// /*Start*/ T1 /*Name*/ []int /*End*/ -// ) +// ype ( +// /*Start*/ T1 /*Name*/ []int /*End*/ +// ) // -// type ( -// /*Start*/ T2 = /*Name*/ T1 /*End*/ -// ) +// // // -// type ( -// /*Start*/ T3 /*Name*/ [P any, Q any] /*TypeParams*/ []P /*End*/ -// ) +// ype ( +// /*Start*/ T2 = /*Assign*/ T1 /*End*/ +// ) +// +// // +// +// ype ( +// /*Start*/ T3 /*Name*/ [P any, Q any] /*TypeParams*/ []P /*End*/ +// ) +// +// // type TypeSpecDecorations struct { NodeDecs Name Decorations TypeParams Decorations + Assign Decorations } // TypeSwitchStmtDecorations holds decorations for TypeSwitchStmt: // -// /*Start*/ -// switch /*Switch*/ f.(type) /*Assign*/ { -// } /*End*/ +// *Start*/ +// switch /*Switch*/ f.(type) /*Assign*/ { +// } /*End*/ // -// /*Start*/ -// switch /*Switch*/ g := f.(type) /*Assign*/ { -// case int: -// print(g) -// } /*End*/ +// // // -// /*Start*/ -// switch /*Switch*/ g := f; /*Init*/ g := g.(type) /*Assign*/ { -// case int: -// print(g) -// } /*End*/ +// *Start*/ +// switch /*Switch*/ g := f.(type) /*Assign*/ { +// case int: +// print(g) +// } /*End*/ +// +// // +// +// *Start*/ +// switch /*Switch*/ g := f; /*Init*/ g := g.(type) /*Assign*/ { +// case int: +// print(g) +// } /*End*/ +// +// // type TypeSwitchStmtDecorations struct { NodeDecs Switch Decorations @@ -588,17 +663,23 @@ type UnaryExprDecorations struct { // ValueSpecDecorations holds decorations for ValueSpec: // -// var ( -// /*Start*/ j = /*Assign*/ 1 /*End*/ -// ) +// ar ( +// /*Start*/ j = /*Assign*/ 1 /*End*/ +// ) // -// var ( -// /*Start*/ k, l = /*Assign*/ 1, 2 /*End*/ -// ) +// // // -// var ( -// /*Start*/ m, n int = /*Assign*/ 1, 2 /*End*/ -// ) +// ar ( +// /*Start*/ k, l = /*Assign*/ 1, 2 /*End*/ +// ) +// +// // +// +// ar ( +// /*Start*/ m, n int = /*Assign*/ 1, 2 /*End*/ +// ) +// +// // type ValueSpecDecorations struct { NodeDecs Assign Decorations diff --git a/decorator/alias_test.go b/decorator/alias_test.go new file mode 100644 index 0000000..a5f9b5f --- /dev/null +++ b/decorator/alias_test.go @@ -0,0 +1,107 @@ +package decorator + +import ( + "bytes" + "go/format" + "testing" +) + +// TestGenericTypeAliases verifies the correct decoration and round-trip restoration +// of Go 1.24 Generic Type Aliases (e.g., type A[T any] = B[T]). +// +// This validates that the combination of TypeParams and Assign (aliasing) co-existing +// on a TypeSpec does not cause decoration conflicts or restoration ordering issues. +func TestGenericTypeAliases(t *testing.T) { + tests := []struct { + name string + code string + }{ + { + name: "basic-generic-alias", + code: `package main + +type Vector[T any] = []T`, + }, + { + name: "multiple-type-params", + code: `package main + +type MapAlias[K comparable, V any] = map[K]V`, + }, + { + name: "complex-constraints", + code: `package main + +type Number[T int | float64] = T`, + }, + { + name: "decorated-type-params", + // Verifies comments attached to TypeParams do not bleed into the Assign token + code: `package main + +type List /*a*/ [T any] = /*b*/ /*c*/ []T`, + }, + { + name: "decorated-assignment", + // Verifies strict separation between the generic list and the right-hand side type + code: `package main + +// Start +type Alias /*1*/ [T any] /*2*/ = /*3*/ Target[T] // End`, + }, + { + name: "multiline-generic-alias", + code: `package main + +type BigAlias[ + T any, + U comparable, +] = struct { + a T + b U +}`, + }, + { + name: "interface-constraint-alias", + code: `package main + +type Stringer = interface { + String() string +} + +type Ptr[T Stringer] = *T`, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // Ensure source is formatted for consistent comparison + expectBytes, err := format.Source([]byte(test.code)) + if err != nil { + t.Fatalf("format.Source error: %v", err) + } + expected := string(expectBytes) + + // Parse using dst decorator + f, err := Parse(expected) + if err != nil { + t.Fatalf("decorator.Parse error: %v", err) + } + + // Restore to AST and print + // We use a fresh restorer to ensure no decoration state leakage + r := NewRestorer() + buf := &bytes.Buffer{} + if err := r.Fprint(buf, f); err != nil { + t.Fatalf("restorer.Fprint error: %v", err) + } + + got := buf.String() + + // Normalize whitespace for robust comparison + if normalize(got) != normalize(expected) { + t.Errorf("Round-trip mismatch.\nExpected:\n%s\nGot:\n%s\nDiff:\n%s", expected, got, diff(normalize(expected), normalize(got))) + } + }) + } +} diff --git a/decorator/decorator-fragment-generated.go b/decorator/decorator-fragment-generated.go index 4fbb7fc..58edde8 100644 --- a/decorator/decorator-fragment-generated.go +++ b/decorator/decorator-fragment-generated.go @@ -1428,11 +1428,6 @@ func (f *fileDecorator) addNodeFragments(n ast.Node) { f.addNodeFragments(n.Name) } - // Token: Assign - if n.Assign.IsValid() { - f.addTokenFragment(n, token.ASSIGN, n.Assign) - } - // Decoration: Name f.addDecorationFragment(n, "Name", token.NoPos) @@ -1446,6 +1441,16 @@ func (f *fileDecorator) addNodeFragments(n ast.Node) { f.addDecorationFragment(n, "TypeParams", token.NoPos) } + // Token: Assign + if n.Assign.IsValid() { + f.addTokenFragment(n, token.ASSIGN, n.Assign) + } + + // Decoration: Assign + if n.Assign.IsValid() { + f.addDecorationFragment(n, "Assign", token.NoPos) + } + // Node: Type if n.Type != nil { f.addNodeFragments(n.Type) diff --git a/decorator/decorator-node-generated.go b/decorator/decorator-node-generated.go index 72044ec..4c70f79 100644 --- a/decorator/decorator-node-generated.go +++ b/decorator/decorator-node-generated.go @@ -808,6 +808,9 @@ func (f *fileDecorator) decorateNode(parent ast.Node, parentName, parentField, p out.Imports = append(out.Imports, child.(*dst.ImportSpec)) } + // Value: GoVersion + out.GoVersion = n.GoVersion + if nd, ok := f.decorations[n]; ok { if decs, ok := nd["Start"]; ok { out.Decs.Start = decs @@ -2198,9 +2201,6 @@ func (f *fileDecorator) decorateNode(parent ast.Node, parentName, parentField, p out.Name = child.(*dst.Ident) } - // Token: Assign - out.Assign = n.Assign.IsValid() - // Node: TypeParams if n.TypeParams != nil { child, err := f.decorateNode(n, "TypeSpec", "TypeParams", "FieldList", n.TypeParams) @@ -2210,6 +2210,9 @@ func (f *fileDecorator) decorateNode(parent ast.Node, parentName, parentField, p out.TypeParams = child.(*dst.FieldList) } + // Token: Assign + out.Assign = n.Assign.IsValid() + // Node: Type if n.Type != nil { child, err := f.decorateNode(n, "TypeSpec", "Type", "Expr", n.Type) @@ -2229,6 +2232,9 @@ func (f *fileDecorator) decorateNode(parent ast.Node, parentName, parentField, p if decs, ok := nd["TypeParams"]; ok { out.Decs.TypeParams = decs } + if decs, ok := nd["Assign"]; ok { + out.Decs.Assign = decs + } if decs, ok := nd["End"]; ok { out.Decs.End = decs } diff --git a/decorator/iterator_test.go b/decorator/iterator_test.go index bcfe6c7..193147d 100644 --- a/decorator/iterator_test.go +++ b/decorator/iterator_test.go @@ -118,7 +118,7 @@ func main() { // Normalize strings to ignore insignificant whitespace differences if necessary, // though typical round-trip should be exact for formatted code. got := buf.String() - + // Use the diff helper assumed to be present in the package from other tests // (e.g. wrapper around diffmatchpatch as seen in existing tests like decorator_fragment_test.go) if normalize(got) != normalize(expectedCode) { @@ -126,4 +126,4 @@ func main() { } }) } -} \ No newline at end of file +} diff --git a/decorator/restorer-generated.go b/decorator/restorer-generated.go index 4b5728f..2f0fd81 100644 --- a/decorator/restorer-generated.go +++ b/decorator/restorer-generated.go @@ -2,10 +2,9 @@ package decorator import ( "fmt" + "github.com/dave/dst" "go/ast" "go/token" - - "github.com/dave/dst" ) func (r *FileRestorer) restoreNode(n dst.Node, parentName, parentField, parentFieldType string, allowDuplicate bool) ast.Node { @@ -700,6 +699,9 @@ func (r *FileRestorer) restoreNode(n dst.Node, parentName, parentField, parentFi // Scope: Scope out.Scope = r.restoreScope(n.Scope) + + // Value: GoVersion + out.GoVersion = n.GoVersion r.applySpace(n, "After", n.Decs.After) return out @@ -1817,12 +1819,6 @@ func (r *FileRestorer) restoreNode(n dst.Node, parentName, parentField, parentFi out.Name = r.restoreNode(n.Name, "TypeSpec", "Name", "Ident", allowDuplicate).(*ast.Ident) } - // Token: Assign - if n.Assign { - out.Assign = r.cursor - r.cursor += token.Pos(len(token.ASSIGN.String())) - } - // Decoration: Name r.applyDecorations(out, "Name", n.Decs.Name, false) @@ -1834,6 +1830,15 @@ func (r *FileRestorer) restoreNode(n dst.Node, parentName, parentField, parentFi // Decoration: TypeParams r.applyDecorations(out, "TypeParams", n.Decs.TypeParams, false) + // Token: Assign + if n.Assign { + out.Assign = r.cursor + r.cursor += token.Pos(len(token.ASSIGN.String())) + } + + // Decoration: Assign + r.applyDecorations(out, "Assign", n.Decs.Assign, false) + // Node: Type if n.Type != nil { out.Type = r.restoreNode(n.Type, "TypeSpec", "Type", "Expr", allowDuplicate).(ast.Expr) diff --git a/dstutil/decorations-generated.go b/dstutil/decorations-generated.go index b3e3157..6e3bc49 100644 --- a/dstutil/decorations-generated.go +++ b/dstutil/decorations-generated.go @@ -343,6 +343,7 @@ func decorations(n dst.Node) (before, after dst.SpaceType, points []DecorationPo points = append(points, DecorationPoint{"Start", n.Decs.Start}) points = append(points, DecorationPoint{"Name", n.Decs.Name}) points = append(points, DecorationPoint{"TypeParams", n.Decs.TypeParams}) + points = append(points, DecorationPoint{"Assign", n.Decs.Assign}) points = append(points, DecorationPoint{"End", n.Decs.End}) case *dst.TypeSwitchStmt: before = n.Decs.Before diff --git a/gendst/data/data.go b/gendst/data/data.go index 4906a2a..4180758 100644 --- a/gendst/data/data.go +++ b/gendst/data/data.go @@ -20,13 +20,13 @@ var Info = map[string][]Part{ // Field.Names is nil for unnamed parameters (parameter lists which only contain types) // and embedded struct fields. In the latter case, the field name is the type name. // - type Field struct { - Doc *CommentGroup // associated documentation; or nil - Names []*Ident // field/method/(type) parameter names; or nil - Type Expr // field/method/(type) parameter type - Tag *BasicLit // field tag; or nil - Comment *CommentGroup // line comments; or nil - } + // type Field struct { + // Doc *CommentGroup // associated documentation; or nil + // Names []*Ident // field/method/(type) parameter names; or nil + // Type Expr // field/method/(type) parameter type + // Tag *BasicLit // field tag; or nil + // Comment *CommentGroup // line comments; or nil + // } */ "Field": { Decoration{ @@ -111,9 +111,9 @@ var Info = map[string][]Part{ // syntax errors for which no correct expression nodes can be // created. // - BadExpr struct { - From, To token.Pos // position range of bad expression - } + // BadExpr struct { + // From, To token.Pos // position range of bad expression + // } */ "BadExpr": { Decoration{ @@ -171,10 +171,10 @@ var Info = map[string][]Part{ // An Ellipsis node stands for the "..." type in a // parameter list or the "..." length in an array type. // - Ellipsis struct { - Ellipsis token.Pos // position of "..." - Elt Expr // ellipsis element type (parameter lists only); or nil - } + // Ellipsis struct { + // Ellipsis token.Pos // position of "..." + // Elt Expr // ellipsis element type (parameter lists only); or nil + // } */ "Ellipsis": { Decoration{ @@ -555,12 +555,12 @@ var Info = map[string][]Part{ // A TypeAssertExpr node represents an expression followed by a // type assertion. // - TypeAssertExpr struct { - X Expr // expression - Lparen token.Pos // position of "(" - Type Expr // asserted type; nil means type switch X.(type) - Rparen token.Pos // position of ")" - } + // TypeAssertExpr struct { + // X Expr // expression + // Lparen token.Pos // position of "(" + // Type Expr // asserted type; nil means type switch X.(type) + // Rparen token.Pos // position of ")" + // } */ "TypeAssertExpr": { Decoration{ @@ -674,10 +674,10 @@ var Info = map[string][]Part{ // A StarExpr node represents an expression of the form "*" Expression. // Semantically it could be a unary "*" expression, or a pointer type. // - StarExpr struct { - Star token.Pos // position of "*" - X Expr // operand - } + // StarExpr struct { + // Star token.Pos // position of "*" + // X Expr // operand + // } */ "StarExpr": { Decoration{ @@ -704,11 +704,11 @@ var Info = map[string][]Part{ // A UnaryExpr node represents a unary expression. // Unary "*" expressions are represented via StarExpr nodes. // - UnaryExpr struct { - OpPos token.Pos // position of Op - Op token.Token // operator - X Expr // operand - } + // UnaryExpr struct { + // OpPos token.Pos // position of Op + // Op token.Token // operator + // X Expr // operand + // } */ "UnaryExpr": { Decoration{ @@ -775,11 +775,11 @@ var Info = map[string][]Part{ // A KeyValueExpr node represents (key : value) pairs // in composite literals. // - KeyValueExpr struct { - Key Expr - Colon token.Pos // position of ":" - Value Expr - } + // KeyValueExpr struct { + // Key Expr + // Colon token.Pos // position of ":" + // Value Expr + // } */ "KeyValueExpr": { Decoration{ @@ -1095,9 +1095,9 @@ var Info = map[string][]Part{ // syntax errors for which no correct statement nodes can be // created. // - BadStmt struct { - From, To token.Pos // position range of bad statement - } + // BadStmt struct { + // From, To token.Pos // position range of bad statement + // } */ "BadStmt": { Decoration{ @@ -1142,10 +1142,10 @@ var Info = map[string][]Part{ // The "position" of the empty statement is the position // of the immediately following (explicit or implicit) semicolon. // - EmptyStmt struct { - Semicolon token.Pos // position of following ";" - Implicit bool // if set, ";" was omitted in the source - } + // EmptyStmt struct { + // Semicolon token.Pos // position of following ";" + // Implicit bool // if set, ";" was omitted in the source + // } */ "EmptyStmt": { Decoration{ @@ -1206,9 +1206,9 @@ var Info = map[string][]Part{ // An ExprStmt node represents a (stand-alone) expression // in a statement list. // - ExprStmt struct { - X Expr // expression - } + // ExprStmt struct { + // X Expr // expression + // } */ "ExprStmt": { Decoration{ @@ -1296,12 +1296,12 @@ var Info = map[string][]Part{ // An AssignStmt node represents an assignment or // a short variable declaration. // - AssignStmt struct { - Lhs []Expr - TokPos token.Pos // position of Tok - Tok token.Token // assignment token, DEFINE - Rhs []Expr - } + // AssignStmt struct { + // Lhs []Expr + // TokPos token.Pos // position of Tok + // Tok token.Token // assignment token, DEFINE + // Rhs []Expr + // } */ "AssignStmt": { Decoration{ @@ -1421,11 +1421,11 @@ var Info = map[string][]Part{ // A BranchStmt node represents a break, continue, goto, // or fallthrough statement. // - BranchStmt struct { - TokPos token.Pos // position of Tok - Tok token.Token // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH) - Label *Ident // label name; or nil - } + // BranchStmt struct { + // TokPos token.Pos // position of Tok + // Tok token.Token // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH) + // Label *Ident // label name; or nil + // } */ "BranchStmt": { Decoration{ @@ -1951,13 +1951,13 @@ var Info = map[string][]Part{ // A ValueSpec node represents a constant or variable declaration // (ConstSpec or VarSpec production). // - ValueSpec struct { - Doc *CommentGroup // associated documentation; or nil - Names []*Ident // value names (len(Names) > 0) - Type Expr // value type; or nil - Values []Expr // initial values; or nil - Comment *CommentGroup // line comments; or nil - } + // ValueSpec struct { + // Doc *CommentGroup // associated documentation; or nil + // Names []*Ident // value names (len(Names) > 0) + // Type Expr // value type; or nil + // Values []Expr // initial values; or nil + // Comment *CommentGroup // line comments; or nil + // } */ "ValueSpec": { Decoration{ @@ -2013,16 +2013,6 @@ var Info = map[string][]Part{ Field: Field{"Name"}, Type: Struct{"Ident"}, }, - Token{ - Name: "Assign", - Token: Basic{jen.Qual("go/token", "ASSIGN")}, - Exists: Double{ - Ast: Expr(func(n *jen.Statement) *jen.Statement { return n.Dot("Assign").Dot("IsValid").Call() }), - Dst: Expr(func(n *jen.Statement) *jen.Statement { return n.Dot("Assign") }), - }, - ExistsField: Field{"Assign"}, - PositionField: Field{"Assign"}, - }, Decoration{ Name: "Name", }, @@ -2035,6 +2025,23 @@ var Info = map[string][]Part{ Name: "TypeParams", Use: Expr(func(n *jen.Statement) *jen.Statement { return n.Dot("TypeParams").Op("!=").Nil() }), }, + Token{ + Name: "Assign", + Token: Basic{jen.Qual("go/token", "ASSIGN")}, + Exists: Double{ + Ast: Expr(func(n *jen.Statement) *jen.Statement { return n.Dot("Assign").Dot("IsValid").Call() }), + Dst: Expr(func(n *jen.Statement) *jen.Statement { return n.Dot("Assign") }), + }, + ExistsField: Field{"Assign"}, + PositionField: Field{"Assign"}, + }, + Decoration{ + Name: "Assign", // Explicit decoration point for '=' + Use: Double{ + Ast: Expr(func(n *jen.Statement) *jen.Statement { return n.Dot("Assign").Dot("IsValid").Call() }), + Dst: Expr(func(n *jen.Statement) *jen.Statement { return n.Dot("Assign") }), + }, + }, Node{ Name: "Type", Field: Field{"Type"}, @@ -2049,9 +2056,9 @@ var Info = map[string][]Part{ // syntax errors for which no correct declaration nodes can be // created. // - BadDecl struct { - From, To token.Pos // position range of bad declaration - } + // BadDecl struct { + // From, To token.Pos // position range of bad declaration + // } */ "BadDecl": { Decoration{ diff --git a/gendst/data/positions.go b/gendst/data/positions.go index fa5e242..1d7de9a 100644 --- a/gendst/data/positions.go +++ b/gendst/data/positions.go @@ -280,7 +280,7 @@ A /*Label*/ : /*Colon*/ // TypeSpec(1) type ( - /*Start*/ T2 = /*Name*/ T1 /*End*/ + /*Start*/ T2 = /*Assign*/ T1 /*End*/ ) // TypeSpec(2)