November 20, 2008, 03:12:37 pm *
News:
 
   Home   Help Search Login Register  
Pages: [1]
  Print  
Author Topic: Expressing method invocation through a field  (Read 1627 times)
rodmax
Newbie
*
Posts: 2


« on: June 09, 2007, 12:47:14 am »

Hello,

I am a newbie and may be missing something.

I am having trouble expressing the concept "invokes method call through a field" in .QL.

Task #1:  Locate all calls to System.out.println()

The following .QL query just happens to work because hardly anyone uses a System.out
field read for any purpose other than invoking the println() method  Smiley     

             // readers of System.out.println()
             from FieldRead out, Class system, Method m
             where
                       system.hasQualifiedName("java.lang", "System")
                and  out.getField().hasName("out")
                and  out.getField().getDeclaringType() == system
                and  out.getSite() == m
                and  m.fromSource()
           select
                m.getDeclaringType().getPackage().getName(),
                m.getDeclaringType().getCompilationUnit().getName(),
                m.getName(),
                out

But to make this query industrial strength, we need to add the fact that field System.out
is of type java.io.PrintStream and println() is invoked through System.out.

             // invokers of System.out
             from FieldRead out, Class system, Class printStream, Method println, MethodCall cc, Method m
             where
                       system.hasQualifiedName("java.lang", "System")
                and  out.getField().hasName("out")
                and  out.getField().getDeclaringType() == system

                and  printStream.hasQualifiedName("java.io", "PrintStream")
                and  println.hasName("println")
                and  println.getDeclaringType() == printStream

                and  out.getField().getType() == printStream

                // ===========================================
                // here is where I have trouble expressing that FieldRead out was
                // for the purpose of invoking println()
                // ===========================================
                and cc.getCallee() == println
                and cc.getCaller() == m
                and  out.getSite() == m

                and  m.fromSource()
           select
                m.getDeclaringType().getPackage().getName(),
                m.getDeclaringType().getCompilationUnit().getName(),
                m.getName(),
                println


Task #2:  Locate places in code where an instance variable is used to invoke a static method.
               This is considered bad form in some circles.

               If task #1 is possible, then we could do task #2.     



Any help would be appreciated.

Thanks,
   Rod.
Logged
Oege de Moor
Newbie
*
Posts: 30


« Reply #1 on: June 09, 2007, 12:39:42 pm »

Hi Rod,

Many thanks for your interest!

I'm afraid that as it stands, it is not possible to write an exact query for what you want to do, because SemmleCode does not store information about the receiver of a method call. We'll try to add such information soon. For a precise account of what is currently in the database, please see http://semmle.com/documentation/semmlecode/database-contents/

In the meantime, you could write a query that looks for a field read and method call that occur on the same line - this is not exact, but it's a fairly good approximation, as it is fairly rare to split the field read and corresponding method call over multiple lines...

Somewhat to my dismay, I noticed that the definitions in default.ql do not provide easy access to locations for field accesses and calls - we'll fix that soon too. For now we'll have to do a bit of DIY to get at that information by defining a couple of new classes (you can just paste these into the quick query window, along with the query I'll discuss below):

Code:
class MyMethodCall extends MethodCall {
   MyLocation getLocation() {
     makesMethodCall(this,_,_,_,result)
   }
}

class MyFieldRead extends FieldRead {
   MyLocation getLocation() {
      readsField(this,_,_,_,result)
   }
}
     
class MyLocation extends Location {
   int getStartLine() {
      locations(this,_,_,_,_,result,_)
   }
}

When writing this sort of code, it can be a little tricky to know exactly what column you want in the tuples of a primitive relation - again, the above web page about database contents gives you that information.

Now we're ready to write the query for finding field reads of java.lang.System.out and calls to println that occur in the same method at the same line number:

Code:
from MyFieldRead out, MyMethodCall c
where out.getField().hasName("out")
      and
      out.getField().getDeclaringType().hasQualifiedName("java.lang","System")
      and
      out.getSite().fromSource()
      and
      out.getSite() = c.getCaller()
      and
      c.getLocation().getStartLine() = out.getLocation().getStartLine()
      and
      c.getCallee().hasName("println")
select out.getSite().getDeclaringType(),
       out.getSite(),
       c

As an aside, note that I've selected elements rather than doing "getName()" as you did in your query. The reason is that this way, one can easily navigate from query results to the corresponding location in the source, simply by double-clicking. It's not necessary to convert results to strings in a select clause.

Logged
rodmax
Newbie
*
Posts: 2


« Reply #2 on: June 10, 2007, 11:13:43 pm »

Hi Oege,

Much thanks for your reply.  Your solution is quite a good one until the database is augmented
with method call receiver information.

I just discovered SemmleCode last week, installed it with Postgres 8.2, and have been
using it constantly since then.

I am porting a lot of code to an IBM WebSphere environment and
internal standards frown on System.out.println();
so eventually, each System.out.println() needs to be refactored into a JSR47 logging call.
Hence the interest in locating System.out.println() calls.  Previously, I would use tools
like find/grep/Perl to do this, but the magic of SemmleCode in Eclispe is that you can click
on the results tree and view the source code.

Excellent tool!
Logged
Pages: [1]
  Print  
 
Jump to: