Merge pull request #5192 from oowekyala:issue5190-npe-infer
This commit is contained in:
8 files changed
+120
-36
No files matched your search
@@ -7754,6 +7754,15 @@
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "vedantchokshi",
|
||||
"name": "Vedant Chokshi",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/22137048?v=4",
|
||||
"profile": "https://github.com/vedantchokshi",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -20,6 +20,8 @@ This is a {{ site.pmd.release_type }} release.
|
||||
(ApexCRUDViolation, CognitiveComplexity, OperationWithLimitsInLoop)
|
||||
* [#5163](https://github.com/pmd/pmd/issues/5163): \[apex] Parser error when using toLabel in SOSL query
|
||||
* [#5182](https://github.com/pmd/pmd/issues/5182): \[apex] Parser error when using GROUPING in a SOQL query
|
||||
* java
|
||||
* [#5190](https://github.com/pmd/pmd/issues/5190): \[java] NPE in type inference
|
||||
|
||||
### 🚨 API Changes
|
||||
|
||||
|
||||
@@ -798,6 +798,11 @@ public final class TypeSystem {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable JTypeMirror getAsSuper(@NonNull JClassSymbol symbol) {
|
||||
throw new UnsupportedOperationException("Null type cannot call asSuper, will return null always");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, P> T acceptVisitor(JTypeVisitor<T, P> visitor, P p) {
|
||||
return visitor.visitNullType(this, p);
|
||||
|
||||
+3
-1
@@ -816,7 +816,7 @@ public final class Infer {
|
||||
|
||||
private boolean commonSuperWithDiffParameterization(JTypeMirror t, JTypeMirror s) {
|
||||
JTypeMirror lubResult = ts.lub(listOf(t, s));
|
||||
if (lubResult.isBottom() || lubResult.isTop()) {
|
||||
if (lubResult.isBottom() || lubResult.isTop() || t.isBottom() || s.isBottom()) {
|
||||
return false;
|
||||
}
|
||||
for (JTypeMirror sup : asList(lubResult)) {
|
||||
@@ -824,6 +824,8 @@ public final class Infer {
|
||||
JClassSymbol sym = ((JClassType) sup).getSymbol();
|
||||
JTypeMirror asSuperOfT = t.getAsSuper(sym);
|
||||
JTypeMirror asSuperOfS = s.getAsSuper(sym);
|
||||
assert asSuperOfS != null : "s <: sup, because sup is part of the LUB of s";
|
||||
assert asSuperOfT != null : "t <: sup, because sup is part of the LUB of t";
|
||||
if (!asSuperOfS.equals(asSuperOfT)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+6
-1
@@ -97,7 +97,6 @@ public final class InferenceVar implements SubstVar {
|
||||
* Adds a new bound on this variable.
|
||||
*/
|
||||
public void addBound(BoundKind kind, JTypeMirror type) {
|
||||
this.hasNonTrivialBound = true;
|
||||
addBound(kind, type, false);
|
||||
}
|
||||
|
||||
@@ -115,9 +114,15 @@ public final class InferenceVar implements SubstVar {
|
||||
// may occur because of transitive propagation
|
||||
// alpha <: alpha is always true and not interesting
|
||||
return;
|
||||
} else if (kind == BoundKind.LOWER && type.isBottom()) {
|
||||
// null <: alpha is not interesting and may cause errors because of lub.
|
||||
return;
|
||||
}
|
||||
|
||||
if (boundSet.bounds.computeIfAbsent(kind, k -> new LinkedHashSet<>()).add(type)) {
|
||||
if (!isPrimaryBound) {
|
||||
this.hasNonTrivialBound = true;
|
||||
}
|
||||
ctx.onBoundAdded(this, kind, type, isPrimaryBound);
|
||||
}
|
||||
}
|
||||
|
||||
+16
@@ -74,6 +74,22 @@ class InferenceCtxUnitTests extends BaseTypeInferenceUnitTest {
|
||||
verify(log).boundAdded(ctx, v2, BoundKind.UPPER, listOfV1, false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testNullTypeCannotBeLowerBound() {
|
||||
TypeInferenceLogger log = spy(TypeInferenceLogger.noop());
|
||||
InferenceContext ctx = emptyCtx(log);
|
||||
|
||||
InferenceVar v1 = newIvar(ctx);
|
||||
|
||||
addSubtypeConstraint(ctx, ts.NULL_TYPE, v1);
|
||||
|
||||
|
||||
assertThat(v1, hasBoundsExactly(upper(ts.OBJECT)));
|
||||
|
||||
verify(log, never()).boundAdded(ctx, v1, BoundKind.LOWER, ts.NULL_TYPE, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEqBoundWithGenerics() {
|
||||
TypeInferenceLogger log = spy(TypeInferenceLogger.noop());
|
||||
|
||||
+44
@@ -454,4 +454,48 @@ public class BadIntersection {
|
||||
info.methodType.formalParameters[0] shouldBe optOutEnum
|
||||
}
|
||||
}
|
||||
parserTest("#5190 NPE in type inf") {
|
||||
val (acu, spy) = parser.parseWithTypeInferenceSpy(
|
||||
"""
|
||||
import java.util.Iterator;
|
||||
interface Optional<V> {
|
||||
static <T> Optional<T> ofNullable(T t) {}
|
||||
}
|
||||
interface Map<K,V> {}
|
||||
interface List<V> extends Iterable<V> {}
|
||||
interface AttributeValue{}
|
||||
|
||||
class Main {
|
||||
|
||||
private Optional<Map<String, AttributeValue>> loadForKey(final String key) {
|
||||
return Optional.ofNullable(
|
||||
getOnlyElement(queryForKey(key), null)
|
||||
);
|
||||
}
|
||||
|
||||
private List<Map<String, AttributeValue>> queryForKey(final String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> T getOnlyElement(final Iterable<? extends T> iterable, final T defaultValue) {
|
||||
return getOnlyElement(iterable.iterator(), defaultValue);
|
||||
}
|
||||
|
||||
public static <T> T getOnlyElement(final Iterator<? extends T> iterator, final T defaultValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val (_, _, _) = acu.declaredTypeSignatures()
|
||||
val (ofNullable) = acu.methodDeclarations().toList { it.genericSignature }
|
||||
|
||||
spy.shouldBeOk {
|
||||
val info = acu.firstMethodCall().overloadSelectionInfo
|
||||
info::isFailed shouldBe false
|
||||
info.methodType shouldBeSomeInstantiationOf ofNullable
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user