javaintellij-ideastructural-search

intellij idea structural search and replace - find all methods that call an api


I'm trying to find all methods in a large java project in which a specific static api is called, and then add an annotation those methods.

The methods can have arbitrary complexity. It can be a simple MyAPI.method("foo");, but it can be also try(Int result = MyAPI.AnotherMethod("foo")) { }. It can be nested inside of a code block, in a lambda expression, anywhere.

The best I have been able to create is this:

class $_1$ { 
  $ReturnType$ $Method$ /* count 1 to inf */ ($ParameterType$ $Parameter$ /* count 0 to inf */)
  {
    $stmt1$; /* count 0 to inf */
    MyAPI.$MethoddCall$($param$ /* count 0 to inf */);
    $stmt2$; /* count 0 to inf */
  }
}

This finds some usages, but generally only the simplest one. In the example class bellow, it finds only usage1 (a,b,c) and usage5. Other examples are skipped. Is it even possible to write such a general search, or would I need to tailor it to all possible cases?

The point is, the api is used in thousands of methods and every and each has to be annotated, so I'm looking for anything that will mean I don't have to do it by hand. Worst case, I would try luck with awk, but that would mess up with the crazy CVS we are using, so I prefer Idea solution.

Now an example:

import java.io.PrintWriter;

public class SearchAndReplaceTest
{
    private static class MyAPI
    {
        public static void foo(String x)
        {}

        public static  int bar(String x)
        {
            return 1;
        }

        public static  int baz(String x, int y)
        {
            return 1;
        }

        public static PrintWriter guu(String x)
        {
            return null;
        }
    }


    public void usage1a()
    {
        MyAPI.foo("aaaa");
    }

    public void usage1b()
    {
        MyAPI.baz("aaaa", 1+1);
    }

    public void usage1c()
    {
        MyAPI.baz("aaaa", (1+1)-1);
    }

    private static int usage2(String xxxx) throws Exception
    {
        new String();
        if(MyAPI.bar("x") == 1)
        {}
        return 0;
    }

    private void usage3a(String xxxx) throws Exception
    {
        new String();
        if(1 == 1)
        {
            MyAPI.baz("xxx", (10+3) - 1);
        }
    }

    private void usage3b(String xxxx) throws Exception
    {
        new String();
        if(1 == 1)
        {
            MyAPI.foo("xxx");
        }
    }

    private static void usage4(String xxxx) throws Exception
    {
        new String();
        try(PrintWriter x = MyAPI.guu("x"))
        {}
        catch (Exception e){}
    }

    public void usage5()
    {
        new String();
        MyAPI.foo("aaaa");
        if(1==0)
        {}
    }
}

Solution

  • I have found out how to do it. Rather than trying to utilize Structural Search's power, I have to search the body of a function only by a script. So the search is for:

    class $_1$ { 
      $ReturnType$ $Method$ ($ParameterType$ $Parameter$);
    }
    

    With those constraints:

    $Parameter$ // count: [0, inf]
    $Method$ // count: [1, inf], text: [x] within hierarchy, script: Method.getText().contains("MyAPI")