As an engineer, I’ve always been obsessed with productivity and efficiency. I frequently experiment with new tools and methodologies and try to find what works best for me. The IDE is no exception… and out of everything that’s out there, IntelliJ is hard to beat.
One of the hidden (and hardly documented) gems in IntelliJ is the structured search. In a sentence, it allows you to leverage IntelliJ’s understanding of code to perform complex search and replace scenarios. There are lots of cool usages for this - although the real power hides under the
Script constraints section.
Some might say that the controller layer should not access the data layer directly. How would you search for these instances? Structured search makes it easy. In this example, we’re searching for all classes that are annotated with
@Controller and have a private member that is (or inherits from) a type that contains “Repo”:
Every legacy code ends up suffering from the
God object code smell. Classes with a large number of methods are very likely to fall into this category. Here’s how it’s done with structural search.
SLF4J recommends we use parameterized log entries to improve efficiency. How do we find log entries that use concatenation? Enter
IntelliJ’s help states the following:
Script constraints are used when items to search for are more than a plain match. If you are looking for certain language constructs (for example, constructors with the specified number of parameters, or members with the specified visibility modifiers), apply constraints described as Groovy scripts.
Granted, this leaves something to be desired. In essence, when
Script constraints is enabled, IntelliJ executes the Groovy script against the variable that was found (in this case,
$FirstParam$). If the script evaluates to true, the condition is met. As you might have guessed, the expression is passed to the Groovy code as
The type of
__context__ depends on the variable in question, although it will always be one of IntelliJ’s internal
Program Structure Interface (PSI) types. For me, the easiest way to find this out was to output the class name to a file while evaluating the Groovy script:
Finally, going back to our example, in order to find non-parameterized log statements, we are looking for statements that include a non-literal expression. Anything other than a literal expression (effectively a regular string) would be considered inefficient, as it would force string concatenation for all log statements.
Here are some links for more information about the different types of PsiExpressions: