CodeQL documentation

Type mismatch on container modification

ID: java/type-mismatch-modification
Kind: problem
Severity: error
Precision: very-high
Tags:
   - reliability
   - correctness
   - logic
Query suites:
   - java-security-and-quality.qls

Click to see the query in the CodeQL repository

The remove method of the Collection interface has an argument of type Object. Therefore, you can try to remove an object of any type from a collection, regardless of the collection’s element type. However, although you can call remove with an argument of a different type than that of the collection, it is unlikely that the collection actually contains an object of this type.

Similar considerations apply to other container modification methods, such as Map.remove, where the argument may also have type Object.

Recommendation

Ensure that you use the correct argument with a call to remove.

Example

In the following example, although the argument to contains is an integer, the code does not result in a type error because the argument to remove does not have to match the type of the elements of list. However, the argument is unlikely to be found and removed (and the body of the if statement is therefore not executed), so it is probably a typographical error: the argument should be enclosed in quotation marks.

void m(List<String> list) {
	if (list.remove(123)) {  // Call 'remove' with non-string argument (without quotation marks)
		// ...
	}
}

Note that you must take particular care when working with collections over boxed types, as illustrated in the following example. The first call to remove fails because you cannot compare two boxed numeric primitives of different types, in this case Short(1) (in set) and Integer(1) (the argument). Therefore, remove cannot find the item to remove. The second call to remove succeeds because you can compare Short(1) and Short(1). Therefore, remove can find the item to remove.

HashSet<Short> set = new HashSet<Short>();
short s = 1;
set.add(s);
// Following statement fails, because the argument is a literal int, which is auto-boxed 
// to an Integer
set.remove(1);
System.out.println(set); // Prints [1]
// Following statement succeeds, because the argument is a literal int that is cast to a short, 
// which is auto-boxed to a Short
set.remove((short)1);
System.out.println(set); // Prints []

References