Extraction of the application under analysis   as of version 2.6.0 (built on 6 Sep 2018)


The Julia analyzer computes a set of methods and constructors that are assumed to be callable from the user of the program under analysis. They are called entry points. This means that the static analysis is performed as if the entry points were the only methods that can be called from the user of the code. Of course, if the entry points call other methods, these other methods are analyzed as well, and so on. This recursive process is called extraction of the reachable part of the application under analysis. Note that, if an instance method is an entry point, then the constructors of its receiver are implicitly entry points, since the user must have been able to create an instance of an object when it calls a method on that object. Since there is no information on the way the user will call the entry points, Julia assumes that their parameters might be completely arbitrary (they might be null as well as non-null, they might share, be cyclical and so on). This is called a worst-case assumption on the initial state of the entry points. Since Julia only analyzes the reachable portion of a program, it is important to understand how the entry points are selected.

Selection of the entry points

Julia selects the set of entry points according to four possible alternatives. We report them below and concretely show their difference for the analysis of the following program, by using the Deadcode and UselessTest checkers:

import com.juliasoft.julia.extraction.EntryPoint;

public class C {
  public static void main(String[] args) {
    for (String s: args)
      process(s);
  }

  private static void process(String s) {}

  public C(String name) {
    print("hello I am " + name);
  }

  private void print(String s) {
    System.out.println(s);
  }

  @EntryPoint private void test13() {
    if (13 == compute13())
      System.out.println("equals");
  }

  protected int compute13() {
    return 13;
  }

  public void test17() {
    if (17 == compute17())
      System.out.println("equals");
  }

  protected final int compute17() {
    return 17;
  }
}

Only standard entry points (ONLY_STANDARD_ENTRIES)

Chose this modality for analyzing stand-alone applications

With this modality, Julia automatically selects as entry points the main() methods and all methods that override a library method, such as run() methods of threads or equals() methods. This also includes event handlers of Swing or Android. Moreover, entry points explicitly marked as such by the programmer are considered. For instance, in the previous example and with this modality, the entry points would be

  • main(), since it is a main method
  • test13(), since it is explicitly marked as entry point by the programmer
  • the constructor of C, since otherwise test13() cannot be called and could not be an entry point
  • The static analysis of the above program with the Deadcode and UselessTest checkers issues the following warnings with this modality:

    C.java:20: [UselessTest: TestIsPredeterminedWarning] The result of this test is fixed: you are comparing 13 against 13
    C.java:29: [Deadcode: UncalledWarning] Method C.test17():void is not reachable
    C.java:34: [Deadcode: UncalledWarning] Method C.compute17():int is not reachable

    Note that methods test17() and compute17() are deemed unreachable, while all other methods are actually reachable from the entry points. Since test17() is unreachable, there is no warning about the useless comparison of 17 with itself at line 29, since it occurs in unreachable code and Julia only analyzes reachable code.

    All public entries (ALL_ENTRIES)

    Chose this modality for analyzing libraries

    With this modality, Julia automatically selects as entry points those selected with the previous modality, plus all public methods and constructors. For instance, in the previous example, the entry points with this modality would be

  • main(), since it is a main method
  • test13(), since it is explicitly marked as entry point by the programmer
  • the constructor of C, since otherwise test13() cannot be called and could not be an entry point, and since it is public
  • test17(), since it is public
  • The static analysis of the above program with the Deadcode and UselessTest checkers issues the following warnings with this modality:

    C.java:20: [UselessTest: TestIsPredeterminedWarning] The result of this test is fixed: you are comparing 13 against 13
    C.java:29: [UselessTest: TestIsPredeterminedWarning] The result of this test is fixed: you are comparing 17 against 17

    Note that all methods are considered reachable now and that the useless test inside test17() is identified correctly.

    Only public entries, allowing redefinitions (LIBRARY)

    Chose this modality for analyzing libraries whose classes you expect the user to redefine

    With this modality, Julia behaves as in the previous modality but assumes that non-final methods can be redefined in subclasses. This allows one to analyze classes that are expected to be subclassed by the user of the code. Note, however, that this reduces the precision of the analysis, since most data flow inferences cannot be performed anymore (the code might change its behavior by subclassing). For instance, in the previous example, the entry points with this modality would be the same as in the previous modality, that is:

  • main(), since it is a main method
  • test13(), since it is explicitly marked as entry point by the programmer
  • the constructor of C, since otherwise test13() cannot be called and could not be an entry point, and since it is public
  • test17(), since it is public
  • However, the static analysis of the above program with the Deadcode and UselessTest checkers issues only the following warning with this modality:

    C.java:29: [UselessTest: TestIsPredeterminedWarning] The result of this test is fixed: you are comparing 17 against 17

    Note that the useless test at line 20 is not such anymore, since method compute13() could be redefined in subclasses and not yield 13 anymore. Instead, method compute17() is final and its behavior is consequently fixed, so that Julia issues the warning at line 29 also with this modality.

    Only explicit entries (ONLY_EXPLICIT_ENTRIES)

    Chose this modality for analyzing the code reachable from some methods or constructors only

    With this modality, Julia considers as entry points only those methods or constructors that the programmer has explicitly annotated as such. This allows one to slice the program and analyze only the slice that is reachable from the manually selected entry points. Remember, however, that if an explicit entry point is an instance method, then the constructors of its receiver are implicitly considered as entry points, since it is not possible to call a method on an object if that object has not yet been created. For instance, in the previous example, the entry points with this modality would be:

  • test13(), since it is explicitly marked as entry point by the programmer
  • the constructor of C, since otherwise test13() cannot be called and could not be an entry point

    The static analysis of the above program with the Deadcode and UselessTest checkers issues the following warnings with this modality:

    C.java:4: [Deadcode: UncalledWarning] Method C.main(java.lang.String[]):void is not reachable
    C.java:9: [Deadcode: UncalledWarning] Method C.process(java.lang.String):void is not reachable
    C.java:20: [UselessTest: TestIsPredeterminedWarning] The result of this test is fixed: you are comparing 13 against 13
    C.java:29: [Deadcode: UncalledWarning] Method C.test17():void is not reachable
    C.java:34: [Deadcode: UncalledWarning] Method C.compute17():int is not reachable

    This time, the reachable code consists of the constructor of C and of methods test13() and compute13(). Moreover, the useless test at line 29 is not reported, since it occurs in unreachable code.

    Application classes and library classes

    Julia's extraction identifies an over-approximation of the reachable portion of the code under analysis. The classes inside that portion are parsed and analyzed. However, such reachable classes might be part of the actual application under analysis or might be library classes from the standard package java.* or from other libraries included in the analysis. The difference is important since, in the first case, the user of Julia expects the tool to generate warnings on application classes and compute statistics of analysis over such classes, while, in the second case, the same user does not expect warnings nor statistics on library classes, that he might not even understand, if he is not the writer of the library code. For this reason, Julia partitions reachable classes into two sets:

  • application classes are part of the application under analysis, are typically written by the programmer and consequently Julia reports warnings and statistics on them;
  • library classes are part of the language support or are third-party libraries included in the analysis, for extra precision, or are code artifacts introduced by the compiler or are auto-generated by some automatic code generator. Julia does not report warnings nor statistics on them. The rationale behind the notion of library classes is that the user of Julia will not even recognize the code where the warning is issued and would consequently consider that warning as noise.


    While it is completely clear that java.* classes or classes of libraries explicitly included as such are library classes, things become ambiguous for compilation artifacts and auto-generated classes. Not all compilers and code generators mark them as synthetic, which would simplify their identification. As a consequence, Julia has some heuristic knowledge about which classes should be considered as compilation artifacts and auto-generated, and consequently put in the set of library classes. In particular, the following rules apply to determine if a class of the application is a library class:

  • classes marked as synthetic are library classes
  • classes annotated with Julia's annotation @Closed are library classes
  • JAXB auto-generated classes, instances of com.sun.xml.bind.JAXBObject, javax.xml.bind.UnmarshallerHandler or javax.xml.bind.helpers.AbstractMarshallerImpl, are library classes
  • Android's BuildConfig classes are library classes
  • Android's resource classes under the R hierarchy are library classes (such as R.layout, for instance)

    If some class falls under these rules but you still want to consider it as part of the application and hence to have warnings reported on it, you can annotate the class with Julia's annotation @StatisticallyClosed.


    Sometimes, the notion of being library code applies to specific methods or fields, rather than to a class as a whole. That is, no warnings nor statistics are computed for such methods and fields, although they might be computed elsewhere in their same class. In particular, Julia applies to following rules to determine if a method or field of the application is a library method or field:

  • fields and methods marked as synthetic are library methods
  • the this$0 field used to refer to the outer class from an inner class is a library field
  • the access$X methods used to access private state and methods of outer classes from inner classes is a library method
  • getters and setters of classes annotated as @javax.persistence.Entity are library methods
  • methods value() and valueOf(String) of enum's are library methods