forked from TrueCloudLab/linters
[#1] linters: add logs linter
This commit is contained in:
parent
e8381da3da
commit
4ad1e47610
15 changed files with 776 additions and 0 deletions
13
Makefile
Normal file
13
Makefile
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
OUT_DIR?=./.bin
|
||||||
|
PLUGIN_SOURCE?=main.go
|
||||||
|
|
||||||
|
test:
|
||||||
|
@go test -v ./...
|
||||||
|
|
||||||
|
lib:
|
||||||
|
@mkdir -pv $(OUT_DIR)
|
||||||
|
@go build -buildmode=plugin -o $(OUT_DIR)/external_linters.so $(PLUGIN_SOURCE)
|
||||||
|
|
||||||
|
lint:
|
||||||
|
@golangci-lint run
|
||||||
|
|
41
README.md
Normal file
41
README.md
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# linters
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
|
||||||
|
`linters` is a project that enables the integration of custom linting rules into the [golangci-lint](https://github.com/golangci/golangci-lint) framework.
|
||||||
|
|
||||||
|
|
||||||
|
## Available linters
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| ----------- | ----------- |
|
||||||
|
| noliteral | The tool prohibits the use of literal string arguments in logging functions |
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone git.frostfs.info/TrueCloudLab/linters
|
||||||
|
cd linters
|
||||||
|
make lib OUT_DIR=<Path to the directory with libraries>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Add to .golagci.yml
|
||||||
|
|
||||||
|
```yml
|
||||||
|
|
||||||
|
linters-settings:
|
||||||
|
custom:
|
||||||
|
custom-linters:
|
||||||
|
path: <Path to the directory with libraries>
|
||||||
|
original-url: git.frostfs.info/TrueCloudLab/linters
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable:
|
||||||
|
custom-linters
|
||||||
|
```
|
10
go.mod
Normal file
10
go.mod
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
module git.frostfs.info/TrueCloudLab/linters
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require golang.org/x/tools v0.9.3
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/mod v0.12.0 // indirect
|
||||||
|
golang.org/x/sys v0.10.0 // indirect
|
||||||
|
)
|
10
go.sum
Normal file
10
go.sum
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||||
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||||
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
|
||||||
|
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||||
|
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||||
|
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||||
|
golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8=
|
||||||
|
golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
|
88
internal/analyzers/no-literal/linter.go
Normal file
88
internal/analyzers/no-literal/linter.go
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
package noliteral
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
)
|
||||||
|
|
||||||
|
const LinterName = "noliteral"
|
||||||
|
|
||||||
|
var LogsAnalyzer = &analysis.Analyzer{
|
||||||
|
Name: LinterName,
|
||||||
|
Doc: LinterName + " is a helper tool that ensures logging messages in Go code are structured and not written as simple text.",
|
||||||
|
Run: run,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
methodsToSearchOnce = &sync.Once{}
|
||||||
|
methodsToSearch = []string{"Debug", "Info", "Warn", "Error"}
|
||||||
|
customLogs = "reportFlushError, reportError"
|
||||||
|
)
|
||||||
|
|
||||||
|
func run(pass *analysis.Pass) (interface{}, error) {
|
||||||
|
for _, file := range pass.Files {
|
||||||
|
ast.Inspect(file, func(n ast.Node) bool {
|
||||||
|
expr, ok := n.(*ast.CallExpr)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
isLog, _ := isLogDot(expr.Fun)
|
||||||
|
if isLog && len(expr.Args) > 0 && isStringValue(expr.Args[0]) {
|
||||||
|
pass.Report(analysis.Diagnostic{
|
||||||
|
Pos: expr.Pos(),
|
||||||
|
End: 0,
|
||||||
|
Category: LinterName,
|
||||||
|
Message: "Literals are not allowed in the body of the logger",
|
||||||
|
SuggestedFixes: nil,
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isLogDot(expr ast.Expr) (bool, string) {
|
||||||
|
sel, ok := expr.(*ast.SelectorExpr)
|
||||||
|
if !ok {
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
methodsToSearchOnce.Do(func() {
|
||||||
|
for _, cl := range strings.Split(customLogs, ",") {
|
||||||
|
cl = strings.Trim(cl, " ")
|
||||||
|
if len(cl) > 0 {
|
||||||
|
methodsToSearch = append(methodsToSearch, cl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, method := range methodsToSearch {
|
||||||
|
if isIdent(sel.Sel, method) {
|
||||||
|
return true, method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func isIdent(expr ast.Expr, ident string) bool {
|
||||||
|
id, ok := expr.(*ast.Ident)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if id.Name == ident {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isStringValue(expr ast.Expr) bool {
|
||||||
|
basicLit, ok := expr.(*ast.BasicLit)
|
||||||
|
return ok && basicLit.Kind == token.STRING
|
||||||
|
}
|
264
internal/analyzers/no-literal/linter_test.go
Normal file
264
internal/analyzers/no-literal/linter_test.go
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
package noliteral
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAnalyzerA_n(t *testing.T) {
|
||||||
|
|
||||||
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
|
dir := filepath.Dir(filename)
|
||||||
|
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
f, err := parser.ParseFile(fset, filepath.Join(dir, "test-case/src/a_negative._go"), nil, parser.AllErrors)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flag := false
|
||||||
|
pass := &analysis.Pass{
|
||||||
|
Fset: fset,
|
||||||
|
Files: []*ast.File{f},
|
||||||
|
Report: func(diag analysis.Diagnostic) {
|
||||||
|
t.Log(diag.Message)
|
||||||
|
Flag = true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = run(pass)
|
||||||
|
|
||||||
|
if !Flag {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnalyzerA_p(t *testing.T) {
|
||||||
|
|
||||||
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
|
dir := filepath.Dir(filename)
|
||||||
|
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
f, err := parser.ParseFile(fset, filepath.Join(dir, "test-case/src/a_positive._go"), nil, parser.AllErrors)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flag := false
|
||||||
|
pass := &analysis.Pass{
|
||||||
|
Fset: fset,
|
||||||
|
Files: []*ast.File{f},
|
||||||
|
Report: func(diag analysis.Diagnostic) {
|
||||||
|
t.Log(diag.Message)
|
||||||
|
flag = true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = run(pass)
|
||||||
|
|
||||||
|
if flag {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnalyzerB_n(t *testing.T) {
|
||||||
|
|
||||||
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
|
dir := filepath.Dir(filename)
|
||||||
|
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
f, err := parser.ParseFile(fset, filepath.Join(dir, "test-case/src/b_negative._go"), nil, parser.AllErrors)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flag := false
|
||||||
|
pass := &analysis.Pass{
|
||||||
|
Fset: fset,
|
||||||
|
Files: []*ast.File{f},
|
||||||
|
Report: func(diag analysis.Diagnostic) {
|
||||||
|
t.Log(diag.Message)
|
||||||
|
Flag = true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = run(pass)
|
||||||
|
|
||||||
|
if !Flag {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnalyzerB_p(t *testing.T) {
|
||||||
|
|
||||||
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
|
dir := filepath.Dir(filename)
|
||||||
|
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
f, err := parser.ParseFile(fset, filepath.Join(dir, "test-case/src/b_positive._go"), nil, parser.AllErrors)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flag := false
|
||||||
|
pass := &analysis.Pass{
|
||||||
|
Fset: fset,
|
||||||
|
Files: []*ast.File{f},
|
||||||
|
Report: func(diag analysis.Diagnostic) {
|
||||||
|
t.Log(diag.Message)
|
||||||
|
flag = true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = run(pass)
|
||||||
|
|
||||||
|
if flag {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnalyzerC_n(t *testing.T) {
|
||||||
|
|
||||||
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
|
dir := filepath.Dir(filename)
|
||||||
|
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
f, err := parser.ParseFile(fset, filepath.Join(dir, "test-case/src/c_negative._go"), nil, parser.AllErrors)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flag := false
|
||||||
|
pass := &analysis.Pass{
|
||||||
|
Fset: fset,
|
||||||
|
Files: []*ast.File{f},
|
||||||
|
Report: func(diag analysis.Diagnostic) {
|
||||||
|
t.Log(diag.Message)
|
||||||
|
Flag = true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = run(pass)
|
||||||
|
|
||||||
|
if !Flag {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnalyzerC_p(t *testing.T) {
|
||||||
|
|
||||||
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
|
dir := filepath.Dir(filename)
|
||||||
|
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
f, err := parser.ParseFile(fset, filepath.Join(dir, "test-case/src/c_positive._go"), nil, parser.AllErrors)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flag := false
|
||||||
|
pass := &analysis.Pass{
|
||||||
|
Fset: fset,
|
||||||
|
Files: []*ast.File{f},
|
||||||
|
Report: func(diag analysis.Diagnostic) {
|
||||||
|
t.Log(diag.Message)
|
||||||
|
flag = true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = run(pass)
|
||||||
|
|
||||||
|
if flag {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnalyzerD_n(t *testing.T) {
|
||||||
|
|
||||||
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
|
dir := filepath.Dir(filename)
|
||||||
|
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
f, err := parser.ParseFile(fset, filepath.Join(dir, "test-case/src/d_negative._go"), nil, parser.AllErrors)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Flag := false
|
||||||
|
pass := &analysis.Pass{
|
||||||
|
Fset: fset,
|
||||||
|
Files: []*ast.File{f},
|
||||||
|
Report: func(diag analysis.Diagnostic) {
|
||||||
|
t.Log(diag.Message)
|
||||||
|
Flag = true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = run(pass)
|
||||||
|
|
||||||
|
if Flag {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnalyzerD_p(t *testing.T) {
|
||||||
|
|
||||||
|
_, filename, _, _ := runtime.Caller(0)
|
||||||
|
dir := filepath.Dir(filename)
|
||||||
|
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
f, err := parser.ParseFile(fset, filepath.Join(dir, "test-case/src/d_positive._go"), nil, parser.AllErrors)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flag := false
|
||||||
|
pass := &analysis.Pass{
|
||||||
|
Fset: fset,
|
||||||
|
Files: []*ast.File{f},
|
||||||
|
Report: func(diag analysis.Diagnostic) {
|
||||||
|
t.Log(diag.Message)
|
||||||
|
flag = true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = run(pass)
|
||||||
|
|
||||||
|
if flag {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
36
internal/analyzers/no-literal/test-case/src/a_negative._go
Normal file
36
internal/analyzers/no-literal/test-case/src/a_negative._go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package src_test
|
||||||
|
|
||||||
|
func (c *cfg) f1_n() {
|
||||||
|
c.log.Info("logs.MSG") //unacceptable
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger interface {
|
||||||
|
Debug(msg string)
|
||||||
|
Info(msg string)
|
||||||
|
Warn(msg string)
|
||||||
|
Error(msg string)
|
||||||
|
Abyr(msg string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Debug(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Warn(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Error(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Abyr(msg string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
var logs = struct {
|
||||||
|
MSG string
|
||||||
|
}{
|
||||||
|
MSG: "some message",
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfg struct {
|
||||||
|
log Logger
|
||||||
|
}
|
46
internal/analyzers/no-literal/test-case/src/a_positive._go
Normal file
46
internal/analyzers/no-literal/test-case/src/a_positive._go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package src_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *cfg) f1_ok() {
|
||||||
|
c.log.Info(logs.MSG) //acceptable
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger interface {
|
||||||
|
Debug(msg string)
|
||||||
|
Info(msg string)
|
||||||
|
Warn(msg string)
|
||||||
|
Error(msg string)
|
||||||
|
Abyr(msg string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Debug(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Warn(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Error(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Abyr(msg string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
fmt.Println(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
var logs = struct {
|
||||||
|
MSG string
|
||||||
|
}{
|
||||||
|
MSG: "some message",
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfg struct {
|
||||||
|
log Logger
|
||||||
|
}
|
36
internal/analyzers/no-literal/test-case/src/b_negative._go
Normal file
36
internal/analyzers/no-literal/test-case/src/b_negative._go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package src_test
|
||||||
|
|
||||||
|
func (c *cfg) f1_n() {
|
||||||
|
c.log.Debug("logs.MSG") //unacceptable
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger interface {
|
||||||
|
Debug(msg string)
|
||||||
|
Info(msg string)
|
||||||
|
Warn(msg string)
|
||||||
|
Error(msg string)
|
||||||
|
Abyr(msg string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Debug(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Warn(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Error(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Abyr(msg string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
var logs = struct {
|
||||||
|
MSG string
|
||||||
|
}{
|
||||||
|
MSG: "some message",
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfg struct {
|
||||||
|
log Logger
|
||||||
|
}
|
46
internal/analyzers/no-literal/test-case/src/b_positive._go
Normal file
46
internal/analyzers/no-literal/test-case/src/b_positive._go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package src_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *cfg) f1_ok() {
|
||||||
|
c.log.Debug(logs.MSG) //acceptable
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger interface {
|
||||||
|
Debug(msg string)
|
||||||
|
Info(msg string)
|
||||||
|
Warn(msg string)
|
||||||
|
Error(msg string)
|
||||||
|
Abyr(msg string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Debug(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Warn(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Error(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Abyr(msg string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
fmt.Println(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
var logs = struct {
|
||||||
|
MSG string
|
||||||
|
}{
|
||||||
|
MSG: "some message",
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfg struct {
|
||||||
|
log Logger
|
||||||
|
}
|
36
internal/analyzers/no-literal/test-case/src/c_negative._go
Normal file
36
internal/analyzers/no-literal/test-case/src/c_negative._go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package src_test
|
||||||
|
|
||||||
|
func (c *cfg) f1_n() {
|
||||||
|
c.log.Error("logs.MSG") //unacceptable
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger interface {
|
||||||
|
Debug(msg string)
|
||||||
|
Info(msg string)
|
||||||
|
Warn(msg string)
|
||||||
|
Error(msg string)
|
||||||
|
Abyr(msg string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Debug(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Warn(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Error(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Abyr(msg string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
var logs = struct {
|
||||||
|
MSG string
|
||||||
|
}{
|
||||||
|
MSG: "some message",
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfg struct {
|
||||||
|
log Logger
|
||||||
|
}
|
46
internal/analyzers/no-literal/test-case/src/c_positive._go
Normal file
46
internal/analyzers/no-literal/test-case/src/c_positive._go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package src_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *cfg) f1_ok() {
|
||||||
|
c.log.Error(logs.MSG) //acceptable
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger interface {
|
||||||
|
Debug(msg string)
|
||||||
|
Info(msg string)
|
||||||
|
Warn(msg string)
|
||||||
|
Error(msg string)
|
||||||
|
Abyr(msg string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Debug(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Warn(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Error(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Abyr(msg string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
fmt.Println(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
var logs = struct {
|
||||||
|
MSG string
|
||||||
|
}{
|
||||||
|
MSG: "some message",
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfg struct {
|
||||||
|
log Logger
|
||||||
|
}
|
36
internal/analyzers/no-literal/test-case/src/d_negative._go
Normal file
36
internal/analyzers/no-literal/test-case/src/d_negative._go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package src_test
|
||||||
|
|
||||||
|
func (c *cfg) f1_n() {
|
||||||
|
c.log.Abyr("logs.MSG") //unacceptable
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger interface {
|
||||||
|
Debug(msg string)
|
||||||
|
Info(msg string)
|
||||||
|
Warn(msg string)
|
||||||
|
Error(msg string)
|
||||||
|
Abyr(msg string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Debug(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Warn(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Error(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Abyr(msg string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
var logs = struct {
|
||||||
|
MSG string
|
||||||
|
}{
|
||||||
|
MSG: "some message",
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfg struct {
|
||||||
|
log Logger
|
||||||
|
}
|
46
internal/analyzers/no-literal/test-case/src/d_positive._go
Normal file
46
internal/analyzers/no-literal/test-case/src/d_positive._go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package src_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *cfg) f1_ok() {
|
||||||
|
c.log.Abyr(logs.MSG) //acceptable
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger interface {
|
||||||
|
Debug(msg string)
|
||||||
|
Info(msg string)
|
||||||
|
Warn(msg string)
|
||||||
|
Error(msg string)
|
||||||
|
Abyr(msg string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Debug(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Warn(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Error(msg string) {
|
||||||
|
}
|
||||||
|
func (l RealLogger) Abyr(msg string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
type RealLogger struct{}
|
||||||
|
|
||||||
|
func (l RealLogger) Info(msg string) {
|
||||||
|
fmt.Println(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
var logs = struct {
|
||||||
|
MSG string
|
||||||
|
}{
|
||||||
|
MSG: "some message",
|
||||||
|
}
|
||||||
|
|
||||||
|
type cfg struct {
|
||||||
|
log Logger
|
||||||
|
}
|
22
main.go
Normal file
22
main.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
noliteral "git.frostfs.info/TrueCloudLab/linters/internal/analyzers/no-literal"
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
)
|
||||||
|
|
||||||
|
var AnalyzerPlugin analyzerPlugin
|
||||||
|
|
||||||
|
type analyzerPlugin struct{}
|
||||||
|
|
||||||
|
// for version ci-lint < '1.5.4'.
|
||||||
|
func (*analyzerPlugin) GetAnalyzers() []*analysis.Analyzer {
|
||||||
|
return []*analysis.Analyzer{noliteral.LogsAnalyzer}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// for version ci-lint >= '1.5.4'.
|
||||||
|
func New(conf any) ([]*analysis.Analyzer, error) {
|
||||||
|
return []*analysis.Analyzer{noliteral.LogsAnalyzer}, nil
|
||||||
|
}
|
||||||
|
*/
|
Loading…
Reference in a new issue