0

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?

droidev
  • 7,352
  • 11
  • 62
  • 94
jody abbot
  • 303
  • 2
  • 15
  • 1
    It is going to be hard to answer this without seeing the declarations of `Patchingchain#add()`. Also I presume `AbstractCollection` is the one in `java.util`, correct? – Jim Garrison Apr 04 '16 at 05:11
  • yes AbstractCollection belong to java.util. – jody abbot Apr 04 '16 at 05:13
  • 2
    You can get rid of this error by casting `units` to `PatchingChain`: `((PatchingChain) units).add(Jimple.v().newIdentityStmt(locThis, Jimple.v().newThisRef(RefType.v(c))))`. There: http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ051 is the description of the problem. – koto Apr 04 '16 at 10:09
  • @jodyabbot I posted more detailed answer, any corrections from you and others and edits are welcome, and if I'm not 100% correct I would appreciate pointing me what's wrong :) – koto Apr 04 '16 at 13:16

1 Answers1

2

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.

koto
  • 720
  • 2
  • 9
  • 29