From ddad891cc11517c1a15c58687aaaef1667b5272b Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 3 Feb 2020 11:49:54 -0500 Subject: [PATCH] New Checks: S025 through S033 (#89) * New Analyzer: helper/passes/schema/schemainfocomputedonly Returns all Schema that are Computed: true only. Refactors existing checks to using it. * New Checks: S025 through S033 Reference: https://github.com/bflad/tfproviderlint/issues/65 * **New Check:** `S025`: check for `Schema` of only `Computed` enabled with `AtLeastOneOf` configured * **New Check:** `S026`: check for `Schema` of only `Computed` enabled with `ConflictsWith` configured * **New Check:** `S027`: check for `Schema` of only `Computed` enabled with `Default` configured * **New Check:** `S028`: check for `Schema` of only `Computed` enabled with `DefaultFunc` configured * **New Check:** `S029`: check for `Schema` of only `Computed` enabled with `ExactlyOneOf` configured * **New Check:** `S030`: check for `Schema` of only `Computed` enabled with `InputDefault` configured * **New Check:** `S031`: check for `Schema` of only `Computed` enabled with `MaxItems` configured * **New Check:** `S032`: check for `Schema` of only `Computed` enabled with `MinItems` configured * **New Check:** `S033`: check for `Schema` of only `Computed` enabled with `StateFunc` configured --- CHANGELOG.md | 9 ++++ README.md | 9 ++++ .../helper/schema/type_schema.go | 20 ++++++++ passes/S010/S010.go | 13 ++--- passes/S011/S011.go | 13 ++--- passes/S020/S020.go | 9 ++-- passes/S025/README.md | 33 ++++++++++++ passes/S025/S025.go | 50 +++++++++++++++++++ passes/S025/S025_test.go | 13 +++++ passes/S025/testdata/src/a/alias.go | 19 +++++++ passes/S025/testdata/src/a/comment_ignore.go | 13 +++++ passes/S025/testdata/src/a/main.go | 33 ++++++++++++ passes/S025/testdata/src/a/outside_package.go | 19 +++++++ passes/S025/testdata/src/a/schema/schema.go | 6 +++ passes/S025/testdata/src/a/vendor | 1 + passes/S026/README.md | 33 ++++++++++++ passes/S026/S026.go | 50 +++++++++++++++++++ passes/S026/S026_test.go | 13 +++++ passes/S026/testdata/src/a/alias.go | 19 +++++++ passes/S026/testdata/src/a/comment_ignore.go | 13 +++++ passes/S026/testdata/src/a/main.go | 33 ++++++++++++ passes/S026/testdata/src/a/outside_package.go | 19 +++++++ passes/S026/testdata/src/a/schema/schema.go | 6 +++ passes/S026/testdata/src/a/vendor | 1 + passes/S027/README.md | 33 ++++++++++++ passes/S027/S027.go | 50 +++++++++++++++++++ passes/S027/S027_test.go | 13 +++++ passes/S027/testdata/src/a/alias.go | 19 +++++++ passes/S027/testdata/src/a/comment_ignore.go | 13 +++++ passes/S027/testdata/src/a/main.go | 33 ++++++++++++ passes/S027/testdata/src/a/outside_package.go | 19 +++++++ passes/S027/testdata/src/a/schema/schema.go | 6 +++ passes/S027/testdata/src/a/vendor | 1 + passes/S028/README.md | 33 ++++++++++++ passes/S028/S028.go | 50 +++++++++++++++++++ passes/S028/S028_test.go | 13 +++++ passes/S028/testdata/src/a/alias.go | 19 +++++++ passes/S028/testdata/src/a/comment_ignore.go | 13 +++++ passes/S028/testdata/src/a/main.go | 37 ++++++++++++++ passes/S028/testdata/src/a/outside_package.go | 19 +++++++ passes/S028/testdata/src/a/schema/schema.go | 6 +++ passes/S028/testdata/src/a/vendor | 1 + passes/S029/README.md | 33 ++++++++++++ passes/S029/S029.go | 50 +++++++++++++++++++ passes/S029/S029_test.go | 13 +++++ passes/S029/testdata/src/a/alias.go | 19 +++++++ passes/S029/testdata/src/a/comment_ignore.go | 13 +++++ passes/S029/testdata/src/a/main.go | 33 ++++++++++++ passes/S029/testdata/src/a/outside_package.go | 19 +++++++ passes/S029/testdata/src/a/schema/schema.go | 6 +++ passes/S029/testdata/src/a/vendor | 1 + passes/S030/README.md | 33 ++++++++++++ passes/S030/S030.go | 50 +++++++++++++++++++ passes/S030/S030_test.go | 13 +++++ passes/S030/testdata/src/a/alias.go | 19 +++++++ passes/S030/testdata/src/a/comment_ignore.go | 13 +++++ passes/S030/testdata/src/a/main.go | 28 +++++++++++ passes/S030/testdata/src/a/outside_package.go | 19 +++++++ passes/S030/testdata/src/a/schema/schema.go | 6 +++ passes/S030/testdata/src/a/vendor | 1 + passes/S031/README.md | 33 ++++++++++++ passes/S031/S031.go | 50 +++++++++++++++++++ passes/S031/S031_test.go | 13 +++++ passes/S031/testdata/src/a/alias.go | 19 +++++++ passes/S031/testdata/src/a/comment_ignore.go | 13 +++++ passes/S031/testdata/src/a/main.go | 28 +++++++++++ passes/S031/testdata/src/a/outside_package.go | 19 +++++++ passes/S031/testdata/src/a/schema/schema.go | 6 +++ passes/S031/testdata/src/a/vendor | 1 + passes/S032/README.md | 33 ++++++++++++ passes/S032/S032.go | 50 +++++++++++++++++++ passes/S032/S032_test.go | 13 +++++ passes/S032/testdata/src/a/alias.go | 19 +++++++ passes/S032/testdata/src/a/comment_ignore.go | 13 +++++ passes/S032/testdata/src/a/main.go | 28 +++++++++++ passes/S032/testdata/src/a/outside_package.go | 19 +++++++ passes/S032/testdata/src/a/schema/schema.go | 6 +++ passes/S032/testdata/src/a/vendor | 1 + passes/S033/README.md | 33 ++++++++++++ passes/S033/S033.go | 50 +++++++++++++++++++ passes/S033/S033_test.go | 13 +++++ passes/S033/testdata/src/a/alias.go | 19 +++++++ passes/S033/testdata/src/a/comment_ignore.go | 13 +++++ passes/S033/testdata/src/a/main.go | 37 ++++++++++++++ passes/S033/testdata/src/a/outside_package.go | 19 +++++++ passes/S033/testdata/src/a/schema/schema.go | 6 +++ passes/S033/testdata/src/a/vendor | 1 + passes/checks.go | 18 +++++++ .../schemainfocomputedonly.go | 35 +++++++++++++ 89 files changed, 1779 insertions(+), 23 deletions(-) create mode 100644 passes/S025/README.md create mode 100644 passes/S025/S025.go create mode 100644 passes/S025/S025_test.go create mode 100644 passes/S025/testdata/src/a/alias.go create mode 100644 passes/S025/testdata/src/a/comment_ignore.go create mode 100644 passes/S025/testdata/src/a/main.go create mode 100644 passes/S025/testdata/src/a/outside_package.go create mode 100644 passes/S025/testdata/src/a/schema/schema.go create mode 120000 passes/S025/testdata/src/a/vendor create mode 100644 passes/S026/README.md create mode 100644 passes/S026/S026.go create mode 100644 passes/S026/S026_test.go create mode 100644 passes/S026/testdata/src/a/alias.go create mode 100644 passes/S026/testdata/src/a/comment_ignore.go create mode 100644 passes/S026/testdata/src/a/main.go create mode 100644 passes/S026/testdata/src/a/outside_package.go create mode 100644 passes/S026/testdata/src/a/schema/schema.go create mode 120000 passes/S026/testdata/src/a/vendor create mode 100644 passes/S027/README.md create mode 100644 passes/S027/S027.go create mode 100644 passes/S027/S027_test.go create mode 100644 passes/S027/testdata/src/a/alias.go create mode 100644 passes/S027/testdata/src/a/comment_ignore.go create mode 100644 passes/S027/testdata/src/a/main.go create mode 100644 passes/S027/testdata/src/a/outside_package.go create mode 100644 passes/S027/testdata/src/a/schema/schema.go create mode 120000 passes/S027/testdata/src/a/vendor create mode 100644 passes/S028/README.md create mode 100644 passes/S028/S028.go create mode 100644 passes/S028/S028_test.go create mode 100644 passes/S028/testdata/src/a/alias.go create mode 100644 passes/S028/testdata/src/a/comment_ignore.go create mode 100644 passes/S028/testdata/src/a/main.go create mode 100644 passes/S028/testdata/src/a/outside_package.go create mode 100644 passes/S028/testdata/src/a/schema/schema.go create mode 120000 passes/S028/testdata/src/a/vendor create mode 100644 passes/S029/README.md create mode 100644 passes/S029/S029.go create mode 100644 passes/S029/S029_test.go create mode 100644 passes/S029/testdata/src/a/alias.go create mode 100644 passes/S029/testdata/src/a/comment_ignore.go create mode 100644 passes/S029/testdata/src/a/main.go create mode 100644 passes/S029/testdata/src/a/outside_package.go create mode 100644 passes/S029/testdata/src/a/schema/schema.go create mode 120000 passes/S029/testdata/src/a/vendor create mode 100644 passes/S030/README.md create mode 100644 passes/S030/S030.go create mode 100644 passes/S030/S030_test.go create mode 100644 passes/S030/testdata/src/a/alias.go create mode 100644 passes/S030/testdata/src/a/comment_ignore.go create mode 100644 passes/S030/testdata/src/a/main.go create mode 100644 passes/S030/testdata/src/a/outside_package.go create mode 100644 passes/S030/testdata/src/a/schema/schema.go create mode 120000 passes/S030/testdata/src/a/vendor create mode 100644 passes/S031/README.md create mode 100644 passes/S031/S031.go create mode 100644 passes/S031/S031_test.go create mode 100644 passes/S031/testdata/src/a/alias.go create mode 100644 passes/S031/testdata/src/a/comment_ignore.go create mode 100644 passes/S031/testdata/src/a/main.go create mode 100644 passes/S031/testdata/src/a/outside_package.go create mode 100644 passes/S031/testdata/src/a/schema/schema.go create mode 120000 passes/S031/testdata/src/a/vendor create mode 100644 passes/S032/README.md create mode 100644 passes/S032/S032.go create mode 100644 passes/S032/S032_test.go create mode 100644 passes/S032/testdata/src/a/alias.go create mode 100644 passes/S032/testdata/src/a/comment_ignore.go create mode 100644 passes/S032/testdata/src/a/main.go create mode 100644 passes/S032/testdata/src/a/outside_package.go create mode 100644 passes/S032/testdata/src/a/schema/schema.go create mode 120000 passes/S032/testdata/src/a/vendor create mode 100644 passes/S033/README.md create mode 100644 passes/S033/S033.go create mode 100644 passes/S033/S033_test.go create mode 100644 passes/S033/testdata/src/a/alias.go create mode 100644 passes/S033/testdata/src/a/comment_ignore.go create mode 100644 passes/S033/testdata/src/a/main.go create mode 100644 passes/S033/testdata/src/a/outside_package.go create mode 100644 passes/S033/testdata/src/a/schema/schema.go create mode 120000 passes/S033/testdata/src/a/vendor create mode 100644 passes/helper/schema/schemainfocomputedonly/schemainfocomputedonly.go diff --git a/CHANGELOG.md b/CHANGELOG.md index f15135d1..8582165d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,15 @@ BREAKING CHANGES FEATURES * **New Check:** `S024`: check for `Schema` that should omit `ForceNew` in data source schema attributes +* **New Check:** `S025`: check for `Schema` of only `Computed` enabled with `AtLeastOneOf` configured +* **New Check:** `S026`: check for `Schema` of only `Computed` enabled with `ConflictsWith` configured +* **New Check:** `S027`: check for `Schema` of only `Computed` enabled with `Default` configured +* **New Check:** `S028`: check for `Schema` of only `Computed` enabled with `DefaultFunc` configured +* **New Check:** `S029`: check for `Schema` of only `Computed` enabled with `ExactlyOneOf` configured +* **New Check:** `S030`: check for `Schema` of only `Computed` enabled with `InputDefault` configured +* **New Check:** `S031`: check for `Schema` of only `Computed` enabled with `MaxItems` configured +* **New Check:** `S032`: check for `Schema` of only `Computed` enabled with `MinItems` configured +* **New Check:** `S033`: check for `Schema` of only `Computed` enabled with `StateFunc` configured * **New Check:** `V002`: check for deprecated `CIDRNetwork` validation function usage * **New Check:** `V003`: check for deprecated `IPRange` validation function usage * **New Check:** `V004`: check for deprecated `SingleIP` validation function usage diff --git a/README.md b/README.md index 8341f2af..ce06bab3 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,15 @@ Standard lint checks are enabled by default in the `tfproviderlint` tool. Opt-in | [S022](passes/S022/README.md) | check for `Schema` of `TypeMap` with invalid `Elem` of `*schema.Resource` | AST | | [S023](passes/S023/README.md) | check for `Schema` that should omit `Elem` with incompatible `Type` | AST | | [S024](passes/S024/README.md) | check for `Schema` that should omit `ForceNew` in data source schema attributes | AST | +| [S025](passes/S025/README.md) | check for `Schema` of `Computed` only with `AtLeastOneOf` configured | AST | +| [S026](passes/S026/README.md) | check for `Schema` of `Computed` only with `ConflictsWith` configured | AST | +| [S027](passes/S027/README.md) | check for `Schema` of `Computed` only with `Default` configured | AST | +| [S028](passes/S028/README.md) | check for `Schema` of `Computed` only with `DefaultFunc` configured | AST | +| [S029](passes/S029/README.md) | check for `Schema` of `Computed` only with `ExactlyOneOf` configured | AST | +| [S030](passes/S030/README.md) | check for `Schema` of `Computed` only with `InputDefault` configured | AST | +| [S031](passes/S031/README.md) | check for `Schema` of `Computed` only with `MaxItems` configured | AST | +| [S032](passes/S032/README.md) | check for `Schema` of `Computed` only with `MinItems` configured | AST | +| [S033](passes/S033/README.md) | check for `Schema` of `Computed` only with `StateFunc` configured | AST | ### Standard Validation Checks diff --git a/helper/terraformtype/helper/schema/type_schema.go b/helper/terraformtype/helper/schema/type_schema.go index 819a9713..e45de25f 100644 --- a/helper/terraformtype/helper/schema/type_schema.go +++ b/helper/terraformtype/helper/schema/type_schema.go @@ -67,6 +67,10 @@ func NewSchemaInfo(cl *ast.CompositeLit, info *types.Info) *SchemaInfo { TypesInfo: info, } + if kvExpr := result.Fields[SchemaFieldAtLeastOneOf]; kvExpr != nil && astutils.ExprValue(kvExpr.Value) != nil { + result.Schema.AtLeastOneOf = []string{} + } + if kvExpr := result.Fields[SchemaFieldComputed]; kvExpr != nil && astutils.ExprBoolValue(kvExpr.Value) != nil { result.Schema.Computed = *astutils.ExprBoolValue(kvExpr.Value) } @@ -79,10 +83,18 @@ func NewSchemaInfo(cl *ast.CompositeLit, info *types.Info) *SchemaInfo { result.Schema.Default = func() (interface{}, error) { return nil, nil } } + if kvExpr := result.Fields[SchemaFieldDefaultFunc]; kvExpr != nil && astutils.ExprValue(kvExpr.Value) != nil { + result.Schema.DefaultFunc = func() (interface{}, error) { return nil, nil } + } + if kvExpr := result.Fields[SchemaFieldDescription]; kvExpr != nil && astutils.ExprStringValue(kvExpr.Value) != nil { result.Schema.Description = *astutils.ExprStringValue(kvExpr.Value) } + if kvExpr := result.Fields[SchemaFieldExactlyOneOf]; kvExpr != nil && astutils.ExprValue(kvExpr.Value) != nil { + result.Schema.ExactlyOneOf = []string{} + } + if kvExpr := result.Fields[SchemaFieldDiffSuppressFunc]; kvExpr != nil && astutils.ExprValue(kvExpr.Value) != nil { result.Schema.DiffSuppressFunc = func(k, old, new string, d *tfschema.ResourceData) bool { return false } } @@ -91,6 +103,10 @@ func NewSchemaInfo(cl *ast.CompositeLit, info *types.Info) *SchemaInfo { result.Schema.ForceNew = *astutils.ExprBoolValue(kvExpr.Value) } + if kvExpr := result.Fields[SchemaFieldInputDefault]; kvExpr != nil && astutils.ExprStringValue(kvExpr.Value) != nil { + result.Schema.InputDefault = *astutils.ExprStringValue(kvExpr.Value) + } + if kvExpr := result.Fields[SchemaFieldMaxItems]; kvExpr != nil && astutils.ExprIntValue(kvExpr.Value) != nil { result.Schema.MaxItems = *astutils.ExprIntValue(kvExpr.Value) } @@ -111,6 +127,10 @@ func NewSchemaInfo(cl *ast.CompositeLit, info *types.Info) *SchemaInfo { result.Schema.Sensitive = *astutils.ExprBoolValue(kvExpr.Value) } + if kvExpr := result.Fields[SchemaFieldStateFunc]; kvExpr != nil && astutils.ExprValue(kvExpr.Value) != nil { + result.Schema.StateFunc = func(interface{}) string { return "" } + } + if kvExpr := result.Fields[SchemaFieldValidateFunc]; kvExpr != nil && astutils.ExprValue(kvExpr.Value) != nil { result.Schema.ValidateFunc = func(interface{}, string) ([]string, []error) { return nil, nil } } diff --git a/passes/S010/S010.go b/passes/S010/S010.go index f914186c..a73a30a7 100644 --- a/passes/S010/S010.go +++ b/passes/S010/S010.go @@ -5,11 +5,10 @@ package S010 import ( "go/ast" - "golang.org/x/tools/go/analysis" - "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" "github.com/bflad/tfproviderlint/passes/commentignore" - "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfo" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" ) const Doc = `check for Schema with only Computed enabled and ValidateFunc configured @@ -23,24 +22,20 @@ var Analyzer = &analysis.Analyzer{ Name: analyzerName, Doc: Doc, Requires: []*analysis.Analyzer{ - schemainfo.Analyzer, commentignore.Analyzer, + schemainfocomputedonly.Analyzer, }, Run: run, } func run(pass *analysis.Pass) (interface{}, error) { ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) - schemaInfos := pass.ResultOf[schemainfo.Analyzer].([]*schema.SchemaInfo) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) for _, schemaInfo := range schemaInfos { if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { continue } - if !schemaInfo.Schema.Computed || schemaInfo.Schema.Optional || schemaInfo.Schema.Required { - continue - } - if schemaInfo.Schema.ValidateFunc == nil { continue } diff --git a/passes/S011/S011.go b/passes/S011/S011.go index ac18ead7..bcaa234e 100644 --- a/passes/S011/S011.go +++ b/passes/S011/S011.go @@ -5,11 +5,10 @@ package S011 import ( "go/ast" - "golang.org/x/tools/go/analysis" - "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" "github.com/bflad/tfproviderlint/passes/commentignore" - "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfo" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" ) const Doc = `check for Schema with only Computed enabled and DiffSuppressFunc configured @@ -23,24 +22,20 @@ var Analyzer = &analysis.Analyzer{ Name: analyzerName, Doc: Doc, Requires: []*analysis.Analyzer{ - schemainfo.Analyzer, commentignore.Analyzer, + schemainfocomputedonly.Analyzer, }, Run: run, } func run(pass *analysis.Pass) (interface{}, error) { ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) - schemaInfos := pass.ResultOf[schemainfo.Analyzer].([]*schema.SchemaInfo) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) for _, schemaInfo := range schemaInfos { if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { continue } - if !schemaInfo.Schema.Computed || schemaInfo.Schema.Optional || schemaInfo.Schema.Required { - continue - } - if schemaInfo.Schema.DiffSuppressFunc == nil { continue } diff --git a/passes/S020/S020.go b/passes/S020/S020.go index 1398acae..5c847fd9 100644 --- a/passes/S020/S020.go +++ b/passes/S020/S020.go @@ -5,11 +5,10 @@ package S020 import ( "go/ast" - "golang.org/x/tools/go/analysis" - "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" "github.com/bflad/tfproviderlint/passes/commentignore" - "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfo" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" ) const Doc = `check for Schema with only Computed enabled and ForceNew enabled @@ -23,15 +22,15 @@ var Analyzer = &analysis.Analyzer{ Name: analyzerName, Doc: Doc, Requires: []*analysis.Analyzer{ - schemainfo.Analyzer, commentignore.Analyzer, + schemainfocomputedonly.Analyzer, }, Run: run, } func run(pass *analysis.Pass) (interface{}, error) { ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) - schemaInfos := pass.ResultOf[schemainfo.Analyzer].([]*schema.SchemaInfo) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) for _, schemaInfo := range schemaInfos { if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { continue diff --git a/passes/S025/README.md b/passes/S025/README.md new file mode 100644 index 00000000..455afb57 --- /dev/null +++ b/passes/S025/README.md @@ -0,0 +1,33 @@ +# S025 + +The S025 analyzer reports cases of schemas which enables only `Computed` +and configures `AtLeastOneOf`, which is not valid. + +## Flagged Code + +```go +&schema.Schema{ + AtLeastOneOf: []string{"example"}, + Computed: true, +} +``` + +## Passing Code + +```go +&schema.Schema{ + Computed: true, +} +``` + +## Ignoring Reports + +Singular reports can be ignored by adding the a `//lintignore:S025` Go code comment at the end of the offending line or on the line immediately proceding, e.g. + +```go +//lintignore:S025 +&schema.Schema{ + AtLeastOneOf: []string{"example"}, + Computed: true, +} +``` diff --git a/passes/S025/S025.go b/passes/S025/S025.go new file mode 100644 index 00000000..666ea331 --- /dev/null +++ b/passes/S025/S025.go @@ -0,0 +1,50 @@ +package S025 + +import ( + "go/ast" + + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/commentignore" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" +) + +const Doc = `check for Schema with only Computed enabled and AtLeastOneOf configured + +The S025 analyzer reports cases of schemas which only enables Computed +and configures AtLeastOneOf, which is not valid.` + +const analyzerName = "S025" + +var Analyzer = &analysis.Analyzer{ + Name: analyzerName, + Doc: Doc, + Requires: []*analysis.Analyzer{ + commentignore.Analyzer, + schemainfocomputedonly.Analyzer, + }, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) + for _, schemaInfo := range schemaInfos { + if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { + continue + } + + if schemaInfo.Schema.AtLeastOneOf == nil { + continue + } + + switch t := schemaInfo.AstCompositeLit.Type.(type) { + default: + pass.Reportf(schemaInfo.AstCompositeLit.Lbrace, "%s: schema should not only enable Computed and configure AtLeastOneOf", analyzerName) + case *ast.SelectorExpr: + pass.Reportf(t.Sel.Pos(), "%s: schema should not only enable Computed and configure AtLeastOneOf", analyzerName) + } + } + + return nil, nil +} diff --git a/passes/S025/S025_test.go b/passes/S025/S025_test.go new file mode 100644 index 00000000..37829f97 --- /dev/null +++ b/passes/S025/S025_test.go @@ -0,0 +1,13 @@ +package S025_test + +import ( + "testing" + + "github.com/bflad/tfproviderlint/passes/S025" + "golang.org/x/tools/go/analysis/analysistest" +) + +func TestS025(t *testing.T) { + testdata := analysistest.TestData() + analysistest.Run(t, testdata, S025.Analyzer, "a") +} diff --git a/passes/S025/testdata/src/a/alias.go b/passes/S025/testdata/src/a/alias.go new file mode 100644 index 00000000..82c561d3 --- /dev/null +++ b/passes/S025/testdata/src/a/alias.go @@ -0,0 +1,19 @@ +package a + +import ( + s "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func falias() { + _ = s.Schema{ // want "schema should not only enable Computed and configure AtLeastOneOf" + AtLeastOneOf: []string{"test"}, + Computed: true, + } + + _ = map[string]*s.Schema{ + "name": { // want "schema should not only enable Computed and configure AtLeastOneOf" + AtLeastOneOf: []string{"test"}, + Computed: true, + }, + } +} diff --git a/passes/S025/testdata/src/a/comment_ignore.go b/passes/S025/testdata/src/a/comment_ignore.go new file mode 100644 index 00000000..112518de --- /dev/null +++ b/passes/S025/testdata/src/a/comment_ignore.go @@ -0,0 +1,13 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func fcommentignore() { + //lintignore:S025 + _ = schema.Schema{ + AtLeastOneOf: []string{"test"}, + Computed: true, + } +} diff --git a/passes/S025/testdata/src/a/main.go b/passes/S025/testdata/src/a/main.go new file mode 100644 index 00000000..e79f998e --- /dev/null +++ b/passes/S025/testdata/src/a/main.go @@ -0,0 +1,33 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func f() { + _ = schema.Schema{ // want "schema should not only enable Computed and configure AtLeastOneOf" + AtLeastOneOf: []string{"test"}, + Computed: true, + } + + _ = schema.Schema{ + AtLeastOneOf: nil, + Computed: true, + } + + _ = schema.Schema{ + Computed: true, + } + + _ = schema.Schema{ + AtLeastOneOf: []string{"test"}, + Optional: true, + } + + _ = map[string]*schema.Schema{ + "name": { // want "schema should not only enable Computed and configure AtLeastOneOf" + AtLeastOneOf: []string{"test"}, + Computed: true, + }, + } +} diff --git a/passes/S025/testdata/src/a/outside_package.go b/passes/S025/testdata/src/a/outside_package.go new file mode 100644 index 00000000..95f51807 --- /dev/null +++ b/passes/S025/testdata/src/a/outside_package.go @@ -0,0 +1,19 @@ +package a + +import ( + "a/schema" +) + +func foutside() { + _ = schema.Schema{ + AtLeastOneOf: []string{"test"}, + Computed: true, + } + + _ = map[string]*schema.Schema{ + "name": { + AtLeastOneOf: []string{"test"}, + Computed: true, + }, + } +} diff --git a/passes/S025/testdata/src/a/schema/schema.go b/passes/S025/testdata/src/a/schema/schema.go new file mode 100644 index 00000000..25142dad --- /dev/null +++ b/passes/S025/testdata/src/a/schema/schema.go @@ -0,0 +1,6 @@ +package schema + +type Schema struct { + AtLeastOneOf []string + Computed bool +} diff --git a/passes/S025/testdata/src/a/vendor b/passes/S025/testdata/src/a/vendor new file mode 120000 index 00000000..776800d2 --- /dev/null +++ b/passes/S025/testdata/src/a/vendor @@ -0,0 +1 @@ +../../../../../vendor \ No newline at end of file diff --git a/passes/S026/README.md b/passes/S026/README.md new file mode 100644 index 00000000..f5c547c4 --- /dev/null +++ b/passes/S026/README.md @@ -0,0 +1,33 @@ +# S026 + +The S026 analyzer reports cases of schemas which enables only `Computed` +and configures `ConflictsWith`, which is not valid. + +## Flagged Code + +```go +&schema.Schema{ + Computed: true, + ConflictsWith: []string{"example"}, +} +``` + +## Passing Code + +```go +&schema.Schema{ + Computed: true, +} +``` + +## Ignoring Reports + +Singular reports can be ignored by adding the a `//lintignore:S026` Go code comment at the end of the offending line or on the line immediately proceding, e.g. + +```go +//lintignore:S026 +&schema.Schema{ + Computed: true, + ConflictsWith: []string{"example"}, +} +``` diff --git a/passes/S026/S026.go b/passes/S026/S026.go new file mode 100644 index 00000000..0661386c --- /dev/null +++ b/passes/S026/S026.go @@ -0,0 +1,50 @@ +package S026 + +import ( + "go/ast" + + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/commentignore" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" +) + +const Doc = `check for Schema with only Computed enabled and ConflictsWith configured + +The S026 analyzer reports cases of schemas which only enables Computed +and configures ConflictsWith, which is not valid.` + +const analyzerName = "S026" + +var Analyzer = &analysis.Analyzer{ + Name: analyzerName, + Doc: Doc, + Requires: []*analysis.Analyzer{ + commentignore.Analyzer, + schemainfocomputedonly.Analyzer, + }, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) + for _, schemaInfo := range schemaInfos { + if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { + continue + } + + if schemaInfo.Schema.ConflictsWith == nil { + continue + } + + switch t := schemaInfo.AstCompositeLit.Type.(type) { + default: + pass.Reportf(schemaInfo.AstCompositeLit.Lbrace, "%s: schema should not only enable Computed and configure ConflictsWith", analyzerName) + case *ast.SelectorExpr: + pass.Reportf(t.Sel.Pos(), "%s: schema should not only enable Computed and configure ConflictsWith", analyzerName) + } + } + + return nil, nil +} diff --git a/passes/S026/S026_test.go b/passes/S026/S026_test.go new file mode 100644 index 00000000..e10c9e9f --- /dev/null +++ b/passes/S026/S026_test.go @@ -0,0 +1,13 @@ +package S026_test + +import ( + "testing" + + "github.com/bflad/tfproviderlint/passes/S026" + "golang.org/x/tools/go/analysis/analysistest" +) + +func TestS026(t *testing.T) { + testdata := analysistest.TestData() + analysistest.Run(t, testdata, S026.Analyzer, "a") +} diff --git a/passes/S026/testdata/src/a/alias.go b/passes/S026/testdata/src/a/alias.go new file mode 100644 index 00000000..26dc98b9 --- /dev/null +++ b/passes/S026/testdata/src/a/alias.go @@ -0,0 +1,19 @@ +package a + +import ( + s "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func falias() { + _ = s.Schema{ // want "schema should not only enable Computed and configure ConflictsWith" + Computed: true, + ConflictsWith: []string{"test"}, + } + + _ = map[string]*s.Schema{ + "name": { // want "schema should not only enable Computed and configure ConflictsWith" + Computed: true, + ConflictsWith: []string{"test"}, + }, + } +} diff --git a/passes/S026/testdata/src/a/comment_ignore.go b/passes/S026/testdata/src/a/comment_ignore.go new file mode 100644 index 00000000..072da5e8 --- /dev/null +++ b/passes/S026/testdata/src/a/comment_ignore.go @@ -0,0 +1,13 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func fcommentignore() { + //lintignore:S026 + _ = schema.Schema{ + Computed: true, + ConflictsWith: []string{"test"}, + } +} diff --git a/passes/S026/testdata/src/a/main.go b/passes/S026/testdata/src/a/main.go new file mode 100644 index 00000000..b9450ab3 --- /dev/null +++ b/passes/S026/testdata/src/a/main.go @@ -0,0 +1,33 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func f() { + _ = schema.Schema{ // want "schema should not only enable Computed and configure ConflictsWith" + Computed: true, + ConflictsWith: []string{"test"}, + } + + _ = schema.Schema{ + Computed: true, + ConflictsWith: nil, + } + + _ = schema.Schema{ + Computed: true, + } + + _ = schema.Schema{ + ConflictsWith: []string{"test"}, + Optional: true, + } + + _ = map[string]*schema.Schema{ + "name": { // want "schema should not only enable Computed and configure ConflictsWith" + Computed: true, + ConflictsWith: []string{"test"}, + }, + } +} diff --git a/passes/S026/testdata/src/a/outside_package.go b/passes/S026/testdata/src/a/outside_package.go new file mode 100644 index 00000000..fef03a0d --- /dev/null +++ b/passes/S026/testdata/src/a/outside_package.go @@ -0,0 +1,19 @@ +package a + +import ( + "a/schema" +) + +func foutside() { + _ = schema.Schema{ + Computed: true, + ConflictsWith: []string{"test"}, + } + + _ = map[string]*schema.Schema{ + "name": { + Computed: true, + ConflictsWith: []string{"test"}, + }, + } +} diff --git a/passes/S026/testdata/src/a/schema/schema.go b/passes/S026/testdata/src/a/schema/schema.go new file mode 100644 index 00000000..8ba404ab --- /dev/null +++ b/passes/S026/testdata/src/a/schema/schema.go @@ -0,0 +1,6 @@ +package schema + +type Schema struct { + Computed bool + ConflictsWith []string +} diff --git a/passes/S026/testdata/src/a/vendor b/passes/S026/testdata/src/a/vendor new file mode 120000 index 00000000..776800d2 --- /dev/null +++ b/passes/S026/testdata/src/a/vendor @@ -0,0 +1 @@ +../../../../../vendor \ No newline at end of file diff --git a/passes/S027/README.md b/passes/S027/README.md new file mode 100644 index 00000000..783ff24b --- /dev/null +++ b/passes/S027/README.md @@ -0,0 +1,33 @@ +# S027 + +The S027 analyzer reports cases of schemas which enables only `Computed` +and configures `Default`, which is not valid. + +## Flagged Code + +```go +&schema.Schema{ + Computed: true, + Default: "example", +} +``` + +## Passing Code + +```go +&schema.Schema{ + Computed: true, +} +``` + +## Ignoring Reports + +Singular reports can be ignored by adding the a `//lintignore:S027` Go code comment at the end of the offending line or on the line immediately proceding, e.g. + +```go +//lintignore:S027 +&schema.Schema{ + Computed: true, + Default: "example", +} +``` diff --git a/passes/S027/S027.go b/passes/S027/S027.go new file mode 100644 index 00000000..20996de9 --- /dev/null +++ b/passes/S027/S027.go @@ -0,0 +1,50 @@ +package S027 + +import ( + "go/ast" + + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/commentignore" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" +) + +const Doc = `check for Schema with only Computed enabled and Default configured + +The S027 analyzer reports cases of schemas which only enables Computed +and configures Default, which is not valid.` + +const analyzerName = "S027" + +var Analyzer = &analysis.Analyzer{ + Name: analyzerName, + Doc: Doc, + Requires: []*analysis.Analyzer{ + commentignore.Analyzer, + schemainfocomputedonly.Analyzer, + }, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) + for _, schemaInfo := range schemaInfos { + if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { + continue + } + + if schemaInfo.Schema.Default == nil { + continue + } + + switch t := schemaInfo.AstCompositeLit.Type.(type) { + default: + pass.Reportf(schemaInfo.AstCompositeLit.Lbrace, "%s: schema should not only enable Computed and configure Default", analyzerName) + case *ast.SelectorExpr: + pass.Reportf(t.Sel.Pos(), "%s: schema should not only enable Computed and configure Default", analyzerName) + } + } + + return nil, nil +} diff --git a/passes/S027/S027_test.go b/passes/S027/S027_test.go new file mode 100644 index 00000000..38e248c8 --- /dev/null +++ b/passes/S027/S027_test.go @@ -0,0 +1,13 @@ +package S027_test + +import ( + "testing" + + "github.com/bflad/tfproviderlint/passes/S027" + "golang.org/x/tools/go/analysis/analysistest" +) + +func TestS027(t *testing.T) { + testdata := analysistest.TestData() + analysistest.Run(t, testdata, S027.Analyzer, "a") +} diff --git a/passes/S027/testdata/src/a/alias.go b/passes/S027/testdata/src/a/alias.go new file mode 100644 index 00000000..af19cf95 --- /dev/null +++ b/passes/S027/testdata/src/a/alias.go @@ -0,0 +1,19 @@ +package a + +import ( + s "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func falias() { + _ = s.Schema{ // want "schema should not only enable Computed and configure Default" + Computed: true, + Default: "test", + } + + _ = map[string]*s.Schema{ + "name": { // want "schema should not only enable Computed and configure Default" + Computed: true, + Default: "test", + }, + } +} diff --git a/passes/S027/testdata/src/a/comment_ignore.go b/passes/S027/testdata/src/a/comment_ignore.go new file mode 100644 index 00000000..3d27550d --- /dev/null +++ b/passes/S027/testdata/src/a/comment_ignore.go @@ -0,0 +1,13 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func fcommentignore() { + //lintignore:S027 + _ = schema.Schema{ + Computed: true, + Default: "test", + } +} diff --git a/passes/S027/testdata/src/a/main.go b/passes/S027/testdata/src/a/main.go new file mode 100644 index 00000000..74aa0d3a --- /dev/null +++ b/passes/S027/testdata/src/a/main.go @@ -0,0 +1,33 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func f() { + _ = schema.Schema{ // want "schema should not only enable Computed and configure Default" + Computed: true, + Default: "test", + } + + _ = schema.Schema{ + Computed: true, + Default: nil, + } + + _ = schema.Schema{ + Computed: true, + } + + _ = schema.Schema{ + Default: "test", + Optional: true, + } + + _ = map[string]*schema.Schema{ + "name": { // want "schema should not only enable Computed and configure Default" + Computed: true, + Default: "test", + }, + } +} diff --git a/passes/S027/testdata/src/a/outside_package.go b/passes/S027/testdata/src/a/outside_package.go new file mode 100644 index 00000000..a06882f1 --- /dev/null +++ b/passes/S027/testdata/src/a/outside_package.go @@ -0,0 +1,19 @@ +package a + +import ( + "a/schema" +) + +func foutside() { + _ = schema.Schema{ + Computed: true, + Default: "test", + } + + _ = map[string]*schema.Schema{ + "name": { + Computed: true, + Default: "test", + }, + } +} diff --git a/passes/S027/testdata/src/a/schema/schema.go b/passes/S027/testdata/src/a/schema/schema.go new file mode 100644 index 00000000..e42d8498 --- /dev/null +++ b/passes/S027/testdata/src/a/schema/schema.go @@ -0,0 +1,6 @@ +package schema + +type Schema struct { + Computed bool + Default string +} diff --git a/passes/S027/testdata/src/a/vendor b/passes/S027/testdata/src/a/vendor new file mode 120000 index 00000000..776800d2 --- /dev/null +++ b/passes/S027/testdata/src/a/vendor @@ -0,0 +1 @@ +../../../../../vendor \ No newline at end of file diff --git a/passes/S028/README.md b/passes/S028/README.md new file mode 100644 index 00000000..6bbff1a1 --- /dev/null +++ b/passes/S028/README.md @@ -0,0 +1,33 @@ +# S028 + +The S028 analyzer reports cases of schemas which enables only `Computed` +and configures `DefaultFunc`, which is not valid. + +## Flagged Code + +```go +&schema.Schema{ + Computed: true, + DefaultFunc: /* ... */, +} +``` + +## Passing Code + +```go +&schema.Schema{ + Computed: true, +} +``` + +## Ignoring Reports + +Singular reports can be ignored by adding the a `//lintignore:S028` Go code comment at the end of the offending line or on the line immediately proceding, e.g. + +```go +//lintignore:S028 +&schema.Schema{ + Computed: true, + DefaultFunc: /* ... */, +} +``` diff --git a/passes/S028/S028.go b/passes/S028/S028.go new file mode 100644 index 00000000..cbb86eed --- /dev/null +++ b/passes/S028/S028.go @@ -0,0 +1,50 @@ +package S028 + +import ( + "go/ast" + + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/commentignore" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" +) + +const Doc = `check for Schema with only Computed enabled and DefaultFunc configured + +The S028 analyzer reports cases of schemas which only enables Computed +and configures DefaultFunc, which is not valid.` + +const analyzerName = "S028" + +var Analyzer = &analysis.Analyzer{ + Name: analyzerName, + Doc: Doc, + Requires: []*analysis.Analyzer{ + commentignore.Analyzer, + schemainfocomputedonly.Analyzer, + }, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) + for _, schemaInfo := range schemaInfos { + if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { + continue + } + + if schemaInfo.Schema.DefaultFunc == nil { + continue + } + + switch t := schemaInfo.AstCompositeLit.Type.(type) { + default: + pass.Reportf(schemaInfo.AstCompositeLit.Lbrace, "%s: schema should not only enable Computed and configure DefaultFunc", analyzerName) + case *ast.SelectorExpr: + pass.Reportf(t.Sel.Pos(), "%s: schema should not only enable Computed and configure DefaultFunc", analyzerName) + } + } + + return nil, nil +} diff --git a/passes/S028/S028_test.go b/passes/S028/S028_test.go new file mode 100644 index 00000000..2dde9c07 --- /dev/null +++ b/passes/S028/S028_test.go @@ -0,0 +1,13 @@ +package S028_test + +import ( + "testing" + + "github.com/bflad/tfproviderlint/passes/S028" + "golang.org/x/tools/go/analysis/analysistest" +) + +func TestS028(t *testing.T) { + testdata := analysistest.TestData() + analysistest.Run(t, testdata, S028.Analyzer, "a") +} diff --git a/passes/S028/testdata/src/a/alias.go b/passes/S028/testdata/src/a/alias.go new file mode 100644 index 00000000..cbc48467 --- /dev/null +++ b/passes/S028/testdata/src/a/alias.go @@ -0,0 +1,19 @@ +package a + +import ( + s "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func falias() { + _ = s.Schema{ // want "schema should not only enable Computed and configure DefaultFunc" + Computed: true, + DefaultFunc: defaultFunc, + } + + _ = map[string]*s.Schema{ + "name": { // want "schema should not only enable Computed and configure DefaultFunc" + Computed: true, + DefaultFunc: defaultFunc, + }, + } +} diff --git a/passes/S028/testdata/src/a/comment_ignore.go b/passes/S028/testdata/src/a/comment_ignore.go new file mode 100644 index 00000000..eb020aef --- /dev/null +++ b/passes/S028/testdata/src/a/comment_ignore.go @@ -0,0 +1,13 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func fcommentignore() { + //lintignore:S028 + _ = schema.Schema{ + Computed: true, + DefaultFunc: defaultFunc, + } +} diff --git a/passes/S028/testdata/src/a/main.go b/passes/S028/testdata/src/a/main.go new file mode 100644 index 00000000..8dc914e0 --- /dev/null +++ b/passes/S028/testdata/src/a/main.go @@ -0,0 +1,37 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func f() { + _ = schema.Schema{ // want "schema should not only enable Computed and configure DefaultFunc" + Computed: true, + DefaultFunc: defaultFunc, + } + + _ = schema.Schema{ + Computed: true, + DefaultFunc: nil, + } + + _ = schema.Schema{ + Computed: true, + } + + _ = schema.Schema{ + DefaultFunc: defaultFunc, + Optional: true, + } + + _ = map[string]*schema.Schema{ + "name": { // want "schema should not only enable Computed and configure DefaultFunc" + Computed: true, + DefaultFunc: defaultFunc, + }, + } +} + +func defaultFunc() (interface{}, error) { + return nil, nil +} diff --git a/passes/S028/testdata/src/a/outside_package.go b/passes/S028/testdata/src/a/outside_package.go new file mode 100644 index 00000000..a1f327ac --- /dev/null +++ b/passes/S028/testdata/src/a/outside_package.go @@ -0,0 +1,19 @@ +package a + +import ( + "a/schema" +) + +func foutside() { + _ = schema.Schema{ + Computed: true, + DefaultFunc: defaultFunc, + } + + _ = map[string]*schema.Schema{ + "name": { + Computed: true, + DefaultFunc: defaultFunc, + }, + } +} diff --git a/passes/S028/testdata/src/a/schema/schema.go b/passes/S028/testdata/src/a/schema/schema.go new file mode 100644 index 00000000..4606dc47 --- /dev/null +++ b/passes/S028/testdata/src/a/schema/schema.go @@ -0,0 +1,6 @@ +package schema + +type Schema struct { + Computed bool + DefaultFunc func() (interface{}, error) +} diff --git a/passes/S028/testdata/src/a/vendor b/passes/S028/testdata/src/a/vendor new file mode 120000 index 00000000..776800d2 --- /dev/null +++ b/passes/S028/testdata/src/a/vendor @@ -0,0 +1 @@ +../../../../../vendor \ No newline at end of file diff --git a/passes/S029/README.md b/passes/S029/README.md new file mode 100644 index 00000000..7f9a9b4c --- /dev/null +++ b/passes/S029/README.md @@ -0,0 +1,33 @@ +# S029 + +The S029 analyzer reports cases of schemas which enables only `Computed` +and configures `ExactlyOneOf`, which is not valid. + +## Flagged Code + +```go +&schema.Schema{ + Computed: true, + ExactlyOneOf: []string{"example"}, +} +``` + +## Passing Code + +```go +&schema.Schema{ + Computed: true, +} +``` + +## Ignoring Reports + +Singular reports can be ignored by adding the a `//lintignore:S029` Go code comment at the end of the offending line or on the line immediately proceding, e.g. + +```go +//lintignore:S029 +&schema.Schema{ + Computed: true, + ExactlyOneOf: []string{"example"}, +} +``` diff --git a/passes/S029/S029.go b/passes/S029/S029.go new file mode 100644 index 00000000..590f21b7 --- /dev/null +++ b/passes/S029/S029.go @@ -0,0 +1,50 @@ +package S029 + +import ( + "go/ast" + + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/commentignore" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" +) + +const Doc = `check for Schema with only Computed enabled and ExactlyOneOf configured + +The S029 analyzer reports cases of schemas which only enables Computed +and configures ExactlyOneOf, which is not valid.` + +const analyzerName = "S029" + +var Analyzer = &analysis.Analyzer{ + Name: analyzerName, + Doc: Doc, + Requires: []*analysis.Analyzer{ + commentignore.Analyzer, + schemainfocomputedonly.Analyzer, + }, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) + for _, schemaInfo := range schemaInfos { + if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { + continue + } + + if schemaInfo.Schema.ExactlyOneOf == nil { + continue + } + + switch t := schemaInfo.AstCompositeLit.Type.(type) { + default: + pass.Reportf(schemaInfo.AstCompositeLit.Lbrace, "%s: schema should not only enable Computed and configure ExactlyOneOf", analyzerName) + case *ast.SelectorExpr: + pass.Reportf(t.Sel.Pos(), "%s: schema should not only enable Computed and configure ExactlyOneOf", analyzerName) + } + } + + return nil, nil +} diff --git a/passes/S029/S029_test.go b/passes/S029/S029_test.go new file mode 100644 index 00000000..48c51421 --- /dev/null +++ b/passes/S029/S029_test.go @@ -0,0 +1,13 @@ +package S029_test + +import ( + "testing" + + "github.com/bflad/tfproviderlint/passes/S029" + "golang.org/x/tools/go/analysis/analysistest" +) + +func TestS029(t *testing.T) { + testdata := analysistest.TestData() + analysistest.Run(t, testdata, S029.Analyzer, "a") +} diff --git a/passes/S029/testdata/src/a/alias.go b/passes/S029/testdata/src/a/alias.go new file mode 100644 index 00000000..618d5310 --- /dev/null +++ b/passes/S029/testdata/src/a/alias.go @@ -0,0 +1,19 @@ +package a + +import ( + s "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func falias() { + _ = s.Schema{ // want "schema should not only enable Computed and configure ExactlyOneOf" + Computed: true, + ExactlyOneOf: []string{"test"}, + } + + _ = map[string]*s.Schema{ + "name": { // want "schema should not only enable Computed and configure ExactlyOneOf" + Computed: true, + ExactlyOneOf: []string{"test"}, + }, + } +} diff --git a/passes/S029/testdata/src/a/comment_ignore.go b/passes/S029/testdata/src/a/comment_ignore.go new file mode 100644 index 00000000..7fffaad0 --- /dev/null +++ b/passes/S029/testdata/src/a/comment_ignore.go @@ -0,0 +1,13 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func fcommentignore() { + //lintignore:S029 + _ = schema.Schema{ + Computed: true, + ExactlyOneOf: []string{"test"}, + } +} diff --git a/passes/S029/testdata/src/a/main.go b/passes/S029/testdata/src/a/main.go new file mode 100644 index 00000000..96418261 --- /dev/null +++ b/passes/S029/testdata/src/a/main.go @@ -0,0 +1,33 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func f() { + _ = schema.Schema{ // want "schema should not only enable Computed and configure ExactlyOneOf" + Computed: true, + ExactlyOneOf: []string{"test"}, + } + + _ = schema.Schema{ + Computed: true, + ExactlyOneOf: nil, + } + + _ = schema.Schema{ + Computed: true, + } + + _ = schema.Schema{ + ExactlyOneOf: []string{"test"}, + Optional: true, + } + + _ = map[string]*schema.Schema{ + "name": { // want "schema should not only enable Computed and configure ExactlyOneOf" + Computed: true, + ExactlyOneOf: []string{"test"}, + }, + } +} diff --git a/passes/S029/testdata/src/a/outside_package.go b/passes/S029/testdata/src/a/outside_package.go new file mode 100644 index 00000000..8c98377c --- /dev/null +++ b/passes/S029/testdata/src/a/outside_package.go @@ -0,0 +1,19 @@ +package a + +import ( + "a/schema" +) + +func foutside() { + _ = schema.Schema{ + Computed: true, + ExactlyOneOf: []string{"test"}, + } + + _ = map[string]*schema.Schema{ + "name": { + Computed: true, + ExactlyOneOf: []string{"test"}, + }, + } +} diff --git a/passes/S029/testdata/src/a/schema/schema.go b/passes/S029/testdata/src/a/schema/schema.go new file mode 100644 index 00000000..f55ebac4 --- /dev/null +++ b/passes/S029/testdata/src/a/schema/schema.go @@ -0,0 +1,6 @@ +package schema + +type Schema struct { + Computed bool + ExactlyOneOf []string +} diff --git a/passes/S029/testdata/src/a/vendor b/passes/S029/testdata/src/a/vendor new file mode 120000 index 00000000..776800d2 --- /dev/null +++ b/passes/S029/testdata/src/a/vendor @@ -0,0 +1 @@ +../../../../../vendor \ No newline at end of file diff --git a/passes/S030/README.md b/passes/S030/README.md new file mode 100644 index 00000000..a835daf1 --- /dev/null +++ b/passes/S030/README.md @@ -0,0 +1,33 @@ +# S030 + +The S030 analyzer reports cases of schemas which enables only `Computed` +and configures `InputDefault`, which is not valid. + +## Flagged Code + +```go +&schema.Schema{ + Computed: true, + InputDefault: "example", +} +``` + +## Passing Code + +```go +&schema.Schema{ + Computed: true, +} +``` + +## Ignoring Reports + +Singular reports can be ignored by adding the a `//lintignore:S030` Go code comment at the end of the offending line or on the line immediately proceding, e.g. + +```go +//lintignore:S030 +&schema.Schema{ + Computed: true, + InputDefault: "example", +} +``` diff --git a/passes/S030/S030.go b/passes/S030/S030.go new file mode 100644 index 00000000..43a7c826 --- /dev/null +++ b/passes/S030/S030.go @@ -0,0 +1,50 @@ +package S030 + +import ( + "go/ast" + + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/commentignore" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" +) + +const Doc = `check for Schema with only Computed enabled and InputDefault configured + +The S030 analyzer reports cases of schemas which only enables Computed +and configures InputDefault, which is not valid.` + +const analyzerName = "S030" + +var Analyzer = &analysis.Analyzer{ + Name: analyzerName, + Doc: Doc, + Requires: []*analysis.Analyzer{ + commentignore.Analyzer, + schemainfocomputedonly.Analyzer, + }, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) + for _, schemaInfo := range schemaInfos { + if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { + continue + } + + if !schemaInfo.DeclaresField(schema.SchemaFieldInputDefault) { + continue + } + + switch t := schemaInfo.AstCompositeLit.Type.(type) { + default: + pass.Reportf(schemaInfo.AstCompositeLit.Lbrace, "%s: schema should not only enable Computed and configure InputDefault", analyzerName) + case *ast.SelectorExpr: + pass.Reportf(t.Sel.Pos(), "%s: schema should not only enable Computed and configure InputDefault", analyzerName) + } + } + + return nil, nil +} diff --git a/passes/S030/S030_test.go b/passes/S030/S030_test.go new file mode 100644 index 00000000..28c8830d --- /dev/null +++ b/passes/S030/S030_test.go @@ -0,0 +1,13 @@ +package S030_test + +import ( + "testing" + + "github.com/bflad/tfproviderlint/passes/S030" + "golang.org/x/tools/go/analysis/analysistest" +) + +func TestS030(t *testing.T) { + testdata := analysistest.TestData() + analysistest.Run(t, testdata, S030.Analyzer, "a") +} diff --git a/passes/S030/testdata/src/a/alias.go b/passes/S030/testdata/src/a/alias.go new file mode 100644 index 00000000..8df95761 --- /dev/null +++ b/passes/S030/testdata/src/a/alias.go @@ -0,0 +1,19 @@ +package a + +import ( + s "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func falias() { + _ = s.Schema{ // want "schema should not only enable Computed and configure InputDefault" + Computed: true, + InputDefault: "test", + } + + _ = map[string]*s.Schema{ + "name": { // want "schema should not only enable Computed and configure InputDefault" + Computed: true, + InputDefault: "test", + }, + } +} diff --git a/passes/S030/testdata/src/a/comment_ignore.go b/passes/S030/testdata/src/a/comment_ignore.go new file mode 100644 index 00000000..219eee70 --- /dev/null +++ b/passes/S030/testdata/src/a/comment_ignore.go @@ -0,0 +1,13 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func fcommentignore() { + //lintignore:S030 + _ = schema.Schema{ + Computed: true, + InputDefault: "test", + } +} diff --git a/passes/S030/testdata/src/a/main.go b/passes/S030/testdata/src/a/main.go new file mode 100644 index 00000000..8697ecc5 --- /dev/null +++ b/passes/S030/testdata/src/a/main.go @@ -0,0 +1,28 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func f() { + _ = schema.Schema{ // want "schema should not only enable Computed and configure InputDefault" + Computed: true, + InputDefault: "test", + } + + _ = schema.Schema{ + Computed: true, + } + + _ = schema.Schema{ + InputDefault: "test", + Optional: true, + } + + _ = map[string]*schema.Schema{ + "name": { // want "schema should not only enable Computed and configure InputDefault" + Computed: true, + InputDefault: "test", + }, + } +} diff --git a/passes/S030/testdata/src/a/outside_package.go b/passes/S030/testdata/src/a/outside_package.go new file mode 100644 index 00000000..0daaeecf --- /dev/null +++ b/passes/S030/testdata/src/a/outside_package.go @@ -0,0 +1,19 @@ +package a + +import ( + "a/schema" +) + +func foutside() { + _ = schema.Schema{ + Computed: true, + InputDefault: "test", + } + + _ = map[string]*schema.Schema{ + "name": { + Computed: true, + InputDefault: "test", + }, + } +} diff --git a/passes/S030/testdata/src/a/schema/schema.go b/passes/S030/testdata/src/a/schema/schema.go new file mode 100644 index 00000000..b4080b0d --- /dev/null +++ b/passes/S030/testdata/src/a/schema/schema.go @@ -0,0 +1,6 @@ +package schema + +type Schema struct { + Computed bool + InputDefault string +} diff --git a/passes/S030/testdata/src/a/vendor b/passes/S030/testdata/src/a/vendor new file mode 120000 index 00000000..776800d2 --- /dev/null +++ b/passes/S030/testdata/src/a/vendor @@ -0,0 +1 @@ +../../../../../vendor \ No newline at end of file diff --git a/passes/S031/README.md b/passes/S031/README.md new file mode 100644 index 00000000..b7c063b8 --- /dev/null +++ b/passes/S031/README.md @@ -0,0 +1,33 @@ +# S031 + +The S031 analyzer reports cases of schemas which enables only `Computed` +and configures `MaxItems`, which is not valid. + +## Flagged Code + +```go +&schema.Schema{ + Computed: true, + MaxItems: 1, +} +``` + +## Passing Code + +```go +&schema.Schema{ + Computed: true, +} +``` + +## Ignoring Reports + +Singular reports can be ignored by adding the a `//lintignore:S031` Go code comment at the end of the offending line or on the line immediately proceding, e.g. + +```go +//lintignore:S031 +&schema.Schema{ + Computed: true, + MaxItems: 1, +} +``` diff --git a/passes/S031/S031.go b/passes/S031/S031.go new file mode 100644 index 00000000..2ccb192f --- /dev/null +++ b/passes/S031/S031.go @@ -0,0 +1,50 @@ +package S031 + +import ( + "go/ast" + + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/commentignore" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" +) + +const Doc = `check for Schema with only Computed enabled and MaxItems configured + +The S031 analyzer reports cases of schemas which only enables Computed +and configures MaxItems, which is not valid.` + +const analyzerName = "S031" + +var Analyzer = &analysis.Analyzer{ + Name: analyzerName, + Doc: Doc, + Requires: []*analysis.Analyzer{ + commentignore.Analyzer, + schemainfocomputedonly.Analyzer, + }, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) + for _, schemaInfo := range schemaInfos { + if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { + continue + } + + if !schemaInfo.DeclaresField(schema.SchemaFieldMaxItems) { + continue + } + + switch t := schemaInfo.AstCompositeLit.Type.(type) { + default: + pass.Reportf(schemaInfo.AstCompositeLit.Lbrace, "%s: schema should not only enable Computed and configure MaxItems", analyzerName) + case *ast.SelectorExpr: + pass.Reportf(t.Sel.Pos(), "%s: schema should not only enable Computed and configure MaxItems", analyzerName) + } + } + + return nil, nil +} diff --git a/passes/S031/S031_test.go b/passes/S031/S031_test.go new file mode 100644 index 00000000..b3f49afa --- /dev/null +++ b/passes/S031/S031_test.go @@ -0,0 +1,13 @@ +package S031_test + +import ( + "testing" + + "github.com/bflad/tfproviderlint/passes/S031" + "golang.org/x/tools/go/analysis/analysistest" +) + +func TestS031(t *testing.T) { + testdata := analysistest.TestData() + analysistest.Run(t, testdata, S031.Analyzer, "a") +} diff --git a/passes/S031/testdata/src/a/alias.go b/passes/S031/testdata/src/a/alias.go new file mode 100644 index 00000000..0de94058 --- /dev/null +++ b/passes/S031/testdata/src/a/alias.go @@ -0,0 +1,19 @@ +package a + +import ( + s "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func falias() { + _ = s.Schema{ // want "schema should not only enable Computed and configure MaxItems" + Computed: true, + MaxItems: 1, + } + + _ = map[string]*s.Schema{ + "name": { // want "schema should not only enable Computed and configure MaxItems" + Computed: true, + MaxItems: 1, + }, + } +} diff --git a/passes/S031/testdata/src/a/comment_ignore.go b/passes/S031/testdata/src/a/comment_ignore.go new file mode 100644 index 00000000..b1a8bcd7 --- /dev/null +++ b/passes/S031/testdata/src/a/comment_ignore.go @@ -0,0 +1,13 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func fcommentignore() { + //lintignore:S031 + _ = schema.Schema{ + Computed: true, + MaxItems: 1, + } +} diff --git a/passes/S031/testdata/src/a/main.go b/passes/S031/testdata/src/a/main.go new file mode 100644 index 00000000..29456572 --- /dev/null +++ b/passes/S031/testdata/src/a/main.go @@ -0,0 +1,28 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func f() { + _ = schema.Schema{ // want "schema should not only enable Computed and configure MaxItems" + Computed: true, + MaxItems: 1, + } + + _ = schema.Schema{ + Computed: true, + } + + _ = schema.Schema{ + MaxItems: 1, + Optional: true, + } + + _ = map[string]*schema.Schema{ + "name": { // want "schema should not only enable Computed and configure MaxItems" + Computed: true, + MaxItems: 1, + }, + } +} diff --git a/passes/S031/testdata/src/a/outside_package.go b/passes/S031/testdata/src/a/outside_package.go new file mode 100644 index 00000000..ea544b31 --- /dev/null +++ b/passes/S031/testdata/src/a/outside_package.go @@ -0,0 +1,19 @@ +package a + +import ( + "a/schema" +) + +func foutside() { + _ = schema.Schema{ + Computed: true, + MaxItems: 1, + } + + _ = map[string]*schema.Schema{ + "name": { + Computed: true, + MaxItems: 1, + }, + } +} diff --git a/passes/S031/testdata/src/a/schema/schema.go b/passes/S031/testdata/src/a/schema/schema.go new file mode 100644 index 00000000..386eae31 --- /dev/null +++ b/passes/S031/testdata/src/a/schema/schema.go @@ -0,0 +1,6 @@ +package schema + +type Schema struct { + Computed bool + MaxItems int +} diff --git a/passes/S031/testdata/src/a/vendor b/passes/S031/testdata/src/a/vendor new file mode 120000 index 00000000..776800d2 --- /dev/null +++ b/passes/S031/testdata/src/a/vendor @@ -0,0 +1 @@ +../../../../../vendor \ No newline at end of file diff --git a/passes/S032/README.md b/passes/S032/README.md new file mode 100644 index 00000000..40a63130 --- /dev/null +++ b/passes/S032/README.md @@ -0,0 +1,33 @@ +# S032 + +The S032 analyzer reports cases of schemas which enables only `Computed` +and configures `MinItems`, which is not valid. + +## Flagged Code + +```go +&schema.Schema{ + Computed: true, + MinItems: 1, +} +``` + +## Passing Code + +```go +&schema.Schema{ + Computed: true, +} +``` + +## Ignoring Reports + +Singular reports can be ignored by adding the a `//lintignore:S032` Go code comment at the end of the offending line or on the line immediately proceding, e.g. + +```go +//lintignore:S032 +&schema.Schema{ + Computed: true, + MinItems: 1, +} +``` diff --git a/passes/S032/S032.go b/passes/S032/S032.go new file mode 100644 index 00000000..55a3f3af --- /dev/null +++ b/passes/S032/S032.go @@ -0,0 +1,50 @@ +package S032 + +import ( + "go/ast" + + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/commentignore" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" +) + +const Doc = `check for Schema with only Computed enabled and MinItems configured + +The S032 analyzer reports cases of schemas which only enables Computed +and configures MinItems, which is not valid.` + +const analyzerName = "S032" + +var Analyzer = &analysis.Analyzer{ + Name: analyzerName, + Doc: Doc, + Requires: []*analysis.Analyzer{ + commentignore.Analyzer, + schemainfocomputedonly.Analyzer, + }, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) + for _, schemaInfo := range schemaInfos { + if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { + continue + } + + if !schemaInfo.DeclaresField(schema.SchemaFieldMinItems) { + continue + } + + switch t := schemaInfo.AstCompositeLit.Type.(type) { + default: + pass.Reportf(schemaInfo.AstCompositeLit.Lbrace, "%s: schema should not only enable Computed and configure MinItems", analyzerName) + case *ast.SelectorExpr: + pass.Reportf(t.Sel.Pos(), "%s: schema should not only enable Computed and configure MinItems", analyzerName) + } + } + + return nil, nil +} diff --git a/passes/S032/S032_test.go b/passes/S032/S032_test.go new file mode 100644 index 00000000..17de2420 --- /dev/null +++ b/passes/S032/S032_test.go @@ -0,0 +1,13 @@ +package S032_test + +import ( + "testing" + + "github.com/bflad/tfproviderlint/passes/S032" + "golang.org/x/tools/go/analysis/analysistest" +) + +func TestS032(t *testing.T) { + testdata := analysistest.TestData() + analysistest.Run(t, testdata, S032.Analyzer, "a") +} diff --git a/passes/S032/testdata/src/a/alias.go b/passes/S032/testdata/src/a/alias.go new file mode 100644 index 00000000..d2343d26 --- /dev/null +++ b/passes/S032/testdata/src/a/alias.go @@ -0,0 +1,19 @@ +package a + +import ( + s "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func falias() { + _ = s.Schema{ // want "schema should not only enable Computed and configure MinItems" + Computed: true, + MinItems: 1, + } + + _ = map[string]*s.Schema{ + "name": { // want "schema should not only enable Computed and configure MinItems" + Computed: true, + MinItems: 1, + }, + } +} diff --git a/passes/S032/testdata/src/a/comment_ignore.go b/passes/S032/testdata/src/a/comment_ignore.go new file mode 100644 index 00000000..3a851953 --- /dev/null +++ b/passes/S032/testdata/src/a/comment_ignore.go @@ -0,0 +1,13 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func fcommentignore() { + //lintignore:S032 + _ = schema.Schema{ + Computed: true, + MinItems: 1, + } +} diff --git a/passes/S032/testdata/src/a/main.go b/passes/S032/testdata/src/a/main.go new file mode 100644 index 00000000..c66e6b1b --- /dev/null +++ b/passes/S032/testdata/src/a/main.go @@ -0,0 +1,28 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func f() { + _ = schema.Schema{ // want "schema should not only enable Computed and configure MinItems" + Computed: true, + MinItems: 1, + } + + _ = schema.Schema{ + Computed: true, + } + + _ = schema.Schema{ + MinItems: 1, + Optional: true, + } + + _ = map[string]*schema.Schema{ + "name": { // want "schema should not only enable Computed and configure MinItems" + Computed: true, + MinItems: 1, + }, + } +} diff --git a/passes/S032/testdata/src/a/outside_package.go b/passes/S032/testdata/src/a/outside_package.go new file mode 100644 index 00000000..3f1af875 --- /dev/null +++ b/passes/S032/testdata/src/a/outside_package.go @@ -0,0 +1,19 @@ +package a + +import ( + "a/schema" +) + +func foutside() { + _ = schema.Schema{ + Computed: true, + MinItems: 1, + } + + _ = map[string]*schema.Schema{ + "name": { + Computed: true, + MinItems: 1, + }, + } +} diff --git a/passes/S032/testdata/src/a/schema/schema.go b/passes/S032/testdata/src/a/schema/schema.go new file mode 100644 index 00000000..85de3723 --- /dev/null +++ b/passes/S032/testdata/src/a/schema/schema.go @@ -0,0 +1,6 @@ +package schema + +type Schema struct { + Computed bool + MinItems int +} diff --git a/passes/S032/testdata/src/a/vendor b/passes/S032/testdata/src/a/vendor new file mode 120000 index 00000000..776800d2 --- /dev/null +++ b/passes/S032/testdata/src/a/vendor @@ -0,0 +1 @@ +../../../../../vendor \ No newline at end of file diff --git a/passes/S033/README.md b/passes/S033/README.md new file mode 100644 index 00000000..b6cb6a09 --- /dev/null +++ b/passes/S033/README.md @@ -0,0 +1,33 @@ +# S033 + +The S033 analyzer reports cases of schemas which enables only `Computed` +and configures `DefaultFunc`, which is not valid. + +## Flagged Code + +```go +&schema.Schema{ + Computed: true, + DefaultFunc: /* ... */, +} +``` + +## Passing Code + +```go +&schema.Schema{ + Computed: true, +} +``` + +## Ignoring Reports + +Singular reports can be ignored by adding the a `//lintignore:S033` Go code comment at the end of the offending line or on the line immediately proceding, e.g. + +```go +//lintignore:S033 +&schema.Schema{ + Computed: true, + DefaultFunc: /* ... */, +} +``` diff --git a/passes/S033/S033.go b/passes/S033/S033.go new file mode 100644 index 00000000..c74b814d --- /dev/null +++ b/passes/S033/S033.go @@ -0,0 +1,50 @@ +package S033 + +import ( + "go/ast" + + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/commentignore" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfocomputedonly" + "golang.org/x/tools/go/analysis" +) + +const Doc = `check for Schema with only Computed enabled and StateFunc configured + +The S033 analyzer reports cases of schemas which only enables Computed +and configures StateFunc, which is not valid.` + +const analyzerName = "S033" + +var Analyzer = &analysis.Analyzer{ + Name: analyzerName, + Doc: Doc, + Requires: []*analysis.Analyzer{ + commentignore.Analyzer, + schemainfocomputedonly.Analyzer, + }, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer) + schemaInfos := pass.ResultOf[schemainfocomputedonly.Analyzer].([]*schema.SchemaInfo) + for _, schemaInfo := range schemaInfos { + if ignorer.ShouldIgnore(analyzerName, schemaInfo.AstCompositeLit) { + continue + } + + if schemaInfo.Schema.StateFunc == nil { + continue + } + + switch t := schemaInfo.AstCompositeLit.Type.(type) { + default: + pass.Reportf(schemaInfo.AstCompositeLit.Lbrace, "%s: schema should not only enable Computed and configure StateFunc", analyzerName) + case *ast.SelectorExpr: + pass.Reportf(t.Sel.Pos(), "%s: schema should not only enable Computed and configure StateFunc", analyzerName) + } + } + + return nil, nil +} diff --git a/passes/S033/S033_test.go b/passes/S033/S033_test.go new file mode 100644 index 00000000..39ab187a --- /dev/null +++ b/passes/S033/S033_test.go @@ -0,0 +1,13 @@ +package S033_test + +import ( + "testing" + + "github.com/bflad/tfproviderlint/passes/S033" + "golang.org/x/tools/go/analysis/analysistest" +) + +func TestS033(t *testing.T) { + testdata := analysistest.TestData() + analysistest.Run(t, testdata, S033.Analyzer, "a") +} diff --git a/passes/S033/testdata/src/a/alias.go b/passes/S033/testdata/src/a/alias.go new file mode 100644 index 00000000..f51783a5 --- /dev/null +++ b/passes/S033/testdata/src/a/alias.go @@ -0,0 +1,19 @@ +package a + +import ( + s "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func falias() { + _ = s.Schema{ // want "schema should not only enable Computed and configure StateFunc" + Computed: true, + StateFunc: stateFunc, + } + + _ = map[string]*s.Schema{ + "name": { // want "schema should not only enable Computed and configure StateFunc" + Computed: true, + StateFunc: stateFunc, + }, + } +} diff --git a/passes/S033/testdata/src/a/comment_ignore.go b/passes/S033/testdata/src/a/comment_ignore.go new file mode 100644 index 00000000..6a76a240 --- /dev/null +++ b/passes/S033/testdata/src/a/comment_ignore.go @@ -0,0 +1,13 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func fcommentignore() { + //lintignore:S033 + _ = schema.Schema{ + Computed: true, + StateFunc: stateFunc, + } +} diff --git a/passes/S033/testdata/src/a/main.go b/passes/S033/testdata/src/a/main.go new file mode 100644 index 00000000..885312c7 --- /dev/null +++ b/passes/S033/testdata/src/a/main.go @@ -0,0 +1,37 @@ +package a + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func f() { + _ = schema.Schema{ // want "schema should not only enable Computed and configure StateFunc" + Computed: true, + StateFunc: stateFunc, + } + + _ = schema.Schema{ + Computed: true, + StateFunc: nil, + } + + _ = schema.Schema{ + Computed: true, + } + + _ = schema.Schema{ + StateFunc: stateFunc, + Optional: true, + } + + _ = map[string]*schema.Schema{ + "name": { // want "schema should not only enable Computed and configure StateFunc" + Computed: true, + StateFunc: stateFunc, + }, + } +} + +func stateFunc(interface{}) string { + return "" +} diff --git a/passes/S033/testdata/src/a/outside_package.go b/passes/S033/testdata/src/a/outside_package.go new file mode 100644 index 00000000..fd77ef2d --- /dev/null +++ b/passes/S033/testdata/src/a/outside_package.go @@ -0,0 +1,19 @@ +package a + +import ( + "a/schema" +) + +func foutside() { + _ = schema.Schema{ + Computed: true, + StateFunc: stateFunc, + } + + _ = map[string]*schema.Schema{ + "name": { + Computed: true, + StateFunc: stateFunc, + }, + } +} diff --git a/passes/S033/testdata/src/a/schema/schema.go b/passes/S033/testdata/src/a/schema/schema.go new file mode 100644 index 00000000..b6c16971 --- /dev/null +++ b/passes/S033/testdata/src/a/schema/schema.go @@ -0,0 +1,6 @@ +package schema + +type Schema struct { + Computed bool + StateFunc func(interface{}) string +} diff --git a/passes/S033/testdata/src/a/vendor b/passes/S033/testdata/src/a/vendor new file mode 120000 index 00000000..776800d2 --- /dev/null +++ b/passes/S033/testdata/src/a/vendor @@ -0,0 +1 @@ +../../../../../vendor \ No newline at end of file diff --git a/passes/checks.go b/passes/checks.go index 0fc3c944..fa03aa49 100644 --- a/passes/checks.go +++ b/passes/checks.go @@ -38,6 +38,15 @@ import ( "github.com/bflad/tfproviderlint/passes/S022" "github.com/bflad/tfproviderlint/passes/S023" "github.com/bflad/tfproviderlint/passes/S024" + "github.com/bflad/tfproviderlint/passes/S025" + "github.com/bflad/tfproviderlint/passes/S026" + "github.com/bflad/tfproviderlint/passes/S027" + "github.com/bflad/tfproviderlint/passes/S028" + "github.com/bflad/tfproviderlint/passes/S029" + "github.com/bflad/tfproviderlint/passes/S030" + "github.com/bflad/tfproviderlint/passes/S031" + "github.com/bflad/tfproviderlint/passes/S032" + "github.com/bflad/tfproviderlint/passes/S033" "github.com/bflad/tfproviderlint/passes/V001" "github.com/bflad/tfproviderlint/passes/V002" "github.com/bflad/tfproviderlint/passes/V003" @@ -90,6 +99,15 @@ var AllChecks = []*analysis.Analyzer{ S022.Analyzer, S023.Analyzer, S024.Analyzer, + S025.Analyzer, + S026.Analyzer, + S027.Analyzer, + S028.Analyzer, + S029.Analyzer, + S030.Analyzer, + S031.Analyzer, + S032.Analyzer, + S033.Analyzer, V001.Analyzer, V002.Analyzer, V003.Analyzer, diff --git a/passes/helper/schema/schemainfocomputedonly/schemainfocomputedonly.go b/passes/helper/schema/schemainfocomputedonly/schemainfocomputedonly.go new file mode 100644 index 00000000..57009fbb --- /dev/null +++ b/passes/helper/schema/schemainfocomputedonly/schemainfocomputedonly.go @@ -0,0 +1,35 @@ +package schemainfocomputedonly + +import ( + "reflect" + + "github.com/bflad/tfproviderlint/helper/terraformtype/helper/schema" + "github.com/bflad/tfproviderlint/passes/helper/schema/schemainfo" + "golang.org/x/tools/go/analysis" +) + +var Analyzer = &analysis.Analyzer{ + Name: "schemainfocomputedonly", + Doc: "find github.com/hashicorp/terraform-plugin-sdk/helper/schema.Schema literals with Computed: true only for later passes", + Requires: []*analysis.Analyzer{ + schemainfo.Analyzer, + }, + Run: run, + ResultType: reflect.TypeOf([]*schema.SchemaInfo{}), +} + +func run(pass *analysis.Pass) (interface{}, error) { + schemaInfos := pass.ResultOf[schemainfo.Analyzer].([]*schema.SchemaInfo) + + var result []*schema.SchemaInfo + + for _, schemaInfo := range schemaInfos { + if !schemaInfo.Schema.Computed || schemaInfo.Schema.Optional || schemaInfo.Schema.Required { + continue + } + + result = append(result, schemaInfo) + } + + return result, nil +}