github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa1001/sa1001.go (about) 1 package sa1001 2 3 import ( 4 "go/ast" 5 htmltemplate "html/template" 6 "strings" 7 texttemplate "text/template" 8 9 "github.com/amarpal/go-tools/analysis/code" 10 "github.com/amarpal/go-tools/analysis/lint" 11 "github.com/amarpal/go-tools/analysis/report" 12 "github.com/amarpal/go-tools/knowledge" 13 14 "golang.org/x/tools/go/analysis" 15 "golang.org/x/tools/go/analysis/passes/inspect" 16 ) 17 18 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 19 Analyzer: &analysis.Analyzer{ 20 Name: "SA1001", 21 Run: run, 22 Requires: []*analysis.Analyzer{inspect.Analyzer}, 23 }, 24 Doc: &lint.Documentation{ 25 Title: `Invalid template`, 26 Since: "2017.1", 27 Severity: lint.SeverityError, 28 MergeIf: lint.MergeIfAny, 29 }, 30 }) 31 32 var Analyzer = SCAnalyzer.Analyzer 33 34 func run(pass *analysis.Pass) (interface{}, error) { 35 fn := func(node ast.Node) { 36 call := node.(*ast.CallExpr) 37 // OPT(dh): use integer for kind 38 var kind string 39 switch code.CallName(pass, call) { 40 case "(*text/template.Template).Parse": 41 kind = "text" 42 case "(*html/template.Template).Parse": 43 kind = "html" 44 default: 45 return 46 } 47 sel := call.Fun.(*ast.SelectorExpr) 48 if !code.IsCallToAny(pass, sel.X, "text/template.New", "html/template.New") { 49 // TODO(dh): this is a cheap workaround for templates with 50 // different delims. A better solution with less false 51 // negatives would use data flow analysis to see where the 52 // template comes from and where it has been 53 return 54 } 55 s, ok := code.ExprToString(pass, call.Args[knowledge.Arg("(*text/template.Template).Parse.text")]) 56 if !ok { 57 return 58 } 59 var err error 60 switch kind { 61 case "text": 62 _, err = texttemplate.New("").Parse(s) 63 case "html": 64 _, err = htmltemplate.New("").Parse(s) 65 } 66 if err != nil { 67 // TODO(dominikh): whitelist other parse errors, if any 68 if strings.Contains(err.Error(), "unexpected") || 69 strings.Contains(err.Error(), "bad character") { 70 report.Report(pass, call.Args[knowledge.Arg("(*text/template.Template).Parse.text")], err.Error()) 71 } 72 } 73 } 74 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 75 return nil, nil 76 }