5 files changed,
55 insertions(+),
16 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-08-13 13:40:52 +0300
Authored at:
2026-08-13 13:24:13 +0300
Change ID:
zlsoytnstwqqnurntpplvnvkwnqkqyum
Parent:
1925839
M
internal/linter/rule_undeclared_account.go
··· 1 1 package linter 2 2 3 3 import ( 4 - "fmt" 5 - 6 4 "olexsmir.xyz/clerk/internal/analyzer" 7 5 ) 8 6 ··· 25 23 Code: u.ID(), 26 24 Severity: u.Severity(), 27 25 Span: usage.Posting.Account.Span, 28 - Message: fmt.Sprintf("undeclared account: %s", name), 26 + Message: "undeclared account: " + name, 29 27 }) 30 28 } 31 29 }
M
internal/linter/rule_undeclared_commodity.go
··· 1 1 package linter 2 2 3 3 import ( 4 - "fmt" 5 - 6 4 "olexsmir.xyz/clerk/internal/analyzer" 7 5 ) 8 6 ··· 22 20 Code: u.ID(), 23 21 Severity: u.Severity(), 24 22 Span: usage.Amount.Span, 25 - Message: fmt.Sprintf("undeclared commodity: %s", name), 23 + Message: "undeclared commodity: " + name, 26 24 }) 27 25 } 28 26 }
M
internal/linter/rule_undeclared_payee.go
··· 1 1 package linter 2 2 3 3 import ( 4 - "fmt" 5 - 6 4 "olexsmir.xyz/clerk/internal/analyzer" 7 5 ) 8 6 ··· 25 23 Code: u.ID(), 26 24 Severity: u.Severity(), 27 25 Span: usage.Payee.Span, 28 - Message: fmt.Sprintf("undeclared payee: %s", name), 26 + Message: "undeclared payee: " + name, 29 27 }) 30 28 } 31 29 }
M
internal/lsp/diagnostics.go
··· 2 2 3 3 import ( 4 4 "context" 5 - "fmt" 6 5 "time" 7 6 8 7 "go.lsp.dev/jsonrpc2" ··· 84 83 } 85 84 86 85 func (s *server) groupFindsByFile(finds []linter.Find) map[string][]protocol.Diagnostic { 87 - diags := make(map[string][]protocol.Diagnostic) 86 + // count per file to pre-size the diagnostic slices: append growth on ~10k 87 + // findings is the dominant allocation in the diagnostics path 88 + counts := make(map[string]int, len(finds)) 89 + for _, find := range finds { 90 + if find.Span.Start.File != "" { 91 + counts[find.Span.Start.File]++ 92 + } 93 + } 94 + diags := make(map[string][]protocol.Diagnostic, len(counts)) 95 + for fpath, n := range counts { 96 + diags[fpath] = make([]protocol.Diagnostic, 0, n) 97 + } 88 98 for _, find := range finds { 89 99 file := find.Span.Start.File 90 100 if file == "" { ··· 106 116 } 107 117 108 118 func dedupFinds(finds []linter.Find) []linter.Find { 109 - seen := make(map[string]bool) 119 + seen := make(map[findKey]bool, len(finds)) 110 120 dedup := make([]linter.Find, 0, len(finds)) 111 121 for _, f := range finds { 112 - s := f.Span.Start 113 - key := fmt.Sprintf("%s:%d:%d:%s", s.File, s.Line, s.Col, f.Code) // TODO: performace 114 - if seen[key] { 122 + k := findKey{f.Span.Start.File, f.Span.Start.Line, f.Span.Start.Col, f.Code} 123 + if seen[k] { 115 124 continue 116 125 } 117 - seen[key] = true 126 + seen[k] = true 118 127 dedup = append(dedup, f) 119 128 } 120 129 return dedup 130 +} 131 + 132 +// findKey identifies a find by its position and rule; a struct key avoids a 133 +// per-find fmt.Sprintf. 134 +type findKey struct { 135 + file string 136 + line, col int 137 + code linter.RuleID 121 138 } 122 139 123 140 func spanToRange(span token.Span) protocol.Range {
A
internal/lsp/diagnostics_test.go
··· 1 +package lsp 2 + 3 +import ( 4 + "os" 5 + "testing" 6 + 7 + "go.lsp.dev/uri" 8 +) 9 + 10 +func BenchmarkDiagnostics(b *testing.B) { 11 + path := "../../journal/testdata/journals/actual-1ktxns-100accts.journal" 12 + src, err := os.ReadFile(path) 13 + if err != nil { 14 + b.Fatal(err) 15 + } 16 + 17 + srv := NewServer("test") 18 + srv.server.openDoc(uri.URI("file:///test.journal"), string(src), 1, "journal") 19 + 20 + b.ReportAllocs() 21 + b.ResetTimer() 22 + for b.Loop() { 23 + // Per-edit cost: re-resolve (parse) + lint + group findings. 24 + a := srv.server.buildAnalysis() 25 + finds := dedupFinds(srv.server.linter.Run(a)) 26 + _ = srv.server.groupFindsByFile(finds) 27 + } 28 +}