|
Project
|
IntelliJ IDEA
|
|
Priority
|
Normal |
|
Type
|
Bug |
|
Fix versions
|
No Fix versions |
|
State
|
Duplicate |
|
Assignee
|
Alexey Kudravtsev |
|
Subsystem
|
Code Analysis. Inspection |
|
Affected versions
|
No Affected versions |
|
Fixed in build
|
No Fixed in build |
Map<Integer,String> map = getMap();
Number n = new Integer(3);
if (map.containsKey(n)) {
...
}
That is to say, no warning should be emitted if the type given is a supertype of the desired type. I suggest that this be the default behaviour, perhaps with a checkbox to give the current behaviour if desired.
We have lots of code like this:
public boolean accept(Map<Integer,String> map, Object key) { return map.containsKey(key); }Here I don't want Idea to warn me that the runtime type of "key" might not give any results: because the runtime type might be Integer. And I don't want to cast to Integer because I want my code to return false if a Double is passed in.On the other hand, I do want to see a big warning in this case:
public boolean accept(Map<Integer,String> map, String key) { return map.containsKey(key); }Integer i = Integer.valueOf (0); Object o = i; String s = "Test"; List<Integer> l = new ArrayList<Integer> (); // No warning - good if (o.equals (i)) { } if (i.equals (o)) { } // Warning "Suspicious call to List.contains()" - not good if (l.contains (o)) { } // Warning "equals between objects of inconvertible types" - good if (s.equals (i)) { } if (i.equals (s)) { } // Warning "Suspicious call to List.contains()" - good if (l.contains (s)) { }Doesn't that feel a little bit wrong to you? Surely the various inspections of this type (that is, "Suspicious 'Collections.toArray()' call", "Suspicious 'System.arraycopy()' call", "Suspicious collections method calls" and "'equals()' between objects of inconvertible types" should be internally coherent (and not just the ones that are "Powered by InspectionGadgets") ;)dataflow analysis to make sure that the variable n is only ever assigned to an Integer.
Why do you not have Map<Number,String> or else if you want Map<Integer,String>
then why don't you have
Map<Integer,String> map = getMap(); Integer n = new Integer(3); if (map.containsKey(n)) { ... }I can't really see a nice general solution to this. For example, you suggest transforming this
public boolean accept(Map<Integer,String> map, Object key) { return map.containsKey(key); }into this
public boolean accept(Map<Integer,String> map, Object key) { if (key instanceof Integer) // Whoops, I get an unnecessary cast warning here :-/ return map.containsKey((Integer) key); else return false; }or maybe thispublic boolean accept (Map<Integer, String> map, Object key) { if (key instanceof Integer) { Integer ikey = (Integer) key; return map.containsKey (ikey); } else { return false; } }which are both kind of ugly and much more verbose than the original; and it doesn't work with generics, for example, in this contrived examplepublic boolean accept(Map<Class<Integer>,String> map, Class<?> key) { if (key instanceof Class<Integer>) return map.containsKey((Integer) key); else return false; }