Create linter rules with go-ruleguard

Linters, the tools that help me write better source code. The first Linter was developed in 1978, as a means to analyse source code. Since then, Linters have evolved to perform tasks beyond its original specification. Nowadays, Linters can “perform Static Analysis, enforce configuration flags, check for compliance with a given style-guide or security rule, and a lot more.” Go’s standard library ships with command gofmt , gofmt performs static analysis on specified source code. The command can also rewrite source code to improve formatting. gofmt is a Go Linter. The OSS community offers its set of Go Linters as well. One of my favorite OSS projects is go-ruleguard . I find it useful because the rules are defined dynamically, with Go code. go-ruleguard has a custom command to perform source code analysis. To run the command, you will need to specify the go source with the rules, and the files to analyse. If used correctly, go-ruleguardis a powerful tool to master.

Writing a linter rule

The first rule I wrote detects if strings are being appended together with the + operator. Joining strings this way is not efficient on a large scale, hence my motivation for writing this. I began by writing source code that would break the rule on purpose. Here is the content of file main.go :

main.go

Next, I’ll create a file named rules.go , it’ll house my Linter rules :

rules.go

This is the interesting part, the powerful syntax available in go-ruleguard . The analysis operates in a similar manner compared to tests. You, the developer, would define a function that is invoked by a command. In this case, the command is ruleguard . The rule above looks for patterns similar to $x + $v and $x += $v . $x and $v represent possible string typed variables or literals. They also become variables, accessible to chained methods. I’ve added a clause within method Where to make sure the linter doesn’t confuse number addition with string concat. This is done by checking if variable x is of type string. Lastly, I’ll chain method Report to write the error out to the console. This is my console output after running the linter defined above :

It is as simple as that. I wanted my next use to wow people. I wrote a linter to detect infinite recursion.

Writing a complex rule

I wrote a rule to detect infinite recursion. It is a rule you would refer to as a “toy.” In the sense that it is using a weak pattern to find matches. The rule searches for a function that invokes itself, the function won’t be flagged if it has conditional return statements. Here is how main.go would look like :

main.go

The second function, infWorkBad will violate the rule, as it has no conditional return statements. I defined the rule to detect recursion with the following code :

rules.go

With this example, we are using a combination of regexp and pattern matching. I devised a clever idea to check if a function invoking itself. I assigned the function name to variable $name , and look for a similar text value next to a pair parentheses. Variable body is prefixed by an asterisk, denoting a wildcard pattern. This will get all the text between the first curly brace and the function invocation. A regexp search is performed on variable body. The search happens on invocation of chained method Where . The search checks if keyword return is present within an if statement. If not, the function will break the rule. The following output will be generated when I perform the analysis :

As expected, infWorkBad will run until the end of time.

Conclusion

go-ruleguard is a great source code analysis tool. The ability to define Linter rules with Go code is unprecedented. As shown with the examples above, it accommodates to the “out-of-the-box” thinker. The documentation is great, with code samples showing its use cases. As a newbie to go-ruleguard , this is my initial understanding of the library. So forgive me if my post missed an important concept. For my next post on the topic, I’ll write about complex use cases. For people developing frameworks, go-ruleguard is an ideal tool to help developers implement your framework correctly.

Do you have a cool Go OSS library? Comment it below and I’ll write about it.

Sources

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store