sa1001.go (2060B)
1 package sa1001 2 3 import ( 4 "go/ast" 5 htmltemplate "html/template" 6 "strings" 7 texttemplate "text/template" 8 9 "honnef.co/go/tools/analysis/code" 10 "honnef.co/go/tools/analysis/lint" 11 "honnef.co/go/tools/analysis/report" 12 "honnef.co/go/tools/knowledge" 13 "honnef.co/go/tools/pattern" 14 15 "golang.org/x/tools/go/analysis" 16 ) 17 18 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 19 Analyzer: &analysis.Analyzer{ 20 Name: "SA1001", 21 Run: run, 22 Requires: code.RequiredAnalyzers, 23 }, 24 Doc: &lint.RawDocumentation{ 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 var query = pattern.MustParse(` 35 (CallExpr 36 (Symbol 37 name@(Or 38 "(*text/template.Template).Parse" 39 "(*html/template.Template).Parse")) 40 [s])`) 41 42 func run(pass *analysis.Pass) (any, error) { 43 for node, m := range code.Matches(pass, query) { 44 name := m.State["name"].(string) 45 var kind string 46 switch name { 47 case "(*text/template.Template).Parse": 48 kind = "text" 49 case "(*html/template.Template).Parse": 50 kind = "html" 51 } 52 53 call := node.(*ast.CallExpr) 54 sel := call.Fun.(*ast.SelectorExpr) 55 if !code.IsCallToAny(pass, sel.X, "text/template.New", "html/template.New") { 56 // TODO(dh): this is a cheap workaround for templates with 57 // different delims. A better solution with less false 58 // negatives would use data flow analysis to see where the 59 // template comes from and where it has been 60 continue 61 } 62 63 s, ok := code.ExprToString(pass, m.State["s"].(ast.Expr)) 64 if !ok { 65 continue 66 } 67 var err error 68 switch kind { 69 case "text": 70 _, err = texttemplate.New("").Parse(s) 71 case "html": 72 _, err = htmltemplate.New("").Parse(s) 73 } 74 if err != nil { 75 // TODO(dominikh): whitelist other parse errors, if any 76 if strings.Contains(err.Error(), "unexpected") || 77 strings.Contains(err.Error(), "bad character") { 78 report.Report(pass, call.Args[knowledge.Arg("(*text/template.Template).Parse.text")], err.Error()) 79 } 80 } 81 } 82 return nil, nil 83 }