Example #1
0
// 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)
}
Example #2
0
// 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)
}
Example #3
0
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
}
Example #4
0
// 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)
}
Example #5
0
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())
}
Example #6
0
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
}