structs for models
This commit is contained in:
@@ -1 +1,23 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Field struct {
|
||||||
|
Name string
|
||||||
|
Type ast.Expr
|
||||||
|
Tags *string
|
||||||
|
Options []string // contains options like "autoCreateTime" or "null"
|
||||||
|
Params []string // contains params like "foreignKey:CustomerId" or "constrain:OnDelete:Cascade"
|
||||||
|
Position token.Pos
|
||||||
|
Comment string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Model struct {
|
||||||
|
Name string
|
||||||
|
Fields map[string]Field
|
||||||
|
Position token.Pos
|
||||||
|
Comment string
|
||||||
|
}
|
||||||
|
|||||||
@@ -1 +1,10 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func NormalizeStructTags(tags string) string {
|
||||||
|
// todo: process case with check with ';' literal
|
||||||
|
tagWithoutQuotes := tags[1 : len(tags)-1]
|
||||||
|
tagWithoutSemicolons := strings.ReplaceAll(tagWithoutQuotes, ";", ",")
|
||||||
|
return tagWithoutSemicolons
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ func isGormValueNullable(tags *structtag.Tags) (*bool, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
gormTag.Options = append([]string{gormTag.Name}, gormTag.Options...)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gormTag.Options = append([]string{gormTag.Name}, gormTag.Options...)
|
||||||
|
|
||||||
nullTagExist := gormTag.HasOption("null")
|
nullTagExist := gormTag.HasOption("null")
|
||||||
notNullTagExist := gormTag.HasOption("not null")
|
notNullTagExist := gormTag.HasOption("not null")
|
||||||
|
|
||||||
@@ -47,8 +47,8 @@ func CheckFieldNullConsistency(field ast.Field, structName string, structTags st
|
|||||||
tags, err := structtag.Parse(structTags)
|
tags, err := structtag.Parse(structTags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(fmt.Sprintf("Invalid structure tag: %s", err))
|
return errors.New(fmt.Sprintf("Invalid structure tag: %s", err))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if tags == nil {
|
if tags == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package analyzers
|
package nullSafetyCheck
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NullSafetyAnalyzer todo: add URL for null safety analyzer rules
|
||||||
var NullSafetyAnalyzer = &analysis.Analyzer{
|
var NullSafetyAnalyzer = &analysis.Analyzer{
|
||||||
Name: "gormNullSafety",
|
Name: "gormNullSafety",
|
||||||
Doc: "reports problems with nullable fields with unsatisfied tag",
|
Doc: "reports problems with nullable fields with unsatisfied tag",
|
||||||
@@ -24,7 +25,6 @@ func run(pass *analysis.Pass) (any, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
pass.Fset.Position(structure.Pos())
|
|
||||||
|
|
||||||
if err := common.CheckUnnamedModel(*typeSpec); err != nil {
|
if err := common.CheckUnnamedModel(*typeSpec); err != nil {
|
||||||
pass.Reportf(structure.Pos(), err.Error())
|
pass.Reportf(structure.Pos(), err.Error())
|
||||||
|
|||||||
@@ -1 +1,92 @@
|
|||||||
package referencesCheck
|
package referencesCheck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/fatih/structtag"
|
||||||
|
"go/ast"
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
"gormlint/common"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReferenceAnalyzer todo: add URL for rule
|
||||||
|
var ReferenceAnalyzer = &analysis.Analyzer{
|
||||||
|
Name: "gormReferencesCheck",
|
||||||
|
Doc: "report about invalid references in models",
|
||||||
|
Run: run,
|
||||||
|
}
|
||||||
|
|
||||||
|
var models map[string]common.Model
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
models = make(map[string]common.Model)
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(pass *analysis.Pass) (any, error) {
|
||||||
|
for _, file := range pass.Files {
|
||||||
|
ast.Inspect(file, func(node ast.Node) bool {
|
||||||
|
typeSpec, ok := node.(*ast.TypeSpec)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
structure, ok := typeSpec.Type.(*ast.StructType)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := common.CheckUnnamedModel(*typeSpec); err != nil {
|
||||||
|
pass.Reportf(structure.Pos(), err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var model common.Model
|
||||||
|
model.Name = typeSpec.Name.Name
|
||||||
|
model.Comment = typeSpec.Comment.Text()
|
||||||
|
model.Position = structure.Pos()
|
||||||
|
model.Fields = make(map[string]common.Field)
|
||||||
|
|
||||||
|
for _, field := range structure.Fields.List {
|
||||||
|
var structField common.Field
|
||||||
|
if err := common.CheckUnnamedField(typeSpec.Name.Name, *field); err != nil {
|
||||||
|
pass.Reportf(field.Pos(), err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
structField.Name = field.Names[0].Name
|
||||||
|
structField.Position = field.Pos()
|
||||||
|
structField.Comment = field.Comment.Text()
|
||||||
|
structField.Type = field.Type
|
||||||
|
if field.Tag != nil {
|
||||||
|
structField.Tags = &field.Tag.Value
|
||||||
|
|
||||||
|
tags, err := structtag.Parse(common.NormalizeStructTags(field.Tag.Value))
|
||||||
|
if err != nil {
|
||||||
|
pass.Reportf(field.Pos(), "Invalid structure tag: %s\n", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if tags != nil {
|
||||||
|
gormTag, parseErr := tags.Get("gorm")
|
||||||
|
if gormTag != nil && parseErr == nil {
|
||||||
|
gormTag.Options = append([]string{gormTag.Name}, gormTag.Options...)
|
||||||
|
for _, opt := range gormTag.Options {
|
||||||
|
if strings.Contains(opt, ":") {
|
||||||
|
structField.Params = append(structField.Options, opt)
|
||||||
|
} else {
|
||||||
|
structField.Options = append(structField.Options, opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if parseErr != nil {
|
||||||
|
pass.Reportf(field.Pos(), "Invalid structure tag: %s\n", parseErr)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model.Fields[structField.Name] = structField
|
||||||
|
}
|
||||||
|
|
||||||
|
models[model.Name] = model
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user