diff --git a/.all-contributorsrc b/.all-contributorsrc
index e26a244d2f..8a891884e5 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -7883,6 +7883,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "VitaliiIevtushenko",
+ "name": "Vitalii Yevtushenko",
+ "avatar_url": "https://avatars.githubusercontent.com/u/11145125?v=4",
+ "profile": "https://github.com/VitaliiIevtushenko",
+ "contributions": [
+ "bug"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md
index b6ccbdf647..81690f91dc 100644
--- a/docs/pages/pmd/projectdocs/credits.md
+++ b/docs/pages/pmd/projectdocs/credits.md
@@ -820,299 +820,300 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Vincent Privat ๐ |
Vishhwas ๐ |
Vishv_Android ๐ |
+ Vitalii Yevtushenko ๐ |
Vitaly ๐ |
Vitaly Polonetsky ๐ |
- Vojtech Polivka ๐ |
+ Vojtech Polivka ๐ |
Vsevolod Zholobov ๐ |
Vyom Yadav ๐ป |
Wang Shidong ๐ |
Waqas Ahmed ๐ |
Wayne J. Earl ๐ |
Wchenghui ๐ |
- Wener ๐ป |
+ Wener ๐ป |
Will Winder ๐ |
Willem A. Hajenius ๐ป |
William Brockhus ๐ป ๐ |
Wilson Kurniawan ๐ |
Wim Deblauwe ๐ |
Woongsik Choi ๐ |
- XenoAmess ๐ป ๐ |
+ XenoAmess ๐ป ๐ |
Yang ๐ป |
YaroslavTER ๐ |
Yasar Shaikh ๐ป |
Young Chan ๐ป ๐ |
YuJin Kim ๐ |
Yuri Dolzhenko ๐ |
- Yurii Dubinka ๐ |
+ Yurii Dubinka ๐ |
Zoltan Farkas ๐ |
Zustin ๐ |
aaronhurst-google ๐ ๐ป |
alexmodis ๐ |
andreoss ๐ |
andrey81inmd ๐ป ๐ |
- anicoara ๐ |
+ anicoara ๐ |
arunprasathav ๐ |
asiercamara ๐ |
astillich-igniti ๐ป |
avesolovksyy ๐ |
avishvat ๐ |
avivmu ๐ |
- axelbarfod1 ๐ |
+ axelbarfod1 ๐ |
b-3-n ๐ |
balbhadra9 ๐ |
base23de ๐ |
bergander ๐ ๐ป |
berkam ๐ป ๐ |
breizh31 ๐ |
- caesarkim ๐ |
+ caesarkim ๐ |
carolyujing ๐ |
cbfiddle ๐ |
cesares-basilico ๐ |
chrite ๐ |
ciufudean ๐ |
cobratbq ๐ |
- coladict ๐ |
+ coladict ๐ |
cosmoJFH ๐ |
cristalp ๐ |
crunsk ๐ |
cwholmes ๐ |
cyberjj999 ๐ |
cyw3 ๐ ๐ |
- d1ss0nanz ๐ |
+ d1ss0nanz ๐ |
dague1 ๐ |
dalizi007 ๐ป |
danbrycefairsailcom ๐ |
dariansanity ๐ |
darrenmiliband ๐ |
davidburstrom ๐ |
- dbirkman-paloalto ๐ |
+ dbirkman-paloalto ๐ |
deepak-patra ๐ |
dependabot[bot] ๐ป ๐ |
dinesh150 ๐ |
diziaq ๐ |
dreaminpast123 ๐ |
duanyanan ๐ |
- dutt-sanjay ๐ |
+ dutt-sanjay ๐ |
duursma ๐ป |
dylanleung ๐ |
dzeigler ๐ |
eant60 ๐ |
ekkirala ๐ |
emersonmoura ๐ |
- emouty ๐ป ๐ |
+ emouty ๐ป ๐ |
eugenepugach ๐ |
fairy ๐ |
filiprafalowicz ๐ป |
flxbl-io ๐ต |
foxmason ๐ |
frankegabor ๐ |
- frankl ๐ |
+ frankl ๐ |
freafrea ๐ |
fsapatin ๐ |
gearsethenry ๐ |
gracia19 ๐ |
gudzpoz ๐ |
guo fei ๐ |
- gurmsc5 ๐ |
+ gurmsc5 ๐ |
gwilymatgearset ๐ป ๐ |
haigsn ๐ |
hemanshu070 ๐ |
henrik242 ๐ |
hongpuwu ๐ |
hvbtup ๐ป ๐ |
- igniti GmbH ๐ |
+ igniti GmbH ๐ |
ilovezfs ๐ |
imax-erik ๐ |
itaigilo ๐ |
jakivey32 ๐ |
jbennett2091 ๐ |
jcamerin ๐ |
- jkeener1 ๐ |
+ jkeener1 ๐ |
jmetertea ๐ |
johnra2 ๐ป |
johnzhao9 ๐ |
josemanuelrolon ๐ป ๐ |
kabroxiko ๐ป ๐ |
karthikaiyasamy ๐ |
- karwer ๐ |
+ karwer ๐ |
kaulonline ๐ |
kdaemonv ๐ |
kdebski85 ๐ ๐ป |
kenji21 ๐ป ๐ |
kfranic ๐ |
khalidkh ๐ |
- koalalam ๐ |
+ koalalam ๐ |
krzyk ๐ |
lasselindqvist ๐ |
lgemeinhardt ๐ |
lihuaib ๐ |
liqingjun123 ๐ |
lonelyma1021 ๐ |
- lpeddy ๐ |
+ lpeddy ๐ |
lujiefsi ๐ป |
lukelukes ๐ป |
lyriccoder ๐ |
marcelmore ๐ |
matchbox ๐ |
matthiaskraaz ๐ |
- meandonlyme ๐ |
+ meandonlyme ๐ |
mikesive ๐ |
milossesic ๐ |
mluckam ๐ป ๐ |
mohan-chinnappan-n ๐ป |
mriddell95 ๐ |
mrlzh ๐ |
- msloan ๐ |
+ msloan ๐ |
mucharlaravalika ๐ |
mvenneman ๐ |
nareshl119 ๐ |
nicolas-harraudeau-sonarsource ๐ |
noerremark ๐ |
novsirion ๐ |
- nwcm ๐ ๐ ๐ป |
+ nwcm ๐ ๐ ๐ป |
oggboy ๐ |
oinume ๐ |
orimarko ๐ป ๐ |
pablogomez2197 ๐ |
pacvz ๐ป |
pallavi agarwal ๐ |
- parksungrin ๐ |
+ parksungrin ๐ |
patpatpat123 ๐ |
patriksevallius ๐ |
pbrajesh1 ๐ |
phoenix384 ๐ |
piotrszymanski-sc ๐ป |
plan3d ๐ |
- poojasix ๐ |
+ poojasix ๐ |
prabhushrikant ๐ |
pujitha8783 ๐ |
r-r-a-j ๐ |
raghujayjunk ๐ |
rajeshveera ๐ |
rajeswarreddy88 ๐ |
- recdevs ๐ |
+ recdevs ๐ |
reudismam ๐ป ๐ |
rijkt ๐ |
rillig-tk ๐ |
rmohan20 ๐ป ๐ |
rnveach ๐ |
rxmicro ๐ |
- ryan-gustafson ๐ป ๐ |
+ ryan-gustafson ๐ป ๐ |
sabi0 ๐ |
scais ๐ |
schosin ๐ |
screamingfrog ๐ต |
sebbASF ๐ |
sergeygorbaty ๐ป |
- shilko2013 ๐ |
+ shilko2013 ๐ |
shiomiyan ๐ |
simeonKondr ๐ |
snajberk ๐ |
sniperrifle2004 ๐ |
snuyanzin ๐ ๐ป |
soloturn ๐ |
- soyodream ๐ |
+ soyodream ๐ |
sratz ๐ |
stonio ๐ |
sturton ๐ป ๐ |
sudharmohan ๐ |
suruchidawar ๐ |
svenfinitiv ๐ |
- szymanp23 ๐ ๐ป |
+ szymanp23 ๐ ๐ป |
tashiscool ๐ |
test-git-hook ๐ |
testation21 ๐ป ๐ |
thanosa ๐ |
tiandiyixian ๐ |
tobwoerk ๐ |
- tprouvot ๐ ๐ป |
+ tprouvot ๐ ๐ป |
trentchilders ๐ |
triandicAnt ๐ |
trishul14 ๐ |
tsui ๐ |
wangzitom12306 ๐ |
winhkey ๐ |
- witherspore ๐ |
+ witherspore ๐ |
wjljack ๐ |
wuchiuwong ๐ |
xingsong ๐ |
xioayuge ๐ |
xnYi9wRezm ๐ป ๐ |
xuanuy ๐ |
- xyf0921 ๐ |
+ xyf0921 ๐ |
yalechen-cyw3 ๐ |
yasuharu-sato ๐ |
zenglian ๐ |
zgrzyt93 ๐ป ๐ |
zh3ng ๐ |
zt_soft ๐ |
- ztt79 ๐ |
+ ztt79 ๐ |
zzzzfeng ๐ |
รrpรกd Magosรกnyi ๐ |
ไปป่ดตๆฐ ๐ |
diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md
index c1d07eb028..34fb78e0c0 100644
--- a/docs/pages/release_notes.md
+++ b/docs/pages/release_notes.md
@@ -27,6 +27,7 @@ This is a {{ site.pmd.release_type }} release.
* [#5329](https://github.com/pmd/pmd/issues/5329): \[java] Type inference issue with unknown method ref in call chain
* java-bestpractices
* [#5083](https://github.com/pmd/pmd/issues/5083): \[java] UnusedPrivateMethod false positive when method reference has no target type
+ * [#5318](https://github.com/pmd/pmd/issues/5318): \[java] PreserveStackTraceRule: false-positive on Pattern Matching with instanceof
* java-performance
* [#5314](https://github.com/pmd/pmd/issues/5314): \[java] InsufficientStringBufferDeclarationRule: Lack of handling for char type parameters
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java
index 03d0d9faea..229e8a5da0 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java
@@ -4,11 +4,10 @@
package net.sourceforge.pmd.lang.java.rule.bestpractices;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-import org.checkerframework.checker.nullness.qual.NonNull;
-
import net.sourceforge.pmd.lang.ast.NodeStream;
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr;
import net.sourceforge.pmd.lang.java.ast.ASTCastExpression;
@@ -17,13 +16,17 @@ import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTInfixExpression;
import net.sourceforge.pmd.lang.java.ast.ASTInitializer;
import net.sourceforge.pmd.lang.java.ast.ASTList;
import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
+import net.sourceforge.pmd.lang.java.ast.ASTPatternExpression;
import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTTypePattern;
import net.sourceforge.pmd.lang.java.ast.ASTVariableAccess;
import net.sourceforge.pmd.lang.java.ast.ASTVariableId;
+import net.sourceforge.pmd.lang.java.ast.BinaryOp;
import net.sourceforge.pmd.lang.java.ast.InvocationNode;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.ast.internal.JavaAstUtils;
@@ -64,7 +67,7 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule {
for (ASTThrowStatement throwStatement : catchStmt.getBody().descendants(ASTThrowStatement.class)) {
ASTExpression thrownExpr = throwStatement.getExpr();
- if (!exprConsumesException(exceptionParam, thrownExpr, true)) {
+ if (!exprConsumesException(Collections.singleton(exceptionParam), thrownExpr, true)) {
asCtx(data).addViolation(thrownExpr, exceptionParam.getName());
}
}
@@ -72,25 +75,39 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule {
return null;
}
- private boolean exprConsumesException(ASTVariableId exceptionParam, ASTExpression expr, boolean mayBeSelf) {
+ private boolean exprConsumesException(Set exceptionParams, ASTExpression expr, boolean mayBeSelf) {
if (expr instanceof ASTConstructorCall) {
// new Exception(e)
- return ctorConsumesException(exceptionParam, (ASTConstructorCall) expr);
+ return ctorConsumesException(exceptionParams, (ASTConstructorCall) expr);
} else if (expr instanceof ASTMethodCall) {
- return methodConsumesException(exceptionParam, (ASTMethodCall) expr);
+ return methodConsumesException(exceptionParams, (ASTMethodCall) expr);
} else if (expr instanceof ASTCastExpression) {
ASTExpression innermost = JavaAstUtils.peelCasts(expr);
- return exprConsumesException(exceptionParam, innermost, mayBeSelf);
+ return exprConsumesException(exceptionParams, innermost, mayBeSelf);
} else if (expr instanceof ASTConditionalExpression) {
ASTConditionalExpression ternary = (ASTConditionalExpression) expr;
- return exprConsumesException(exceptionParam, ternary.getThenBranch(), mayBeSelf)
- && exprConsumesException(exceptionParam, ternary.getElseBranch(), mayBeSelf);
+ Set possibleExceptionParams = new HashSet<>(exceptionParams);
+
+ // Peel out a type pattern variable in case this conditional is an instanceof pattern
+ NodeStream.of(ternary.getCondition())
+ .filterIs(ASTInfixExpression.class)
+ .filterMatching(ASTInfixExpression::getOperator, BinaryOp.INSTANCEOF)
+ .map(ASTInfixExpression::getRightOperand)
+ .filterIs(ASTPatternExpression.class)
+ .map(ASTPatternExpression::getPattern)
+ .filterIs(ASTTypePattern.class)
+ .map(ASTTypePattern::getVarId)
+ .firstOpt()
+ .ifPresent(possibleExceptionParams::add);
+
+ return exprConsumesException(possibleExceptionParams, ternary.getThenBranch(), mayBeSelf)
+ && exprConsumesException(possibleExceptionParams, ternary.getElseBranch(), mayBeSelf);
} else if (expr instanceof ASTVariableAccess) {
JVariableSymbol referencedSym = ((ASTVariableAccess) expr).getReferencedSym();
@@ -99,7 +116,7 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule {
}
ASTVariableId decl = referencedSym.tryGetNode();
- if (decl == exceptionParam) {
+ if (exceptionParams.contains(decl)) {
return mayBeSelf;
} else if (decl == null || decl.isFormalParameter() || decl.isField()) {
return false;
@@ -113,16 +130,16 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule {
// if any of the initializer and usages consumes the variable,
// answer true.
- if (exprConsumesException(exceptionParam, decl.getInitializer(), mayBeSelf)) {
+ if (exprConsumesException(exceptionParams, decl.getInitializer(), mayBeSelf)) {
return true;
}
for (ASTNamedReferenceExpr usage : decl.getLocalUsages()) {
- if (assignmentRhsConsumesException(exceptionParam, decl, usage)) {
+ if (assignmentRhsConsumesException(exceptionParams, decl, usage)) {
return true;
}
- if (JavaAstUtils.followingCallChain(usage).any(it -> consumesExceptionNonRecursive(exceptionParam, it))) {
+ if (JavaAstUtils.followingCallChain(usage).any(it -> consumesExceptionNonRecursive(exceptionParams, it))) {
return true;
}
}
@@ -134,7 +151,7 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule {
}
}
- private boolean assignmentRhsConsumesException(ASTVariableId exceptionParam, ASTVariableId lhsVariable, ASTNamedReferenceExpr usage) {
+ private boolean assignmentRhsConsumesException(Set exceptionParams, ASTVariableId lhsVariable, ASTNamedReferenceExpr usage) {
if (usage.getIndexInParent() == 0) {
ASTExpression assignmentRhs = JavaAstUtils.getOtherOperandIfInAssignmentExpr(usage);
boolean rhsIsSelfReferential =
@@ -142,25 +159,25 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule {
.descendantsOrSelf()
.filterIs(ASTVariableAccess.class)
.any(it -> JavaAstUtils.isReferenceToVar(it, lhsVariable.getSymbol()));
- return !rhsIsSelfReferential && exprConsumesException(exceptionParam, assignmentRhs, true);
+ return !rhsIsSelfReferential && exprConsumesException(exceptionParams, assignmentRhs, true);
}
return false;
}
- private boolean ctorConsumesException(ASTVariableId exceptionParam, ASTConstructorCall ctorCall) {
- return ctorCall.isAnonymousClass() && callsInitCauseInAnonInitializer(exceptionParam, ctorCall)
- || anArgumentConsumesException(exceptionParam, ctorCall);
+ private boolean ctorConsumesException(Set exceptionParams, ASTConstructorCall ctorCall) {
+ return ctorCall.isAnonymousClass() && callsInitCauseInAnonInitializer(exceptionParams, ctorCall)
+ || anArgumentConsumesException(exceptionParams, ctorCall);
}
- private boolean consumesExceptionNonRecursive(ASTVariableId exceptionParam, ASTExpression expr) {
+ private boolean consumesExceptionNonRecursive(Set exceptionParam, ASTExpression expr) {
if (expr instanceof ASTConstructorCall) {
return ctorConsumesException(exceptionParam, (ASTConstructorCall) expr);
}
return expr instanceof InvocationNode && anArgumentConsumesException(exceptionParam, (InvocationNode) expr);
}
- private boolean methodConsumesException(ASTVariableId exceptionParam, ASTMethodCall call) {
- if (anArgumentConsumesException(exceptionParam, call)) {
+ private boolean methodConsumesException(Set exceptionParams, ASTMethodCall call) {
+ if (anArgumentConsumesException(exceptionParams, call)) {
return true;
}
ASTExpression qualifier = call.getQualifier();
@@ -168,24 +185,24 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule {
return false;
}
boolean mayBeSelf = ALLOWED_GETTERS.anyMatch(call);
- return exprConsumesException(exceptionParam, qualifier, mayBeSelf);
+ return exprConsumesException(exceptionParams, qualifier, mayBeSelf);
}
- private boolean callsInitCauseInAnonInitializer(ASTVariableId exceptionParam, ASTConstructorCall ctorCall) {
+ private boolean callsInitCauseInAnonInitializer(Set exceptionParams, ASTConstructorCall ctorCall) {
return NodeStream.of(ctorCall.getAnonymousClassDeclaration())
.flatMap(ASTTypeDeclaration::getDeclarations)
.map(NodeStream.asInstanceOf(ASTFieldDeclaration.class, ASTInitializer.class))
.descendants().filterIs(ASTMethodCall.class)
- .any(it -> isInitCauseWithTargetInArg(exceptionParam, it));
+ .any(it -> isInitCauseWithTargetInArg(exceptionParams, it));
}
- private boolean isInitCauseWithTargetInArg(ASTVariableId exceptionSym, JavaNode expr) {
- return INIT_CAUSE.matchesCall(expr) && anArgumentConsumesException(exceptionSym, (ASTMethodCall) expr);
+ private boolean isInitCauseWithTargetInArg(Set exceptionParams, JavaNode expr) {
+ return INIT_CAUSE.matchesCall(expr) && anArgumentConsumesException(exceptionParams, (ASTMethodCall) expr);
}
- private boolean anArgumentConsumesException(@NonNull ASTVariableId exceptionParam, InvocationNode thrownExpr) {
+ private boolean anArgumentConsumesException(Set exceptionParams, InvocationNode thrownExpr) {
for (ASTExpression arg : ASTList.orEmptyStream(thrownExpr.getArguments())) {
- if (exprConsumesException(exceptionParam, arg, true)) {
+ if (exprConsumesException(exceptionParams, arg, true)) {
return true;
}
}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/PreserveStackTrace.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/PreserveStackTrace.xml
index 5292c61d64..637b6dffa6 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/PreserveStackTrace.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/PreserveStackTrace.xml
@@ -1168,4 +1168,35 @@ public class Foo {
]]>
+
+ #5318 [java] PreserveStackTraceRule: false-positive on Pattern Matching with instanceof
+ 0
+ formatExceptionHandler = e -> { e.printStackTrace(); };
+}
+]]>
+