tools/checklocks: support field comments for guard specifications

This allows specifying guards in the format:

    type foo struct {
        mu  sync.Mutex
        bar int // +checklocks:mu
    }

This syntax, while more limited, makes writing lock guards less verbose
for structures where field documentation isn't attached to each field.
For example, being able to write something like the following with field
comments reduces the number of lines in the struct by >25% and is, in my
opinion, easier to read.

    type widget struct {
        mu sync.Mutex // guards following

        // The following counters track [...]

        success  int // +checklocks:mu
        failure  int // +checklocks:mu
        retries  int // +checklocks:mu
        timeouts int // +checklocks:mu
    }

Signed-off-by: Andrew Dunham <andrew@du.nham.ca>
This commit is contained in:
Andrew Dunham
2024-06-26 13:58:40 -04:00
parent b4ca91450f
commit e3db6f0c3a
3 changed files with 22 additions and 1 deletions
+5 -1
View File
@@ -670,7 +670,11 @@ func (pc *passContext) structLockGuardFacts(structType *types.Struct, ss *ast.St
for i, field := range ss.Fields.List {
var lgf lockGuardFacts
fieldObj = structType.Field(i) // N.B. Captured above.
pc.fillLockGuardFacts(fieldObj, field.Doc, findLocal, &lgf)
if field.Doc != nil {
pc.fillLockGuardFacts(fieldObj, field.Doc, findLocal, &lgf)
} else if field.Comment != nil {
pc.fillLockGuardFacts(fieldObj, field.Comment, findLocal, &lgf)
}
// See above, for anonymous structure fields.
if ss, ok := field.Type.(*ast.StructType); ok {
+10
View File
@@ -143,3 +143,13 @@ func testTwoLocksDoubleGuardStructOnlyOne(tc *twoLocksDoubleGuardStruct) {
func testTwoLocksDoubleGuardStructInvalid(tc *twoLocksDoubleGuardStruct) {
tc.doubleGuardedField = 3 // +checklocksfail:2
}
func testFieldCommentValid(tc *fieldCommentStruct) {
tc.mu.Lock()
tc.guardedField = 1
tc.mu.Unlock()
}
func testFieldCommentInvalid(tc *fieldCommentStruct) {
tc.guardedField = 2 // +checklocksfail
}
+7
View File
@@ -64,3 +64,10 @@ type nestedGuardStruct struct {
val oneGuardStruct
ptr *oneGuardStruct
}
// fieldCommentStruct has one lock and a single field, but uses the
// field.Comment instead of field.Doc for the guard.
type fieldCommentStruct struct {
mu sync.Mutex
guardedField int // +checklocks:mu
}