Search code examples
javaintellij-ideasoot

Ambiguous method call. Both add(Unit) in Patchingchain and add(Unit) in AbstractCollection match"


Hi I run the code which has these instructions in intellij idea

SootClass c = Scene.v().loadClassAndSupport(name);
final Body b = Jimple.v().newBody(m);
PatchingChain<Unit> units = b.getUnits();       
LocalGenerator locGen = new LocalGenerator(b)
Local locThis = locGen.generateLocal(RefType.v(c));
units.add(Jimple.v().newIdentityStmt(locThis, Jimple.v().newThisRef(RefType.v(c))));

I got the error on last line with this content

"Ambiguous method call. Both add(Unit) in Patchingchain and add(Unit) in AbstractCollection match"

How I can fix this error?


Solution

  • The solution is to cast units to PatchingChain in the last line:

    ((PatchingChain) units).add(Jimple.v().newIdentityStmt(locThis, Jimple.v().newThisRef(RefType.v(c))))
    

    What's the problem?

    I've looked into Soot source code. The PatchingChain extends AbstractCollection and it's header looks like this:

    public class PatchingChain<E extends Unit> extends AbstractCollection<E> implements Chain<E>
    

    The E extends Unit section is important. When you look into java.util.AbstractCollection code, it is as follows:

    public abstract class AbstractCollection<E> implements Collection<E>
    

    So we have base class with type parameter section E and derived class with section E extends Unit.

    The AbstractCollection's method add(E e) and PatchingChain's method add(E o) seems to have the same signature, so it looks like that the one from PatchingChain (derived class) should override the one from AbstractCollection (base class), and compiler should know to use the derived one. But, in fact, the add method isn't overrided, it's overloaded. The declaration of parameter types in these generic classes affects how compiler sees those methods. The two add methods are visible to compiler as add(E) and add(E extends Unit), so they have different signatures, and there is a need to manually point to compiler (by casting to one of the classes, either base or derived), which one it should use.


    Disclaimer: This answer is my attempt to expand my comment to the question, which seemed to help and was based on website linked by me. Edits to my answer are more than welcome.