Find out double arithmetic operations in my java c

2019-09-21 11:57发布

问题:

I have many java projects and I would like to find the double arithmetic operations (+, -, *, /) in my entire code. For example, I want to find a + b line from the below code. Once the code returns all the results, I will manually change them to some APIs. Any one has any idea how to write a program which returns all of such usages? The code to find the below results doesn't necessarily to be written java. I didn't find this question in stackoverflow or in google, please post it if you find any.

double a = 0.0, b=0;
if(a+b > 0){
...

回答1:

Operations on doubles have their own bytecode instructions: dadd, ddiv, dmul, etc. So you can search for those operations in the class files for your project.

I'm sure there are tools to do that, so search for those.

But if you can't find any suitable, it's not too hard to build your own. On a compiled class, you can use javap -c ClassName to get a fairly human-readable version of the bytecode for the class. For instance, this code:

import java.util.Random;

public class Example {
    public static void main(String[] args) {
        Random r = new Random();
        double d1 = r.nextDouble();
        double d2 = r.nextDouble();
        double d3 = d1 + d2;
        System.out.println(d3);
    }
}

...results in this output from javap -c:

Compiled from "Example.java"
public class Example {
  public Example();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/util/Random
       3: dup
       4: invokespecial #3                  // Method java/util/Random."":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method java/util/Random.nextDouble:()D
      12: dstore_2
      13: aload_1
      14: invokevirtual #4                  // Method java/util/Random.nextDouble:()D
      17: dstore        4
      19: dload_2
      20: dload         4
      22: dadd
      23: dstore        6
      25: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      28: dload         6
      30: invokevirtual #6                  // Method java/io/PrintStream.println:(D)V
      33: return
}

So you could write a program to:

  1. Get the javap -c output for each class

  2. Look in that output for double-related bytecode instructions (fairly simple regular expression work)



回答2:

You can use Refaster, part of Google's errorprone.

(Disclosure: I work for Google, and use this tool regularly. Other tools exist. I've never used it out in the real world, so I don't know how hard it is to use in your tool chain).

You can write a simple refaster rule like this:

class FindTheDoubleOps {
  @BeforeTemplate double plus(double a, double b) { return a + b; }
  @BeforeTemplate double minus(double a, double b) { return a - b; }
  @BeforeTemplate double times(double a, double b) { return a * b; }
  @BeforeTemplate double divide(double a, double b) { return a * b; }
}

which will match double operations like:

double a = 1.0 + 2.0;
double b = methodReturningDouble() + Double.NAN;

etc, i.e. a lot more than you'll find with regular expressions.

Note that I've not added an @AfterTemplate here, but you could do something like:

class ReplacePlus {
  @BeforeTemplate double before(double a, double b) { return a + b; }
  @AfterTemplate double after(double a, double b) { return myPlus(a, b); }
}

and the resulting patch will contain this substitution.


I've been trying to follow the instructions. I figured it'd be a useful bit of documentation to add here:

$ wget http://repo1.maven.org/maven2/com/google/errorprone/javac/9-dev-r3297-4/javac-9-dev-r3297-4.jar
$ wget http://repo1.maven.org/maven2/com/google/errorprone/error_prone_refaster/2.0.18/error_prone_refaster-2.0.18.jar

$ java -cp javac-9-dev-r3297-4.jar:error_prone_refaster-2.0.18.jar \
  com.google.errorprone.refaster.RefasterRuleCompiler \
  FindTheDoubleOps.java --out $(pwd)/doubleops.refaster

$ wget https://repo1.maven.org/maven2/com/google/errorprone/error_prone_ant/2.0.19/error_prone_ant-2.0.19.jar

$ java -Xbootclasspath/p:error_prone_ant-2.0.19.jar com.google.errorprone.ErrorProneCompiler -XepPatchChecks:refaster:$(pwd)/doubleops.refaster -XepPatchLocation:$(pwd)/patch.patch Example.java

$ java -Xbootclasspath/p:error_prone_ant-2.0.19.jar com.google.errorprone.ErrorProneCompiler -XepPatchChecks:refaster:$(pwd)/doubleops.refaster -XepPatchLocation:$(pwd) Example.java
Example.java:8: warning: [FindTheDoubleOps] 
        double d3 = d1 + d2;
                       ^
  Did you mean 'double d3 = /* match found */ d1 + d2;'?
1 warning
Apr 19, 2017 9:55:38 AM com.google.errorprone.apply.DiffApplier decrementTasks
INFO: Completed 1 files in 6.346 ms
Changes were written to <pwd>/error-prone.patch. Please inspect the file and apply with: patch -p0 -u -i error-prone.patch

(I used T.J. Crowder's example code above).

So, not so hard at all!