terraform/tools/defect-detector/analyzer.go
Sarah French b046d8a010
Some checks are pending
build / Determine intended Terraform version (push) Waiting to run
build / Determine Go toolchain version (push) Waiting to run
build / Generate release metadata (push) Blocked by required conditions
build / Build for freebsd_386 (push) Blocked by required conditions
build / Build for linux_386 (push) Blocked by required conditions
build / Build for openbsd_386 (push) Blocked by required conditions
build / Build for windows_386 (push) Blocked by required conditions
build / Build for darwin_amd64 (push) Blocked by required conditions
build / Build for freebsd_amd64 (push) Blocked by required conditions
build / Build for linux_amd64 (push) Blocked by required conditions
build / Build for openbsd_amd64 (push) Blocked by required conditions
build / Build for solaris_amd64 (push) Blocked by required conditions
build / Build for windows_amd64 (push) Blocked by required conditions
build / Build for freebsd_arm (push) Blocked by required conditions
build / Build for linux_arm (push) Blocked by required conditions
build / Build for darwin_arm64 (push) Blocked by required conditions
build / Build for linux_arm64 (push) Blocked by required conditions
build / Build for windows_arm64 (push) Blocked by required conditions
build / Build for linux_s390x (push) Blocked by required conditions
build / Build Docker image for linux_386 (push) Blocked by required conditions
build / Build Docker image for linux_amd64 (push) Blocked by required conditions
build / Build Docker image for linux_arm (push) Blocked by required conditions
build / Build Docker image for linux_arm64 (push) Blocked by required conditions
build / Build Docker image for linux_s390x (push) Blocked by required conditions
build / Build e2etest for linux_386 (push) Blocked by required conditions
build / Build e2etest for windows_386 (push) Blocked by required conditions
build / Build e2etest for darwin_amd64 (push) Blocked by required conditions
build / Build e2etest for linux_amd64 (push) Blocked by required conditions
build / Build e2etest for windows_amd64 (push) Blocked by required conditions
build / Build e2etest for linux_arm (push) Blocked by required conditions
build / Build e2etest for darwin_arm64 (push) Blocked by required conditions
build / Build e2etest for linux_arm64 (push) Blocked by required conditions
build / Run e2e test for linux_386 (push) Blocked by required conditions
build / Run e2e test for windows_386 (push) Blocked by required conditions
build / Run e2e test for darwin_amd64 (push) Blocked by required conditions
build / Run e2e test for linux_amd64 (push) Blocked by required conditions
build / Run e2e test for windows_amd64 (push) Blocked by required conditions
build / Run e2e test for linux_arm (push) Blocked by required conditions
build / Run e2e test for linux_arm64 (push) Blocked by required conditions
build / Run terraform-exec test for linux amd64 (push) Blocked by required conditions
Quick Checks / Unit Tests (push) Waiting to run
Quick Checks / Race Tests (push) Waiting to run
Quick Checks / End-to-end Tests (push) Waiting to run
Quick Checks / Code Consistency Checks (push) Waiting to run
Quick Checks / Automated defect checks (push) Waiting to run
ci: Add (tfdiags.Diagnostics).Append checker to PR checks (#38606)
* tool: Go analyzer made with Copilot that detects when calls to tfdiags.Diagnostics.Append ignores the returned value.
* ci: Update script to be able to identify newly-added instances of the defect in a PR context aware way
* ci: Tool only identifies new occurrences of defect when run in CI on a PR
2026-05-19 10:32:10 +01:00

86 lines
1.8 KiB
Go

// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: BUSL-1.1
package defectdetector
import (
"go/ast"
"go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
// DiagsAppendAnalyzer reports ignored return values from tfdiags.Diagnostics.Append.
var DiagsAppendAnalyzer = &analysis.Analyzer{
Name: "tfdiagsappendcheck",
Doc: "reports ignored return values from tfdiags.Diagnostics.Append",
Requires: []*analysis.Analyzer{
inspect.Analyzer,
},
Run: run,
}
func run(pass *analysis.Pass) (interface{}, error) {
ins, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
if !ok {
return nil, nil
}
nodeFilter := []ast.Node{(*ast.ExprStmt)(nil)}
ins.Preorder(nodeFilter, func(n ast.Node) {
exprStmt := n.(*ast.ExprStmt)
call, ok := exprStmt.X.(*ast.CallExpr)
if !ok {
return
}
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok || sel.Sel == nil || sel.Sel.Name != "Append" {
return
}
selInfo, ok := pass.TypesInfo.Selections[sel]
if !ok || selInfo.Kind() != types.MethodVal {
return
}
if !isTfdiagsDiagnostics(selInfo.Recv()) {
// Ignore calls to other Append methods that aren't tfdiags.Diagnostics.Append.
return
}
pass.Reportf(sel.Sel.Pos(), "ignored return value from tfdiags.Diagnostics.Append")
})
return nil, nil
}
// Check that the receiver type is tfdiags.Diagnostics or *tfdiags.Diagnostics
func isTfdiagsDiagnostics(t types.Type) bool {
if t == nil {
return false
}
if ptr, ok := t.(*types.Pointer); ok {
t = ptr.Elem()
}
named, ok := t.(*types.Named)
if !ok {
return false
}
obj := named.Obj()
if obj == nil || obj.Name() != "Diagnostics" {
return false
}
pkg := obj.Pkg()
if pkg == nil {
return false
}
return pkg.Path() == "github.com/hashicorp/terraform/internal/tfdiags"
}