@@ -88,7 +88,11 @@ module Collection {
8888 }
8989 }
9090
91- /** A call where a collection of constants of class `collectionClass` can be in */
91+ /**
92+ * A call with a collection of class `collectionClass` as argument `arg` (or
93+ * as qualifier, if `arg` is -1) which will not add any new non-constant
94+ * elements to it.
95+ */
9296 abstract class SafeCall extends Call {
9397 int arg ;
9498 CollectionClass collectionClass ;
@@ -120,7 +124,7 @@ module Collection {
120124 or
121125 collectionClass = "Set" and
122126 t .hasQualifiedName ( "java.util" , "Set" ) and
123- m .getName ( ) = [ "add" ] and
127+ m .getName ( ) = "add" and
124128 this .getArgument ( 0 ) .isCompileTimeConstant ( )
125129 )
126130 }
@@ -140,40 +144,19 @@ module Collection {
140144 }
141145 }
142146
143- // Expr foo(Expr q, string s) {
144- // q = any(CollectionContainsCall ccc).getQualifier() and
145- // result = getALocalExprFlowRoot(q) and
146- // (
147- // if exists(Field f | DataFlow::localExprFlow(f.getAnAccess(), result))
148- // then
149- // exists(Field f | DataFlow::localExprFlow(f.getAnAccess(), result) |
150- // f.isStatic() and
151- // f.isFinal() and
152- // s = "static final field"
153- // or
154- // not (
155- // f.isStatic() and
156- // f.isFinal()
157- // ) and
158- // s = "field read"
159- // )
160- // else
161- // if result = any(MethodCall mc)
162- // then s = "method call"
163- // else
164- // if result = any(ConstructorCall cc)
165- // then s = "constructor call"
166- // else
167- // if result = any(Call cc)
168- // then s = "other call"
169- // else s = "something else"
170- // )
171- // }
172- Expr getALocalExprFlowRoot ( Expr e ) {
147+ /**
148+ * Gets an `Expr` which locally flows to `e` and which nothing locally flows
149+ * to.
150+ */
151+ private Expr getALocalExprFlowRoot ( Expr e ) {
173152 DataFlow:: localExprFlow ( result , e ) and
174153 not exists ( Expr e2 | e2 != result | DataFlow:: localExprFlow ( e2 , result ) )
175154 }
176155
156+ /**
157+ * Holds if `e` was not involved in any calls which might add non-constant
158+ * elements.
159+ */
177160 private predicate noUnsafeCalls ( Expr e ) {
178161 forall ( MethodCall mc , int arg , Expr x |
179162 DataFlow:: localExprFlow ( x , e ) and
@@ -187,20 +170,19 @@ module Collection {
187170 )
188171 }
189172
190- private predicate collectionOfConstantsFlowsTo ( Expr e ) {
173+ /** Holds if `e` is a collection of constants. */
174+ private predicate isCollectionOfConstants ( Expr e ) {
191175 forex ( Expr r | r = getALocalExprFlowRoot ( e ) |
192176 r instanceof CollectionOfConstants
193177 or
194178 // Access a static final field to get an immutable list of constants.
195179 exists ( Field f | r = f .getAnAccess ( ) |
196180 f .isStatic ( ) and
197181 f .isFinal ( ) and
198- forall ( Expr v | v = f .getInitializer ( ) |
199- v = any ( CollectionOfConstants loc | loc .isImmutable ( ) )
200- ) and
182+ forall ( Expr v | v = f .getInitializer ( ) | v instanceof ImmutableCollectionOfConstants ) and
201183 forall ( Expr fieldSource | fieldSource = f .getAnAccess ( ) .( FieldWrite ) .getASource ( ) |
202184 forall ( Expr root | root = getALocalExprFlowRoot ( fieldSource ) |
203- root . ( CollectionOfConstants ) . isImmutable ( )
185+ root instanceof ImmutableCollectionOfConstants
204186 ) and
205187 noUnsafeCalls ( fieldSource )
206188 )
@@ -210,36 +192,40 @@ module Collection {
210192 }
211193
212194 /**
213- * An invocation of `java.util.List.contains` where the qualifier contains only
214- * compile-time constants.
195+ * An invocation of `java.util.List.contains` or `java.util.Set. contains`
196+ * where the qualifier contains only compile-time constants.
215197 */
216198 private class CollectionOfConstantsContains extends ListOfConstantsComparison {
217199 CollectionOfConstantsContains ( ) {
218200 exists ( CollectionContainsCall mc |
219201 this = mc and
220202 e = mc .getArgument ( 0 ) and
221203 outcome = true and
222- collectionOfConstantsFlowsTo ( mc .getQualifier ( ) )
204+ isCollectionOfConstants ( mc .getQualifier ( ) )
223205 )
224206 }
225207 }
226208
227209 /**
228- * An instance of `java.util.List` which contains only compile-time constants.
210+ * An instance of `java.util.List` or `java.util.Set` which contains only
211+ * compile-time constants.
229212 */
230213 abstract class CollectionOfConstants extends Call {
231214 CollectionClass collectionClass ;
232215
233216 /** Gets whether the collection is a "List" or a "Set". */
234217 CollectionClass getCollectionClass ( ) { result = collectionClass }
235-
236- /** Holds if this list of constants is immutable. */
237- abstract predicate isImmutable ( ) ;
238218 }
239219
220+ /**
221+ * An immutable instance of `java.util.List` or `java.util.Set` which
222+ * contains only compile-time constants.
223+ */
224+ abstract class ImmutableCollectionOfConstants extends CollectionOfConstants { }
225+
240226 /**
241227 * A invocation of a constructor of a type that extends `java.util.List` or
242- * `java.util.Set` which constructs an empty mutable list.
228+ * `java.util.Set` which constructs an empty mutable list/set .
243229 */
244230 private class CollectionOfConstantsEmptyConstructor extends ClassInstanceExpr ,
245231 CollectionOfConstants
@@ -260,13 +246,11 @@ module Collection {
260246 c .getParameter ( 0 ) .getType ( ) .( PrimitiveType ) .hasName ( "float" )
261247 )
262248 }
263-
264- override predicate isImmutable ( ) { none ( ) }
265249 }
266250
267251 /**
268252 * A invocation of a constructor of a type that extends `java.util.List` or
269- * `java.util.Set` which constructs a non-empty mutable list.
253+ * `java.util.Set` which constructs a non-empty mutable list/set .
270254 */
271255 private class CollectionOfConstantsNonEmptyConstructor extends ClassInstanceExpr ,
272256 CollectionOfConstants
@@ -284,11 +268,9 @@ module Collection {
284268 .getASourceSupertype * ( )
285269 .hasQualifiedName ( "java.util" , "Collection" )
286270 ) and
287- // Any collection can be used in the non-empty constructor.
288- collectionOfConstantsFlowsTo ( this .getArgument ( 0 ) )
271+ // Note that any collection can be used in the non-empty constructor.
272+ isCollectionOfConstants ( this .getArgument ( 0 ) )
289273 }
290-
291- override predicate isImmutable ( ) { none ( ) }
292274 }
293275
294276 /**
@@ -306,15 +288,15 @@ module Collection {
306288 ) and
307289 methodCallHasConstantArguments ( this )
308290 }
309-
310- override predicate isImmutable ( ) { none ( ) }
311291 }
312292
313293 /**
314- * An invocation of `java.util.List.of` which constructs an immutable list
315- * which contains only compile-time constants.
294+ * An invocation of `java.util.List.of` or `java.util.Set.of` which
295+ * constructs an immutable list/set which contains only compile-time constants.
316296 */
317- private class CollectionOfConstantsCreatedWithOf extends MethodCall , CollectionOfConstants {
297+ private class CollectionOfConstantsCreatedWithOf extends MethodCall ,
298+ ImmutableCollectionOfConstants
299+ {
318300 CollectionOfConstantsCreatedWithOf ( ) {
319301 exists ( Method m | this .getMethod ( ) = m |
320302 m .hasName ( "of" ) and
@@ -325,8 +307,6 @@ module Collection {
325307 ) and
326308 methodCallHasConstantArguments ( this )
327309 }
328-
329- override predicate isImmutable ( ) { any ( ) }
330310 }
331311
332312 /**
@@ -335,7 +315,7 @@ module Collection {
335315 * list/set which contains only compile-time constants.
336316 */
337317 private class CollectionOfConstantsCreatedWithCollectionsUnmodifiableList extends MethodCall ,
338- CollectionOfConstants
318+ ImmutableCollectionOfConstants
339319 {
340320 CollectionOfConstantsCreatedWithCollectionsUnmodifiableList ( ) {
341321 exists ( Method m |
@@ -346,10 +326,8 @@ module Collection {
346326 .hasQualifiedName ( "java.util" , "Collections" ) and
347327 this .getMethod ( ) = m
348328 |
349- collectionOfConstantsFlowsTo ( this .getArgument ( 0 ) )
329+ isCollectionOfConstants ( this .getArgument ( 0 ) )
350330 )
351331 }
352-
353- override predicate isImmutable ( ) { any ( ) }
354332 }
355333}
0 commit comments