golangci-lint 自定义linter核心代码 用于检查错误使用gtime.Time.Format() 例如gtime.Time.Format(“2006-01-02 15:04:05“)

这篇博客介绍了一个针对GoFrame框架中gtime.Time类型Format方法使用的静态代码分析工具。由于gtime.Time的Format方法与标准库time.Time的Format方法参数不同,容易导致误用且不易察觉。该分析工具旨在检测并报告可能的错误参数,以提高代码质量。示例代码展示了如何识别和报告不正确的Format方法调用。
摘要由CSDN通过智能技术生成

gtime.Time对象通过Format方法来实现自定义格式的时间日期转换,该方法与标准库time.Time的Format方法冲突。在gtime.Time对象中,通过Layout方法实现标准库time.Time的Format格式,例如:t.Layout(2006-01-02 15:04:05)。

gtime.Time是GoFrame框架的时间类型,它的Format方法的形参与标准库Format方法的形参完全不同。
很多人会使用错误,而且使用错误不会报错;导致难以发现。
本代码只是Demo阶段,未测试,不能保证识别的准确和完整性
文末有示例代码,用于识别测试
本代码参考:https://disaev.me/p/writing-useful-go-analysis-linter/

package analyzer

import (
	"flag"
	"go/ast"
	"golang.org/x/tools/go/analysis"
	"strings"
)

var Analyzer = &analysis.Analyzer{
	Name:  "gtimeFormatLinter",
	Doc:   "gtime.Time is the time type of the Go Frame framework. The formal parameters of its Format method are completely different from those of the Format method in the standard library.",
	Flags: flag.FlagSet{},
	Run:   run,
}

func callMultiplexing(call *ast.CallExpr, pass *analysis.Pass, formatSymbols []string) {
	if call.Args == nil || len(call.Args) == 0 {
		return
	}
	for _, arg := range call.Args {
		if arg == nil {
			continue
		}
		bas, ok := arg.(*ast.BasicLit)
		if !ok {
			continue
		}
		var existence bool
		for _, formatSymbol := range formatSymbols {
			if strings.Contains(bas.Value, formatSymbol) {
				existence = true
			}
		}
		if existence {
			pass.Reportf(bas.Pos(), "Incorrect formal parameters of the Format method of gtime.Time")
		}
	}
}
func run(pass *analysis.Pass) (interface{}, error) {
	var formatSymbols = []string{"2006", "01", "02", "15", "04", "05"}
	inspect := func(node ast.Node) bool {
		fun, ok := node.(*ast.FuncDecl)
		if !ok {
			return true
		}
		if fun.Body == nil || fun.Body.List == nil || len(fun.Body.List) == 0 {
			return true
		}
		for _, stmt := range fun.Body.List {
			if stmt == nil {
				continue
			}
			expr, ok := stmt.(*ast.ExprStmt)
			if !ok {
				continue
			}
			if expr.X == nil {
				continue
			}
			call, ok := expr.X.(*ast.CallExpr)
			if !ok {
				continue
			}
			if call.Fun == nil {
				continue
			}
			sel, ok := call.Fun.(*ast.SelectorExpr)
			if !ok {
				continue
			}
			if sel.Sel == nil || sel.Sel.Name != "Format" {
				continue
			}
			if sel.X == nil {
				continue
			}
			switch sel.X.(type) {
			case *ast.Ident:
				id := sel.X.(*ast.Ident)
				if id.Obj == nil {
					continue
				}
				if id.Obj.Decl == nil {
					continue
				}
				obj, ok := id.Obj.Decl.(*ast.ValueSpec)
				if !ok {
					continue
				}
				if obj.Type == nil {
					continue
				}
				sel2, ok := obj.Type.(*ast.SelectorExpr)
				if !ok {
					continue
				}
				if sel2.X == nil {
					continue
				}
				id2, ok := sel2.X.(*ast.Ident)
				if !ok {
					continue
				}
				if id2.Name != "gtime" {
					continue
				}
				if sel2.Sel == nil {
					continue
				}
				if sel2.Sel.Name != "Time" {
					continue
				}
				callMultiplexing(call, pass, formatSymbols)
			case *ast.CallExpr:
				call2, ok := sel.X.(*ast.CallExpr)
				if !ok {
					continue
				}
				if call2.Fun == nil {
					continue
				}
				sel2, ok := call2.Fun.(*ast.SelectorExpr)
				if !ok {
					continue
				}
				if sel2.X == nil {
					continue
				}
				id, ok := sel2.X.(*ast.Ident)
				if !ok {
					continue
				}
				if id.Name != "gtime" {
					continue
				}
				callMultiplexing(call, pass, formatSymbols)
			}
		}
		return true
	}

	for _, file := range pass.Files {
		ast.Inspect(file, inspect)
	}
	return nil, nil
}

package main

import (
	"github.com/gogf/gf/os/gtime"
	"time"
)

func A() {
	var t gtime.Time
	t.Format("2006-01-02 15:04:05")
	gtime.New().Format("2006-01-02 15:04:05")

	gtime.NewFromStr("2006-01-02 15:04:05").Format("2006-01-02 15:04:05")

	t.Format("%Y-m-d")
	gtime.New().Format("%Y-m-d")

	var sy time.Time
	sy.Format("2006-01-02 15:04:05")
	time.Now().Format("2006-01-02 15:04:05")
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Deng_Xian_Shemg

捐助1元钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值