quasilyte / go-ruleguard

Define and run pattern-based custom linting rules.
https://go-ruleguard.github.io/
BSD 3-Clause "New" or "Revised" License
796 stars 42 forks source link

How to match func called in a defer statement? #482

Open ayushman2609 opened 2 months ago

ayushman2609 commented 2 months ago

I have a usecase where I need to check if a Recover func is called in the defer statement in a go routine. I am currently doing this using this rule:

func checkGoStmtUsedInAnonymousFunc(m dsl.Matcher) {
    m.Match(`go func(){$expr; $*_}()`).
        Where(!(m["expr"].Node.Is(`DeferStmt`) && m["expr"].Contains("safeconc.Recover"))).
        Report("anonymous function called in a go routine doesn't have a defer recover function as the first expression")
}

I am getting the safeconc.Recover func from a different package. Currently this rule is matching this func using text matching, I wanted to check if there is a better way to do that which uses the actual func in the package

quasilyte commented 2 months ago

I am getting the safeconc.Recover func from a different package.

There are multiple safeconc.Recover providers, is that what you're saying?

Currently this rule is matching this func using text matching

It's not a text matching, Contains parses the AST node and matches against that (safeconc.Recover is a selector expression). There are ways to use a text-based matching, but you're not using it in the example above.

ayushman2609 commented 2 months ago

There are multiple safeconc.Recover providers, is that what you're saying?

Its been imported from an internal library

import "x/pkg/safeconc" ... defer safeconc.Recover()

It's not a text matching, Contains parses the AST node and matches against that (safeconc.Recover is a selector expression). There are ways to use a text-based matching, but you're not using it in the example above.

Got it. Is this the best way to write this rule then? I was thinking if there is some way I could import the safeconc pkg in the rule and then get the func lit being called in the defer statement and see if its the same as the one I get from the pkg

quasilyte commented 2 months ago

There are package-aware filters related to types that require Import, but I'm not sure it can be used here. I'm not sure how to express "comes from a package" filter as it doesn't make sense for an arbitrary expression, only for identifiers, therefore adding it to a top-level could be weird (as in m["expr"].OriginPackage == "foo", because $expr is a defer statement and it may contain multiple symbols).

If you have any ideas how this can be improved and/or expressed in the DSL, please do describe it.