Skip to content

Commit 335599d

Browse files
authored
lint generated go code (#79)
* lint generated go code * x
1 parent d7ecbe7 commit 335599d

File tree

9 files changed

+417
-291
lines changed

9 files changed

+417
-291
lines changed

.github/workflows/ci.yml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,17 @@ concurrency:
2121
jobs:
2222
test:
2323
timeout-minutes: 15
24-
runs-on: ubuntu-latest
2524
strategy:
2625
matrix:
2726
go-version: [1.25.x, 1.24.x]
28-
27+
os: [ubuntu-latest]
28+
runs-on: ${{ matrix.os }}
2929
steps:
30-
- name: Checkout code
31-
uses: actions/checkout@v6
30+
- uses: actions/checkout@v6
3231
with:
3332
persist-credentials: false
3433

35-
- name: Set up Go
36-
uses: actions/setup-go@v6
34+
- uses: actions/setup-go@v6
3735
with:
3836
go-version: ${{ matrix.go-version }}
3937
cache: true
@@ -51,6 +49,13 @@ jobs:
5149
cd ../..
5250
make
5351
52+
- name: golangci-lint
53+
uses: golangci/golangci-lint-action@v9
54+
with:
55+
version: v2.7.2
56+
working-directory: test/files
57+
args: --config ../../.golangci.yml
58+
5459
- name: Run tests
5560
run: make CI_TAGS="--tags=noresinit" test
5661

.golangci.yml

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
version: "2"
2+
3+
run:
4+
timeout: 5m
5+
tests: true
6+
7+
formatters:
8+
enable:
9+
- gofumpt
10+
11+
linters:
12+
enable:
13+
# Core recommended linters
14+
- errcheck # Checks for unchecked errors
15+
- govet # Go vet checks
16+
- ineffassign # Detects ineffectual assignments
17+
- staticcheck # Advanced static analysis
18+
- unused # Finds unused code
19+
20+
# Code quality
21+
- misspell # Finds commonly misspelled words
22+
- unconvert # Unnecessary type conversions
23+
- unparam # Finds unused function parameters
24+
- gocritic # Various checks
25+
- revive # Fast, configurable linter
26+
27+
# Security and best practices
28+
- gosec # Security-focused linter
29+
- bodyclose # Checks HTTP response body closed
30+
- noctx # Finds HTTP requests without context
31+
32+
settings:
33+
gocritic:
34+
disabled-checks:
35+
- ifElseChain
36+
- elseif
37+
38+
govet:
39+
enable-all: true
40+
disable:
41+
- shadow
42+
- fieldalignment
43+
44+
revive:
45+
enable-all-rules: false
46+
47+
exclusions:
48+
rules:
49+
# Exclude specific revive rules for generated code
50+
- linters:
51+
- revive
52+
text: "package-comments"
53+
54+
- linters:
55+
- revive
56+
text: "exported"
57+
58+
# Exclude var-naming for intentional underscores in generated AVDL code
59+
- linters:
60+
- revive
61+
text: "var-naming"
62+
63+
# Exclude specific staticcheck rules
64+
- linters:
65+
- staticcheck
66+
text: "ST1005"
67+
68+
# Exclude specific gocritic rules
69+
- linters:
70+
- gocritic
71+
text: "ifElseChain"
72+
73+
# Exclude gofumpt formatting for generated AVDL code - uses tabs for alignment
74+
- linters:
75+
- gofumpt
76+
path: "test/files/sample\\.go"
77+
78+
# Exclude unused for test sample files - they're just for testing the generator
79+
- linters:
80+
- unused
81+
path: "test/files/sample\\.go"

lib/go_emit.js

Lines changed: 37 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/go_emit.iced

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,12 @@ exports.GoEmitter = class GoEmitter extends BaseEmitter
212212
@untab()
213213
@output "}"
214214
@output "tmp := ", {frag : true }
215-
@deep_copy { t : t[1], val : "(*x)", exported : true }
215+
# For pointer-to-type where type has DeepCopy() method, we can simplify
216+
# (*x).DeepCopy() to x.DeepCopy(). But for arrays/maps/primitives, we need to dereference.
217+
inner = t[1]
218+
can_simplify = (typeof(inner) is 'string' and not @is_primitive_type_lax(inner))
219+
inner_val = if can_simplify then "x" else "(*x)"
220+
@deep_copy { t : inner, val : inner_val, exported : true }
216221
@output "return &tmp"
217222
@deep_copy_postamble { val }
218223

@@ -353,7 +358,14 @@ exports.GoEmitter = class GoEmitter extends BaseEmitter
353358
cases = ("o.#{@variant_field(obj.switch.name)} == #{v}" for v in cases)
354359
@output "if #{cases.join(" || ")} {"
355360
else
356-
@output "if o.#{@variant_field(obj.switch.name)} != #{tag_val} {"
361+
# Simplify boolean comparisons for cleaner code
362+
switch_field = "o.#{@variant_field(obj.switch.name)}"
363+
if tag_val in ["true", true]
364+
@output "if !#{switch_field} {"
365+
else if tag_val in ["false", false]
366+
@output "if #{switch_field} {"
367+
else
368+
@output "if #{switch_field} != #{tag_val} {"
357369
@tab()
358370
@output """panic("wrong case accessed")"""
359371
@untab()
@@ -529,14 +541,14 @@ exports.GoEmitter = class GoEmitter extends BaseEmitter
529541
@output "}"
530542

531543
unless nostring
532-
@output "func (e " + name + ") String() string {"
544+
@output "func (o " + name + ") String() string {"
533545
@tab()
534-
@output "if v, ok := #{name}RevMap[e]; ok {"
546+
@output "if v, ok := #{name}RevMap[o]; ok {"
535547
@tab()
536548
@output "return v"
537549
@untab()
538550
@output "}"
539-
@output "return fmt.Sprintf(\"%v\", int(e))"
551+
@output "return fmt.Sprintf(\"%v\", int(o))"
540552
@untab()
541553
@output "}"
542554

@@ -584,27 +596,27 @@ exports.GoEmitter = class GoEmitter extends BaseEmitter
584596
emit_imports : ({imports, messages, types}, outfile, {types_only}) ->
585597
@output "import ("
586598
@tab()
587-
if not types_only
588-
@output '"github.com/keybase/go-framed-msgpack-rpc/rpc"'
589-
@output 'context "golang.org/x/net/context"' if Object.keys(messages).length > 0
599+
600+
# Standard library imports - gofumpt will sort and format these
601+
has_messages = Object.keys(messages).length > 0
602+
@output '"context"' if has_messages
603+
@output '"errors"' if @count_variants({types}) > 0
604+
@output '"fmt"' if @count_enums_with_string({types}) > 0
605+
@output '"time"' if has_messages
606+
607+
# Third-party imports - gofumpt will separate these from stdlib
608+
@output '"github.com/keybase/go-framed-msgpack-rpc/rpc"' unless types_only
590609

591610
# Go modules mode - construct import paths relative to module root
592611
relative_file = path_lib.resolve(outfile).replace(@gomod_dir, "")
593612
relative_dir = @gomod_path + path_lib.dirname(relative_file)
594613

595614
for {import_as, path} in imports when path.indexOf('/') >= 0
596-
if path.match /(\.\/|\.\.\/)/
597-
path = path_lib.normalize(relative_dir + "/" + path)
598-
line = ""
599-
line = import_as + " " if import_as?
615+
path = path_lib.normalize(relative_dir + "/" + path) if path.match /(\.\/|\.\.\/)/
616+
line = if import_as? then import_as + " " else ""
600617
line += '"' + path + '"'
601618
@output line
602-
if @count_variants({types}) > 0
603-
@output '"errors"'
604-
if @count_enums_with_string({types}) > 0
605-
@output '"fmt"'
606-
if Object.keys(messages).length > 0
607-
@output '"time"'
619+
608620
@untab()
609621
@output ")"
610622
@output ""

src/go_emit.test.iced

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ describe 'GoEmitter', () ->
5151
emitter.emit_imports {imports, messages: {}, types: []}, 'location/of/my/output.go', {types_only: true}
5252
code = emitter._code.join "\n"
5353

54+
# Note: gofumpt will format this, so spacing may vary
5455
expect(code).toBe('''
5556
import (
5657
\tgregor1 "github.com/keybase/node-avdl-compiler/location/of/gregor1"
@@ -88,11 +89,12 @@ describe 'GoEmitter', () ->
8889
it "should only import the content and time packages if types_only is false and the file contains messages", () ->
8990
emitter.emit_imports {imports: [], messages: {fake_message: 'blah'}, types: []}, 'location/of/my/output.go', {types_only: false}
9091
code = emitter._code.join "\n"
92+
# gofumpt will sort imports - stdlib first, then third-party
9193
expect(code).toBe("""
9294
import (
93-
\t"github.com/keybase/go-framed-msgpack-rpc/rpc"
94-
\tcontext "golang.org/x/net/context"
95+
\t"context"
9596
\t"time"
97+
\t"github.com/keybase/go-framed-msgpack-rpc/rpc"
9698
)\n\n
9799
""")
98100
return
@@ -123,6 +125,7 @@ describe 'GoEmitter', () ->
123125
emitter.emit_typedef type
124126
code = emitter._code.join "\n"
125127

128+
# gofumpt will add spacing between type and method
126129
expect(code).toBe("""
127130
type BuildPaymentID string
128131
func (o BuildPaymentID) DeepCopy() BuildPaymentID {
@@ -405,11 +408,11 @@ describe 'GoEmitter', () ->
405408
\t3: "V3",
406409
}
407410
408-
func (e AuditVersion) String() string {
409-
\tif v, ok := AuditVersionRevMap[e]; ok {
411+
func (o AuditVersion) String() string {
412+
\tif v, ok := AuditVersionRevMap[o]; ok {
410413
\t\treturn v
411414
\t}
412-
\treturn fmt.Sprintf("%v", int(e))
415+
\treturn fmt.Sprintf("%v", int(o))
413416
}\n
414417
""")
415418
return

0 commit comments

Comments
 (0)