deferror

package module
v0.0.0-...-6bcf11d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 28, 2023 License: MIT Imports: 11 Imported by: 0

README

deferror

Deferror is a Go linter that suggests a customly made defer function call when the function has a return named error and the function does not already start with a defer call.

Install

go install github.com/Jiang-Gianni/deferror/cmd/deferror@latest

How to use

A template file for the deferred function call is needed.

To generate a template file like deferror.tmpl with a custom name in the current directory:

deferror init -o "yourDeferror.tmpl"

If the -o flag is not specified then the file will be generated as deferror.tmpl.

To run the linter on a go file:

DFRR_FILE=yourDeferror.tmpl deferror yourGoFile.go

If the environment variable DFRR_FILE is not specified, the linter will look for deferror.tmpl as the template.

Add the -fix flag to make the linter write the suggested defer function call:

DFRR_FILE=yourDeferror.tmpl deferror -fix yourGoFile.go

Template

The template must uses text/template package. The functions in the strings package are made available (see funcmap.go).

The structure of the input data map is the following (type F):

type F struct {
	PkgName     string
	PkgPath     string
	FnName      string
	RecvName    string
	RecvType    string
	RecvPointer bool
	Params      []P
	ErrName     string
}

type P struct {
	Name    string
	Type    string
	Pointer bool
}

Example

readme.go

package example

import (
	"time"
)

type R struct{}

func (r *R) MyExample(now time.Duration, i *int) (a int, err error) {
	return 0, nil
}

The input data map for the template is:

&{PkgName:example PkgPath:github.com/Jiang-Gianni/deferror/example FnName:MyExample RecvName:r RecvType:*R RecvPointer:true Params:[{Name:now Type:time.Duration Pointer:false} {Name:i Type:*int Pointer:true}] ErrName: err}

The following defer call is suggested with the default template:

	defer func(now time.Duration, i *int) {
		if err != nil {
			err = fmt.Errorf("r.MyExample(%v, %v, ): %w", now, i, err)
		}
	}(now, i)

Tips

Wrap function wrap.go

With a Wrap function like this:

package dfrr

import "fmt"

func Wrap(errp *error, format string, args ...any) {
	if *errp != nil {
		*errp = fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), *errp)
	}
}

the template can be simplified to:

{{define "main"}}   defer dfrr.Wrap(&err, "{{if .RecvName}}{{.RecvName}}.{{end}}{{.FnName}}({{template "percV" .}})", {{template "plist" .}})
{{end}}

{{define "plist"}}{{range $item := .Params}}{{$item.Name}}, {{end}}{{end}}

{{define "percV"}}{{range $item := .Params}}%v, {{end}}{{end}}

which suggests (dfrr module will need to be imported):

defer dfrr.Wrap(&err, "r.MyExample(%v, %v, )", now, i)

You can clone this repository and try it yourself on the example folder.

Subpackage templates

By using the strings package functions it is possible to determine if the analyzed function package name or path contains a substring which means it allows to define subpackage specific templates.

For example you may want to add the complete input list values to the wrapping error message only inside critical package.

{{if Contains .PkgPath "/api/"}}
{{template "apiDefer" .}}
{{end}}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Analyzer = &analysis.Analyzer{
	Name:             "deferror",
	Doc:              doc,
	Run:              run,
	RunDespiteErrors: false,
	Requires: []*analysis.Analyzer{
		inspect.Analyzer,
		buildssa.Analyzer,
	},
}

Analyzer is ...

Functions

This section is empty.

Types

type A

type A struct {
	// contains filtered or unexported fields
}

type F

type F struct {
	PkgName     string
	PkgPath     string
	FnName      string
	RecvName    string
	RecvType    string
	RecvPointer bool
	Params      []P
	ErrName     string
}

type P

type P struct {
	Name    string
	Type    string
	Pointer bool
}

Directories

Path Synopsis
cmd
watch
fw

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL