├── LICENSE ├── README.md ├── go.mod ├── main.go └── testdata └── sample.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Kensei Nakada 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # easydebug 2 | tool: add debug statements after statements to store values 3 | 4 | - You can add debug statements after all statements to store values. 5 | - You can remove all debug statements with this tool, of course. 6 | - You can edit debug function `dmp` to arrange debug as you like 7 | 8 | 9 | ## Installation 10 | 11 | ``` 12 | go get -u github.com/sanposhiho/easydebug 13 | ``` 14 | 15 | ## Usage 16 | 17 | ### add debug statements 18 | 19 | ``` 20 | easydebug -f target.go -mode 0 21 | ``` 22 | 23 | ### remove debug statements 24 | 25 | ``` 26 | easydebug -f target.go -mode 1 27 | ``` 28 | 29 | ## sample 30 | 31 | ### before 32 | 33 | ``` 34 | package main 35 | 36 | func test() int { 37 | hoge := 1 38 | 39 | fuga := 3 40 | 41 | if hoge == 2 { 42 | fuga = abusoluteTwo() 43 | 44 | hoge = 12 45 | 46 | } 47 | 48 | return hoge + fuga 49 | } 50 | 51 | func abusoluteTwo() int { 52 | return 2 53 | } 54 | ``` 55 | 56 | ### after 57 | 58 | ``` 59 | package main 60 | 61 | func test() int { 62 | hoge := 1 63 | dmp("hoge", hoge) 64 | 65 | fuga := 3 66 | dmp("fuga", fuga) 67 | 68 | if hoge == 2 { 69 | fuga = abusoluteTwo() 70 | dmp("fuga", fuga) 71 | 72 | hoge = 12 73 | dmp("hoge", hoge) 74 | 75 | } 76 | 77 | return hoge + fuga 78 | } 79 | 80 | func abusoluteTwo() int { 81 | return 2 82 | } 83 | 84 | // generated from goeasydebug 85 | // function for data dump 86 | func dmp(valueName string, v ...interface{}) { 87 | for _, vv := range(v) { 88 | // arrange debug as you like 89 | fmt.Printf("%s: %#v\n",valueName, vv) 90 | } 91 | } 92 | ``` 93 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/sanposhiho/easydebug 2 | 3 | go 1.14 4 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "os" 10 | 11 | "go/ast" 12 | "go/format" 13 | "go/parser" 14 | "go/token" 15 | ) 16 | 17 | var ( 18 | mode = flag.Int("mode", 0, "mode must be set\n 0: add debug statements\n 1: remove debug statements\n") 19 | filename = flag.String("f", "", "target filename must be set\n") 20 | ) 21 | 22 | func Usage() { 23 | fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) 24 | flag.PrintDefaults() 25 | } 26 | 27 | func main() { 28 | log.SetFlags(0) 29 | log.SetPrefix("goeasydebug: ") 30 | flag.Usage = Usage 31 | flag.Parse() 32 | 33 | if *filename == "" { 34 | flag.Usage() 35 | os.Exit(2) 36 | } 37 | 38 | switch *mode { 39 | case 0: 40 | processAddDebugStatementsMode() 41 | case 1: 42 | processRemoveDebugStatementsMode() 43 | } 44 | } 45 | 46 | func rmDebugStmt(bodyList []ast.Stmt) ([]ast.Stmt, error) { 47 | result := []ast.Stmt{} 48 | for _, l := range bodyList { 49 | switch a := l.(type) { 50 | case *ast.ExprStmt: 51 | result = append(result, a) 52 | switch x := a.X.(type) { 53 | case *ast.CallExpr: 54 | switch f := x.Fun.(type) { 55 | case *ast.Ident: 56 | if f.Name == "dmp" { 57 | result = result[:len(result)-1] 58 | } 59 | } 60 | } 61 | case *ast.IfStmt: 62 | r, err := rmDebugStmt(a.Body.List) 63 | if err != nil { 64 | return result, err 65 | } 66 | a.Body.List = r 67 | result = append(result, a) 68 | case *ast.BlockStmt: 69 | r, err := rmDebugStmt(a.List) 70 | if err != nil { 71 | return result, err 72 | } 73 | a.List = r 74 | result = append(result, a) 75 | case *ast.SwitchStmt: 76 | r, err := rmDebugStmt(a.Body.List) 77 | if err != nil { 78 | return result, err 79 | } 80 | a.Body.List = r 81 | result = append(result, a) 82 | case *ast.TypeSwitchStmt: 83 | r, err := rmDebugStmt(a.Body.List) 84 | if err != nil { 85 | return result, err 86 | } 87 | a.Body.List = r 88 | result = append(result, a) 89 | case *ast.SelectStmt: 90 | r, err := rmDebugStmt(a.Body.List) 91 | if err != nil { 92 | return result, err 93 | } 94 | a.Body.List = r 95 | result = append(result, a) 96 | case *ast.ForStmt: 97 | r, err := rmDebugStmt(a.Body.List) 98 | if err != nil { 99 | return result, err 100 | } 101 | a.Body.List = r 102 | result = append(result, a) 103 | case *ast.RangeStmt: 104 | r, err := rmDebugStmt(a.Body.List) 105 | if err != nil { 106 | return result, err 107 | } 108 | a.Body.List = r 109 | result = append(result, a) 110 | default: 111 | result = append(result, a) 112 | } 113 | } 114 | 115 | return result, nil 116 | } 117 | 118 | func addDebugStmt(bodyList []ast.Stmt) ([]ast.Stmt, error) { 119 | result := []ast.Stmt{} 120 | for _, l := range bodyList { 121 | switch a := l.(type) { 122 | case *ast.AssignStmt: 123 | result = append(result, a) 124 | for _, lh := range a.Lhs { 125 | switch i := lh.(type) { 126 | case *ast.Ident: 127 | debug := fmt.Sprintf(`dmp("%s",%s)`, string(i.Name), string(i.Name)) 128 | ex, err := parser.ParseExpr(debug) 129 | if err != nil { 130 | return result, err 131 | } 132 | switch as := ex.(type) { 133 | case *ast.CallExpr: 134 | as.Args[1].(*ast.Ident).NamePos = token.Pos(int(as.Args[0].(*ast.BasicLit).ValuePos) + len(i.Name)) 135 | } 136 | debugStmt := &ast.ExprStmt{ 137 | X: ex, 138 | } 139 | result = append(result, debugStmt) 140 | } 141 | } 142 | case *ast.IfStmt: 143 | r, err := addDebugStmt(a.Body.List) 144 | if err != nil { 145 | return result, err 146 | } 147 | a.Body.List = r 148 | result = append(result, a) 149 | case *ast.BlockStmt: 150 | r, err := addDebugStmt(a.List) 151 | if err != nil { 152 | return result, err 153 | } 154 | a.List = r 155 | result = append(result, a) 156 | case *ast.SwitchStmt: 157 | r, err := addDebugStmt(a.Body.List) 158 | if err != nil { 159 | return result, err 160 | } 161 | a.Body.List = r 162 | result = append(result, a) 163 | case *ast.TypeSwitchStmt: 164 | r, err := addDebugStmt(a.Body.List) 165 | if err != nil { 166 | return result, err 167 | } 168 | a.Body.List = r 169 | result = append(result, a) 170 | case *ast.SelectStmt: 171 | r, err := addDebugStmt(a.Body.List) 172 | if err != nil { 173 | return result, err 174 | } 175 | a.Body.List = r 176 | result = append(result, a) 177 | case *ast.ForStmt: 178 | r, err := addDebugStmt(a.Body.List) 179 | if err != nil { 180 | return result, err 181 | } 182 | a.Body.List = r 183 | result = append(result, a) 184 | case *ast.RangeStmt: 185 | r, err := addDebugStmt(a.Body.List) 186 | if err != nil { 187 | return result, err 188 | } 189 | a.Body.List = r 190 | result = append(result, a) 191 | default: 192 | result = append(result, a) 193 | } 194 | } 195 | 196 | return result, nil 197 | } 198 | 199 | func processAddDebugStatementsMode() { 200 | fset := token.NewFileSet() 201 | 202 | file, err := parser.ParseFile(fset, *filename, nil, 0) 203 | if err != nil { 204 | log.Fatalln("Error:", err) 205 | return 206 | } 207 | 208 | f, err := ioutil.TempFile("", "goeasydebug.go") 209 | if err != nil { 210 | log.Fatalln("Error:", err) 211 | return 212 | } 213 | defer f.Close() 214 | 215 | writer := bufio.NewWriter(f) 216 | 217 | for _, d := range file.Decls { 218 | switch w := d.(type) { 219 | case *ast.FuncDecl: 220 | newBodyList, err := addDebugStmt(w.Body.List) 221 | if err != nil { 222 | log.Fatalln("Error:", err) 223 | return 224 | } 225 | w.Body.List = newBodyList 226 | } 227 | } 228 | 229 | if err := format.Node(writer, fset, file); err != nil { 230 | log.Fatalln("Error:", err) 231 | return 232 | } 233 | 234 | goeasydebugDefinition := ` 235 | // generated from goeasydebug 236 | // function for data dump 237 | func dmp(valueName string, v ...interface{}) { 238 | for _, vv := range(v) { 239 | // arrange debug as you like 240 | fmt.Printf("%s: %#v\n",valueName, vv) 241 | } 242 | } 243 | ` 244 | 245 | writer.WriteString(goeasydebugDefinition) 246 | 247 | writer.Flush() 248 | 249 | if err := os.Rename(f.Name(), *filename); err != nil { 250 | log.Fatalln("Error:", err) 251 | return 252 | } 253 | 254 | return 255 | } 256 | 257 | func processRemoveDebugStatementsMode() { 258 | fset := token.NewFileSet() 259 | 260 | file, err := parser.ParseFile(fset, *filename, nil, 0) 261 | if err != nil { 262 | log.Fatalln("Error:", err) 263 | return 264 | } 265 | 266 | f, err := ioutil.TempFile("", "goeasydebug.go") 267 | if err != nil { 268 | log.Fatalln("Error:", err) 269 | return 270 | } 271 | defer f.Close() 272 | 273 | writer := bufio.NewWriter(f) 274 | 275 | newDeclList := []ast.Decl{} 276 | for _, d := range file.Decls { 277 | switch w := d.(type) { 278 | case *ast.FuncDecl: 279 | if w.Name.Name == "dmp" { 280 | continue 281 | } 282 | newBodyList, err := rmDebugStmt(w.Body.List) 283 | if err != nil { 284 | log.Fatalln("Error:", err) 285 | return 286 | } 287 | w.Body.List = newBodyList 288 | } 289 | newDeclList = append(newDeclList, d) 290 | } 291 | 292 | file.Decls = newDeclList 293 | 294 | if err := format.Node(writer, fset, file); err != nil { 295 | log.Fatalln("Error:", err) 296 | return 297 | } 298 | 299 | writer.Flush() 300 | 301 | if err := os.Rename(f.Name(), *filename); err != nil { 302 | log.Fatalln("Error:", err) 303 | return 304 | } 305 | 306 | return 307 | } 308 | -------------------------------------------------------------------------------- /testdata/sample.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func test() int { 4 | hoge := 1 5 | 6 | fuga := 3 7 | 8 | if hoge == 2 { 9 | fuga = abusoluteTwo() 10 | 11 | hoge = 12 12 | 13 | } 14 | 15 | return hoge + fuga 16 | } 17 | 18 | func abusoluteTwo() int { 19 | return 2 20 | } 21 | --------------------------------------------------------------------------------