// FormatCode runs "goimports -w" on the source file. func (f *SourceFile) FormatCode() error { if NoFormat { return nil } // Parse file into AST fset := token.NewFileSet() file, err := parser.ParseFile(fset, f.Abs(), nil, parser.ParseComments) if err != nil { return err } // Clean unused imports imports := astutil.Imports(fset, file) for _, group := range imports { for _, imp := range group { path := strings.Trim(imp.Path.Value, `"`) if !astutil.UsesImport(file, path) { astutil.DeleteImport(fset, file, path) } } } ast.SortImports(fset, file) // Open file to be written w, err := os.OpenFile(f.Abs(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) if err != nil { return err } defer w.Close() // Write formatted code without unused imports return format.Node(w, fset, file) }
// FormatCode runs "goimports -w" on the source file. func (f *SourceFile) FormatCode() error { // Parse file into AST fset := token.NewFileSet() file, err := parser.ParseFile(fset, f.Abs(), nil, parser.ParseComments) if err != nil { content, _ := ioutil.ReadFile(f.Abs()) var buf bytes.Buffer scanner.PrintError(&buf, err) return fmt.Errorf("%s\n========\nContent:\n%s", buf.String(), content) } // Clean unused imports imports := astutil.Imports(fset, file) for _, group := range imports { for _, imp := range group { path := strings.Trim(imp.Path.Value, `"`) if !astutil.UsesImport(file, path) { if imp.Name != nil { astutil.DeleteNamedImport(fset, file, imp.Name.Name, path) } else { astutil.DeleteImport(fset, file, path) } } } } ast.SortImports(fset, file) // Open file to be written w, err := os.OpenFile(f.Abs(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) if err != nil { return err } defer w.Close() // Write formatted code without unused imports return format.Node(w, fset, file) }
func New() *noStateTenet { t := &noStateTenet{} t.SetInfo(tenet.Info{ Name: "worker_nostate", Usage: "workers should not access state directly", Description: "If you're passing a \\*state.State into your worker, you are almost certainly doing it wrong. The layers go worker->apiserver->state, and any attempt to skip past the apiserver layer should be viewed with *extreme* suspicion.", Language: "golang", SearchTags: []string{"juju", "worker"}, }) // We register any issues, metrics and tags that we'll be using. t.confidence = t.RegisterMetric("confidence") t.observability = t.RegisterTag("observability") t.maybeIssue = t.RegisterIssue("imports_state_returns_worker", tenet.AddComment(` I see you've imported state. A worker shouldn't need it. Best practice for writing workers: https://github.com/juju/juju/wiki/Guidelines-for-writing-workers `[1:]), ) t.mostLikelyIssue = t.RegisterIssue("func_takes_state_returns_worker", tenet.AddComment(` Please don't pass in a state object here. Workers should use the API. More info here: https://github.com/juju/juju/wiki/Guidelines-for-writing-workers `[1:]), ) // First, let's knock out any file that doesn't import state and worker. t.SmellNode(func(r tenet.Review, astFile *ast.File) error { if !astutil.UsesImport(astFile, "github.com/juju/juju/state") || !astutil.UsesImport(astFile, "github.com/juju/juju/worker") { // This file will no longer be smelt by this tenet. r.FileDone() } return nil }) t.smellFuncs() return t }
// Clean writes the clean source to io.Writer. The source can be a io.Reader, // string or []bytes func Clean(w io.Writer, src interface{}) error { fset := token.NewFileSet() file, err := parser.ParseFile(fset, "clean.go", src, parser.ParseComments) if err != nil { return err } // Clean unused imports imports := astutil.Imports(fset, file) for _, group := range imports { for _, imp := range group { path := strings.Trim(imp.Path.Value, `"`) if !astutil.UsesImport(file, path) { astutil.DeleteImport(fset, file, path) } } } ast.SortImports(fset, file) // Write formatted code without unused imports return format.Node(w, fset, file) }
func Generate(filename string, typenames ...string) ([]byte, error) { fset := token.NewFileSet() f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments) if err != nil { return nil, err } f = replace(func(node ast.Node) ast.Node { se, ok := node.(*ast.SelectorExpr) if !ok { return node } x, ok := se.X.(*ast.Ident) if !ok || x.Name != genericPkg { return node } for i, t := range genericTypes { if se.Sel.Name == t { return &ast.Ident{NamePos: 0, Name: typenames[i]} } } return node }, f).(*ast.File) if !astutil.UsesImport(f, pkgPath) { astutil.DeleteImport(fset, f, pkgPath) } var buf bytes.Buffer if err = format.Node(&buf, fset, f); err != nil { return nil, err } return format.Source(buf.Bytes()) }
func mainret(file *ast.File) bool { fixed := false // Add "os" import. addImport(file, "os") // Locate the "main" function. mainFunc, ok := findMainFunc(file) if !ok { return false } // Apply the following transitions for the "main" function: // // 1) // // from: // return 42 // // // to: // os.Exit(42) // // 2) // // from: // return 0 // // // to: // return // // 3) // // from: // func main() { // return // } // // // to: // func main() { // } walk(mainFunc, func(n interface{}) { stmt, ok := n.(*ast.Stmt) if !ok { return } retStmt, ok := (*stmt).(*ast.ReturnStmt) if !ok { return } switch len(retStmt.Results) { case 0: // Leave blank returns as is. return case 1: result := retStmt.Results[0] if isZero(result) { // Replace "return 0" with "return". retStmt.Results = nil } else { // Replace "return 42" with "os.Exit(42)". exit := createExit(result) *stmt = exit } fixed = true default: log.Fatalf("invalid number of arguments to return; expected 1, got %d", len(retStmt.Results)) } }) // Remove "os" import if not required. if !astutil.UsesImport(file, "os") { astutil.DeleteImport(token.NewFileSet(), file, "os") } // Remove trailing blank return statement. list := mainFunc.Body.List n := len(list) if n > 0 { if isEmptyReturn(list[n-1]) { mainFunc.Body.List = list[:n-1] fixed = true } } return fixed }