I want to be able to find all functions that fulfil certain pattern in a fast manner and only it (without getting the function body). Normally, I would use grep for that (and parse the output) but that doesn't work well if a pattern (here: function signature) spans across multiple lines.
So, from a code like this (saved as a.go):
func (o *Type) Method(a *Args,
y *Reply) error {
longcode()
longcode()
longcode()
longcode()
longcode()
return 1
}
I want to get the following result:
func (o *Type) Method(a *Args, y *Reply) error
Now, semgrep does almost allow for that now. This can be done with the following CLI command:
$ semgrep --lang go --pattern 'func ($O *Type) Method($A *$ARGTYPE, $R $REPLYTYPE) $RETTYPE { ... }'
a.go
1:func (o *Type) Method(a *Args,
2: y *Reply) error {
3: longcode()
4: longcode()
5: longcode()
6: longcode()
7: longcode()
8: return 1
9:}
However, there are three issues with that:
1) It displays the function body, which I am not interested in
2) If I wanted to run this command line with different patterns, most likely the same parsing occurs many times instead of just once and being cached (I haven't confirmed it but I think semgrep does not cache anything?), which might make this slower than it could be?
3) If I use the semgrep --lang go --pattern 'func ($O *Type) Method($A *$ARGTYPE, $R $REPLYTYPE) $RETTYPE' pattern (note the missing { ... }), nothing is found and no error is there. Is it expected?
This can be worked around by creating a rule with the message key to specify the output and then grepping out the results, as shown below. However, this is not very convenient.
$ cat rule.yml
rules:
- id: some-rule
pattern: func ($O *Type) Method($A *$ARGTYPE, $R $REPLYTYPE) $RETTYPE { ... }
message: func ($O *Type) Method($A *$ARGTYPE, $R $REPLYTYPE) $RETTYPE
severity: WARNING
languages: [go]
$ semgrep --config rule.yml | grep severity
running 1 rules...
severity:warning rule:some-rule: func (o *Type) Method(a *Args, y *Reply) error
I'd like to either be able to match just the function header/signature or to get an output of just it. With no function body.
This has been discussed on the slack and there are two ideas for solving this:
display-pattern key which would allow to re-define what is displayed as the matched code. If that is added, it should probably have some special metavariables for displaying the ... matches from the pattern[s].... from the pattern and display it as shown below. I think this is a great feature that needs to be added anyway, but it doesn't solve the described issue. class ThunderBoltClass {
[... 7 matched lines ...]
}
I think i ll add the ability to just have pattern for function signature (or a clas header)
That way you can omit the trailing {...} in the pattern and we will not display the body
Just a bit more input on this. Consider this rule where I want to report any classes where the ngOnDestroy function exists but does not contain this.isDestroyed.next(). The output is voluminous--it prints out the entire class. Both of the two options that @disconnect3d mentions above would fix this, but I am not sure how the third option you mention @aryx , would do that.
- id: ngOnDestroy-missing-next
patterns:
- pattern: |
class $CLASS {
...
ngOnDestroy() {
...
this.isDestroyed.complete(...);
...
}
...
}
- pattern-not: |
class $CLASS {
...
ngOnDestroy() {
this.isDestroyed.next(...);
this.isDestroyed.complete(...);
}
...
}
message: ngOnDestroy missing this.isDestroyed.next()
languages: [ts]
severity: ERROR
With the ability to omit trailing {...} you could potentially use pattern-in and pattern-not-in:
- id: ngOnDestroy-missing-next
patterns:
- pattern-in: |
class $CLASS {
...
ngOnDestroy() {
...
this.isDestroyed.complete(...);
...
}
...
}
- pattern-not-in: |
class $CLASS {
...
ngOnDestroy() {
this.isDestroyed.next(...);
this.isDestroyed.complete(...);
}
...
}
- pattern: class $CLASS
message: ngOnDestroy missing this.isDestroyed.next()
languages: [ts]
severity: ERROR
Should work now for function signature and class header in Go and Javascript/Typescript
Most helpful comment
That way you can omit the trailing {...} in the pattern and we will not display the body