Compare commits
6 Commits
9d14fa7c57
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| b37121a218 | |||
| ffbeccc4fd | |||
| 4536be4d10 | |||
| 6e5e676e84 | |||
| 4089f0b084 | |||
| fefc7a701b |
29
.idea/watcherTasks.xml
generated
Normal file
29
.idea/watcherTasks.xml
generated
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectTasksOptions">
|
||||
<TaskOptions isEnabled="true">
|
||||
<option name="arguments" value="run --disable=typecheck $FileDir$" />
|
||||
<option name="checkSyntaxErrors" value="true" />
|
||||
<option name="description" />
|
||||
<option name="exitCodeBehavior" value="ERROR" />
|
||||
<option name="fileExtension" value="go" />
|
||||
<option name="immediateSync" value="false" />
|
||||
<option name="name" value="golangci-lint" />
|
||||
<option name="output" value="" />
|
||||
<option name="outputFilters">
|
||||
<array />
|
||||
</option>
|
||||
<option name="outputFromStdout" value="false" />
|
||||
<option name="program" value="golangci-lint" />
|
||||
<option name="runOnExternalChanges" value="false" />
|
||||
<option name="scopeName" value="Project Files" />
|
||||
<option name="trackOnlyRoot" value="true" />
|
||||
<option name="workingDir" value="$ProjectFileDir$" />
|
||||
<envs>
|
||||
<env name="GOROOT" value="$GOROOT$" />
|
||||
<env name="GOPATH" value="$GOPATH$" />
|
||||
<env name="PATH" value="$GoBinDirs$" />
|
||||
</envs>
|
||||
</TaskOptions>
|
||||
</component>
|
||||
</project>
|
||||
BIN
cmd/gormlint/gormlint
Executable file
BIN
cmd/gormlint/gormlint
Executable file
Binary file not shown.
@@ -1,9 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kuzgoga/gormlint/nullSafetyCheck"
|
||||
"github.com/kuzgoga/gormlint/relationsCheck"
|
||||
"golang.org/x/tools/go/analysis/multichecker"
|
||||
"gormlint/nullSafetyCheck"
|
||||
"gormlint/relationsCheck"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package nullSafetyCheck
|
||||
|
||||
import (
|
||||
"github.com/kuzgoga/gormlint/common"
|
||||
"go/ast"
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"gormlint/common"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package relationsCheck
|
||||
|
||||
import (
|
||||
"gormlint/common"
|
||||
"github.com/kuzgoga/gormlint/common"
|
||||
)
|
||||
|
||||
func IsBelongsTo(field common.Field, model common.Model, relatedModel common.Model) bool {
|
||||
foreignKey := field.Tags.GetParamOr("foreignKey", "Id")
|
||||
references := field.Tags.GetParamOr("references", relatedModel.Name+"Id")
|
||||
references := field.Tags.GetParamOr("references", "Id")
|
||||
foreignKey := field.Tags.GetParamOr("foreignKey", field.Name+"Id")
|
||||
|
||||
if !model.HasField(references) {
|
||||
if !model.HasField(foreignKey) {
|
||||
return false
|
||||
}
|
||||
if !relatedModel.HasField(foreignKey) {
|
||||
if !relatedModel.HasField(references) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
18
relationsCheck/checkHasOne.go
Normal file
18
relationsCheck/checkHasOne.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package relationsCheck
|
||||
|
||||
import "github.com/kuzgoga/gormlint/common"
|
||||
|
||||
func IsHasOne(field common.Field, model common.Model, relatedModel common.Model) bool {
|
||||
foreignKey := field.Tags.GetParamOr("foreignKey", model.Name+"Id")
|
||||
references := field.Tags.GetParamOr("references", "Id")
|
||||
|
||||
if !relatedModel.HasField(foreignKey) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !model.HasField(references) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package relationsCheck
|
||||
|
||||
import (
|
||||
"github.com/kuzgoga/gormlint/common"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"gormlint/common"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ package relationsCheck
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kuzgoga/gormlint/common"
|
||||
"go/types"
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"gormlint/common"
|
||||
)
|
||||
|
||||
func findBackReferenceInOneToMany(model common.Model, relatedModel common.Model) *common.Field {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package relationsCheck
|
||||
|
||||
import (
|
||||
"github.com/kuzgoga/gormlint/common"
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"gormlint/common"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CheckCascadeDelete(pass *analysis.Pass, field common.Field) bool {
|
||||
if !field.Tags.HasParam("constraint") {
|
||||
pass.Reportf(field.Pos, "field %s should have a constraint", field.Name)
|
||||
pass.Reportf(field.Pos, "field %s should have a delete constraint", field.Name)
|
||||
return true
|
||||
}
|
||||
constraintValue := field.Tags.GetParam("constraint").Value
|
||||
|
||||
@@ -2,8 +2,8 @@ package relationsCheck
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kuzgoga/gormlint/common"
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"gormlint/common"
|
||||
"slices"
|
||||
)
|
||||
|
||||
@@ -98,6 +98,9 @@ func CheckOneToMany(pass *analysis.Pass, models map[string]common.Model) {
|
||||
if common.IsSlice(field.Type) {
|
||||
continue
|
||||
}
|
||||
if field.Tags.HasParam("many2many") {
|
||||
continue
|
||||
}
|
||||
|
||||
baseType := common.ResolveBaseType(field.Type)
|
||||
if baseType == nil {
|
||||
@@ -114,10 +117,22 @@ func CheckOneToMany(pass *analysis.Pass, models map[string]common.Model) {
|
||||
fmt.Printf("Found 1:M relation in model `%s` with model `%s`\n", model.Name, *baseType)
|
||||
}
|
||||
|
||||
foundBelongsTo := IsBelongsTo(field, model, *relatedModel)
|
||||
hasOne := IsHasOne(field, model, *relatedModel)
|
||||
|
||||
if !foundOneToMany {
|
||||
foundBelongsTo := IsBelongsTo(field, model, *relatedModel)
|
||||
if foundBelongsTo {
|
||||
fmt.Printf("Found belongs to relation in model `%s` with model `%s`\n", model.Name, *baseType)
|
||||
fmt.Printf("`%s` belongs `%s`\n", *baseType, model.Name)
|
||||
if CheckCascadeDelete(pass, field) {
|
||||
return
|
||||
}
|
||||
} else if hasOne {
|
||||
fmt.Printf("`%s` has one `%s` \n", model.Name, relatedModel.Name)
|
||||
if CheckCascadeDelete(pass, field) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
pass.Reportf(field.Pos, "Invalid relation in field `%s`", field.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"github.com/kuzgoga/gormlint/nullSafetyCheck"
|
||||
"golang.org/x/tools/go/analysis/analysistest"
|
||||
"gormlint/nullSafetyCheck"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNullSafety(t *testing.T) {
|
||||
t.Parallel()
|
||||
analysistest.Run(t, analysistest.TestData(), nullSafetyCheck.NullSafetyAnalyzer, "null_safety")
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"github.com/kuzgoga/gormlint/relationsCheck"
|
||||
"golang.org/x/tools/go/analysis/analysistest"
|
||||
"gormlint/relationsCheck"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRelationsCheck(t *testing.T) {
|
||||
t.Parallel()
|
||||
analysistest.Run(t, analysistest.TestData(), relationsCheck.RelationsAnalyzer, "relations_check")
|
||||
}
|
||||
|
||||
25
tests/testdata/src/relations_check/negative.go
vendored
25
tests/testdata/src/relations_check/negative.go
vendored
@@ -50,3 +50,28 @@ type File struct {
|
||||
PostId uint
|
||||
Post Post
|
||||
}
|
||||
|
||||
type Consumer struct {
|
||||
Id uint `gorm:"primaryKey"`
|
||||
Name string
|
||||
ShoppingCart ShoppingCart // want "Invalid relation in field `ShoppingCart`"
|
||||
}
|
||||
|
||||
type ShoppingCart struct {
|
||||
Id uint `gorm:"primaryKey"`
|
||||
SerializedItems string
|
||||
}
|
||||
|
||||
// Has one
|
||||
|
||||
type Hotel struct {
|
||||
Id uint `gorm:"primaryKey"`
|
||||
Office // want "field Office should have a delete constraint"
|
||||
}
|
||||
|
||||
type Office struct {
|
||||
Id uint `gorm:"primaryKey"`
|
||||
Name string
|
||||
Address string
|
||||
HotelId uint
|
||||
}
|
||||
|
||||
18
tests/testdata/src/relations_check/positive.go
vendored
18
tests/testdata/src/relations_check/positive.go
vendored
@@ -26,8 +26,8 @@ type Kuzbass struct {
|
||||
}
|
||||
|
||||
type City struct {
|
||||
Id uint `gorm:"primaryKey"`
|
||||
Kuzbass Kuzbass
|
||||
Id uint `gorm:"primaryKey"`
|
||||
Kuzbass Kuzbass // want "Invalid relation in field `Kuzbass`"
|
||||
}
|
||||
|
||||
type Federation struct { // want "Id field should be presented model \"Federation\""
|
||||
@@ -38,3 +38,17 @@ type Land struct {
|
||||
Id uint `gorm:"primaryKey"`
|
||||
FederationId uint
|
||||
}
|
||||
|
||||
// Belongs to
|
||||
|
||||
type Owner struct {
|
||||
Id uint `gorm:"primaryKey"`
|
||||
Name string
|
||||
CompanyId int
|
||||
Company Company `gorm:"constraint:OnDelete:CASCADE;"`
|
||||
}
|
||||
|
||||
type Company struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user