Skip to content

Commit 15c817a

Browse files
Add support for local variables for arrays. (#1146)
I added changes to support local variables specifically for arrays. Added a new class `LocalVariableLocation` that will contain location details in the scenario when the target is a local variable. --------- Co-authored-by: Manu Sridharan <msridhar@gmail.com>
1 parent 4805b0b commit 15c817a

File tree

3 files changed

+237
-0
lines changed

3 files changed

+237
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2024 Uber Technologies, Inc.
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
* THE SOFTWARE.
21+
*/
22+
23+
package com.uber.nullaway.fixserialization.location;
24+
25+
import com.sun.tools.javac.code.Symbol;
26+
import com.uber.nullaway.fixserialization.Serializer;
27+
import com.uber.nullaway.fixserialization.adapters.SerializationAdapter;
28+
import javax.lang.model.element.ElementKind;
29+
30+
/** subtype of {@link AbstractSymbolLocation} targeting local variables. */
31+
public class LocalVariableLocation extends AbstractSymbolLocation {
32+
33+
/** Symbol of the targeted local variable. */
34+
private final Symbol.VarSymbol localVariableSymbol;
35+
36+
public LocalVariableLocation(Symbol target) {
37+
super(ElementKind.LOCAL_VARIABLE, target);
38+
this.localVariableSymbol = (Symbol.VarSymbol) target;
39+
}
40+
41+
@Override
42+
public String tabSeparatedToString(SerializationAdapter adapter) {
43+
Symbol.MethodSymbol enclosingMethod = (Symbol.MethodSymbol) localVariableSymbol.owner;
44+
return String.join(
45+
"\t",
46+
type.toString(),
47+
Serializer.serializeSymbol(enclosingClass, adapter),
48+
Serializer.serializeSymbol(enclosingMethod, adapter),
49+
Serializer.serializeSymbol(localVariableSymbol, adapter),
50+
"null",
51+
path != null ? path.toString() : "null");
52+
}
53+
}

nullaway/src/main/java/com/uber/nullaway/fixserialization/location/SymbolLocation.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,21 @@ static SymbolLocation createLocationFromSymbol(Symbol target) {
6262
return new MethodLocation(target);
6363
case FIELD:
6464
return new FieldLocation(target);
65+
// The case where a local variable is declared inside a lambda expression is currently not
66+
// handled. This will require changes to how LocalVariableLocation is created.
67+
// An example of the case :
68+
// void shadowInLambda() {
69+
// Object[] l = new Object[12];
70+
// a.exec(
71+
// () -> {
72+
// Object[] l = new Object[10];
73+
// // BUG: Diagnostic contains: Writing @Nullable expression into array with
74+
// @NonNull contents.
75+
// l[0] = null;
76+
// });
77+
// }
78+
case LOCAL_VARIABLE:
79+
return new LocalVariableLocation(target);
6580
default:
6681
throw new IllegalArgumentException("Cannot locate node: " + target);
6782
}

nullaway/src/test/java/com/uber/nullaway/SerializationTest.java

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2168,4 +2168,173 @@ public void errorSerializationTestArrayComponentNull() {
21682168
.setOutputFileNameAndHeader(ERROR_FILE_NAME, ERROR_FILE_HEADER)
21692169
.doTest();
21702170
}
2171+
2172+
@Test
2173+
public void errorSerializationTestArrayComponentNullLocalVariable() {
2174+
SerializationTestHelper<ErrorDisplay> tester = new SerializationTestHelper<>(root);
2175+
tester
2176+
.setArgs(
2177+
Arrays.asList(
2178+
"-d",
2179+
temporaryFolder.getRoot().getAbsolutePath(),
2180+
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
2181+
"-XepOpt:NullAway:SerializeFixMetadata=true",
2182+
"-XepOpt:NullAway:JSpecifyMode=true",
2183+
"-XepOpt:NullAway:FixSerializationConfigPath=" + configPath))
2184+
.addSourceLines(
2185+
"com/uber/A.java",
2186+
"package com.uber;",
2187+
"import org.jspecify.annotations.Nullable;",
2188+
"public class A {",
2189+
" void spin() {",
2190+
" String [] foo = {\"SomeRandomWords\"};",
2191+
" // BUG: Diagnostic contains: Writing @Nullable expression into array with @NonNull contents.",
2192+
" foo[1] = null;",
2193+
" }",
2194+
"}")
2195+
.setExpectedOutputs(
2196+
new ErrorDisplay(
2197+
"ASSIGN_NULLABLE_TO_NONNULL_ARRAY",
2198+
"Writing @Nullable expression into array with @NonNull contents.",
2199+
"com.uber.A",
2200+
"spin()",
2201+
235,
2202+
"com/uber/A.java",
2203+
"LOCAL_VARIABLE",
2204+
"com.uber.A",
2205+
"spin()",
2206+
"foo",
2207+
"null",
2208+
"com/uber/A.java"))
2209+
.setFactory(errorDisplayFactory)
2210+
.setOutputFileNameAndHeader(ERROR_FILE_NAME, ERROR_FILE_HEADER)
2211+
.doTest();
2212+
}
2213+
2214+
@Test
2215+
public void errorSerializationTestArrayComponentNullLocalVariableLambda() {
2216+
SerializationTestHelper<ErrorDisplay> tester = new SerializationTestHelper<>(root);
2217+
tester
2218+
.setArgs(
2219+
Arrays.asList(
2220+
"-d",
2221+
temporaryFolder.getRoot().getAbsolutePath(),
2222+
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
2223+
"-XepOpt:NullAway:SerializeFixMetadata=true",
2224+
"-XepOpt:NullAway:JSpecifyMode=true",
2225+
"-XepOpt:NullAway:FixSerializationConfigPath=" + configPath))
2226+
.addSourceLines(
2227+
"com/uber/A.java",
2228+
"package com.uber;",
2229+
"import org.jspecify.annotations.Nullable;",
2230+
"public class A {",
2231+
" A a = new A();",
2232+
" public void f() {",
2233+
" final Object[] l = new Object[10];",
2234+
" class B {",
2235+
" void b() {",
2236+
" // BUG: Diagnostic contains: Writing @Nullable expression into array with @NonNull contents.",
2237+
" l[0] = null;",
2238+
" }",
2239+
" void shadowInLambda() {",
2240+
" a.exec(",
2241+
" () -> {",
2242+
" Object[] l = new Object[10];",
2243+
" // BUG: Diagnostic contains: Writing @Nullable expression into array with @NonNull contents.",
2244+
" l[0] = null;",
2245+
" });",
2246+
" }",
2247+
" void useFieldInLambda(A a) {",
2248+
" Object[] l = new Object[10];",
2249+
" a.exec(",
2250+
" () -> {",
2251+
" // BUG: Diagnostic contains: Writing @Nullable expression into array with @NonNull contents.",
2252+
" l[0] = null;",
2253+
" });",
2254+
" }",
2255+
" }",
2256+
" a.exec(new Runnable() {",
2257+
" @Override",
2258+
" public void run() {",
2259+
" // BUG: Diagnostic contains: Writing @Nullable expression into array with @NonNull contents.",
2260+
" l[0] = null;",
2261+
" }",
2262+
" });",
2263+
" // BUG: Diagnostic contains: Writing @Nullable expression into array with @NonNull contents.",
2264+
" l[0] = null;",
2265+
" }",
2266+
" void exec(Runnable runnable) {",
2267+
" runnable.run();",
2268+
" }",
2269+
"}")
2270+
.setExpectedOutputs(
2271+
new ErrorDisplay(
2272+
"ASSIGN_NULLABLE_TO_NONNULL_ARRAY",
2273+
"Writing @Nullable expression into array with @NonNull contents.",
2274+
"com.uber.A$1B",
2275+
"b()",
2276+
293,
2277+
"com/uber/A.java",
2278+
"LOCAL_VARIABLE",
2279+
"com.uber.A",
2280+
"f()",
2281+
"l",
2282+
"null",
2283+
"com/uber/A.java"),
2284+
new ErrorDisplay(
2285+
"ASSIGN_NULLABLE_TO_NONNULL_ARRAY",
2286+
"Writing @Nullable expression into array with @NonNull contents.",
2287+
"com.uber.A$1B",
2288+
"shadowInLambda()",
2289+
560,
2290+
"com/uber/A.java",
2291+
"LOCAL_VARIABLE",
2292+
"com.uber.A$1B",
2293+
"shadowInLambda()",
2294+
"l",
2295+
"null",
2296+
"com/uber/A.java"),
2297+
new ErrorDisplay(
2298+
"ASSIGN_NULLABLE_TO_NONNULL_ARRAY",
2299+
"Writing @Nullable expression into array with @NonNull contents.",
2300+
"com.uber.A$1B",
2301+
"useFieldInLambda(com.uber.A)",
2302+
842,
2303+
"com/uber/A.java",
2304+
"LOCAL_VARIABLE",
2305+
"com.uber.A$1B",
2306+
"useFieldInLambda(com.uber.A)",
2307+
"l",
2308+
"null",
2309+
"com/uber/A.java"),
2310+
new ErrorDisplay(
2311+
"ASSIGN_NULLABLE_TO_NONNULL_ARRAY",
2312+
"Writing @Nullable expression into array with @NonNull contents.",
2313+
"com.uber.A$1",
2314+
"run()",
2315+
1068,
2316+
"com/uber/A.java",
2317+
"LOCAL_VARIABLE",
2318+
"com.uber.A",
2319+
"f()",
2320+
"l",
2321+
"null",
2322+
"com/uber/A.java"),
2323+
new ErrorDisplay(
2324+
"ASSIGN_NULLABLE_TO_NONNULL_ARRAY",
2325+
"Writing @Nullable expression into array with @NonNull contents.",
2326+
"com.uber.A",
2327+
"f()",
2328+
1198,
2329+
"com/uber/A.java",
2330+
"LOCAL_VARIABLE",
2331+
"com.uber.A",
2332+
"f()",
2333+
"l",
2334+
"null",
2335+
"com/uber/A.java"))
2336+
.setFactory(errorDisplayFactory)
2337+
.setOutputFileNameAndHeader(ERROR_FILE_NAME, ERROR_FILE_HEADER)
2338+
.doTest();
2339+
}
21712340
}

0 commit comments

Comments
 (0)