@@ -17,14 +17,15 @@ most of generated branches would be `NPE` branches, while useful paths could be
17
17
18
18
Beyond that, in many cases the ` null ` value of a field can't be generated using the public API
19
19
of the class. This is particularly true for final fields, especially in system classes.
20
- Automatically generated tests assign ` null ` values to fields in questions using reflection,
20
+ it is also often true for non-public fields from standard library and third-party libraries (even setters often do not
21
+ allow ` null ` values). Automatically generated tests assign ` null ` values to fields in questions using reflection,
21
22
but these tests may be uninformative as the corresponding ` NPE ` branches would never occur
22
23
in the real code that limits itself to the public API.
23
24
24
25
## The solution
25
26
26
27
To discard irrelevant ` NPE ` branches, we can speculatively mark fields we as non-nullable even they
27
- do not have an explicit ` @NotNull ` annotation. In particular, we can use this approach to final
28
+ do not have an explicit ` @NotNull ` annotation. In particular, we can use this approach to final and non-public
28
29
fields of system classes, as they are usually correctly initialized and are not equal ` null ` .
29
30
30
31
At the same time, we can't always add the "not null" hard constraint for the field: it would break
@@ -38,18 +39,18 @@ no way to check whether the address corresponds to a final field, as the corresp
38
39
of the global graph would refer to a local variable. The only place where we have the complete
39
40
information about the field is this method.
40
41
41
- We use the following approach. If the field is final and belongs to a system class,
42
- we mark it as a speculatively non-nullable in the memory
42
+ We use the following approach. If the field belongs to a library class (according to ` soot.SootClass.isLibraryClass ` )
43
+ and is final or non-public, we mark it as a speculatively non-nullable in the memory
43
44
(see ` org.utbot.engine.Memory.speculativelyNotNullAddresses ` ). During the NPE check
44
45
we will add the ` !isSpeculativelyNotNull(addr(field)) ` constraint
45
46
to the ` NPE ` branch together with the usual ` addr(field) == null ` constraint.
46
47
47
- For final fields, these two conditions can't be satisfied at the same time, as we speculatively
48
- mark final fields as non-nullable. As a result, the NPE branch would be discarded. If a field
49
- is not final, the condition is satisfiable, so the NPE branch would stay alive.
48
+ For final/non-public fields, these two conditions can't be satisfied at the same time, as we speculatively
49
+ mark such fields as non-nullable. As a result, the NPE branch would be discarded. If a field
50
+ is public or not final, the condition is satisfiable, so the NPE branch would stay alive.
50
51
51
- We limit this approach to the system classes only, because it is hard to speculatively assume
52
- something about non-nullability of final fields in the user code.
52
+ We limit this approach to the library classes only, because it is hard to speculatively assume
53
+ something about non-nullability of final/non-public fields in the user code.
53
54
54
55
The same approach can be extended for other cases where we want to speculatively consider some
55
56
fields as non-nullable to prevent ` NPE ` branch generation.
0 commit comments