Daniel
Daniel

Reputation: 4549

Find all Java methods using only one specific property of a specific type of parameter

We're in the process of trying to identify everywhere that a specific type of object is used only to get a specific property from it, and pass that property into the method instead.

I'm thinking IntelliJ IDEA's "Structural Search" might be a good tool for this, but I'm not sure how to formulate the search template.

A concrete example:

public class MyClass {
   public Long getId() {...}
   public void setSomethingElse(int se) {...}
}

public class SomeOtherClasses {
   public void shouldBeMatched(MyClass mc) {
     doSomething();
     mc.getId();
     doSomethingElse();
   }

   public void shouldNotBeMatched(MyClass mc) {
      doSomething();
      mc.getId();
      mc.setSomethingElse(14);
      doSomethingElse();
   }

   public void alsoShouldNotBeMatched(MyClass mc) {
      shouldBeMatched(mc);
   }
}

In the above example, if I'm looking for methods that only use getId, then I should find shouldBeMatched, but not be bothered with shoudNotBeMatched and alsoShouldNotBeMatched, because they do something with the mc object other than call getId().

Upvotes: 4

Views: 294

Answers (1)

Yevgen
Yevgen

Reputation: 1667

I'm thinking IntelliJ IDEA's "Structural Search" might be a good tool for this

And it is indeed. The documentation can be tough though.

Let's check Search templates, filters, and script constraints page. It goes as follows.

Let's say, you have a variable that matches a method, a toString() method. Then this variable is actually a PsiMethod node. Retrieving variable.parent will produce a PsiClass node, and so forth. variable.text then will give you the entire text of the method. If you just need the name of the method, you can use variable.name.

It seems that the task can be done by choosing the right template and writing a corresponding Groovy script.

The template is called methods of the class and can be found under Existing templates. They provide __context__variable to be used with a script.

We have to be sure matched methods have parameters. It is simple enough, just put a count filter on a $Parameter$ variable.

Count filter

Then we need to extract the name of a parameter of desired type and see if it is called in the body of the method. The following script will do.

def parameters = __context__.getParameterList().getParameters();
def parameter = parameters.find { p -> p.getType().getName().equals('MyClass') };
if (parameter == null) return false;
String parameterName = parameter.getName();
String methodText = __context__.getText();
String occurrence = "${parameterName}.";
String methodCall = "${parameterName}.getId()";
return methodText.count(occurrence) > 0 && methodText.count(occurrence) == methodText.count(methodCall);

Put it in the $Method$ variable filter and verify the results.

Verify results by pressing Find

Upvotes: 1

Related Questions