[java-inspections] IDEA-266365. Added support record deconstruction

GitOrigin-RevId: 13f50bf376221046e2903de076ee4f8d143d5ff5
This commit is contained in:
Mikhail Pyltsin
2022-12-28 10:35:23 +00:00
committed by intellij-monorepo-bot
parent fda015b92e
commit e60923ac0b
4 changed files with 115 additions and 7 deletions
@@ -337,9 +337,12 @@ public final class JavaPsiPatternUtil {
}
public static @Nullable PsiType getDeconstructedImplicitPatternVariableType(@NotNull PsiPatternVariable parameter) {
PsiRecordComponent recordComponent = getRecordComponentForPattern(parameter.getPattern());
return getDeconstructedImplicitPatternType(parameter.getPattern());
}
public static @Nullable PsiType getDeconstructedImplicitPatternType(@NotNull PsiPattern pattern) {
PsiRecordComponent recordComponent = getRecordComponentForPattern(pattern);
if (recordComponent != null) {
PsiTypeTestPattern pattern = (PsiTypeTestPattern)parameter.getParent();
PsiDeconstructionList deconstructionList = ObjectUtils.tryCast(pattern.getParent(), PsiDeconstructionList.class);
if (deconstructionList == null) return null;
PsiDeconstructionPattern deconstructionPattern = (PsiDeconstructionPattern)deconstructionList.getParent();
@@ -21,6 +21,7 @@ import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.JavaPsiPatternUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
@@ -180,7 +181,31 @@ public class TypeParameterExtendsFinalClassInspection extends BaseInspection imp
private static boolean isWildcardRequired(PsiTypeElement typeElement) {
final PsiElement ancestor = PsiTreeUtil.skipParentsOfType(
typeElement, PsiTypeElement.class, PsiJavaCodeReferenceElement.class, PsiReferenceParameterList.class);
if (ancestor instanceof PsiParameter) {
if (ancestor instanceof PsiDeconstructionPattern deconstructionPattern) {
PsiForeachStatement parentForEach = PsiTreeUtil.getParentOfType(deconstructionPattern, PsiForeachStatement.class);
if (parentForEach == null) {
return false;
}
if (!PsiTreeUtil.isAncestor(parentForEach.getIterationDeclaration(), deconstructionPattern, false)) {
return false;
}
if (ancestor.getParent() instanceof PsiForeachStatement foreachStatement) {
PsiExpression iteratedValue = foreachStatement.getIteratedValue();
if (iteratedValue == null) {
return false;
}
return isWildcardRequired(typeElement, deconstructionPattern.getTypeElement(),
JavaGenericsUtil.getCollectionItemType(iteratedValue));
}
else if (deconstructionPattern.getParent() instanceof PsiDeconstructionList) {
PsiType type = JavaPsiPatternUtil.getDeconstructedImplicitPatternType(deconstructionPattern);
if (type == null) {
return false;
}
return isWildcardRequired(typeElement, deconstructionPattern.getTypeElement(), type);
}
}
else if (ancestor instanceof PsiParameter) {
final PsiParameter parameter = (PsiParameter)ancestor;
final PsiElement scope = parameter.getDeclarationScope();
if (scope instanceof PsiMethod method) {
@@ -196,10 +221,20 @@ public class TypeParameterExtendsFinalClassInspection extends BaseInspection imp
if (iteratedValue == null) {
return true; // incomplete code
}
final PsiParameter iterationParameter = foreachStatement.getIterationParameter();
final PsiTypeElement foreachTypeElement = iterationParameter.getTypeElement();
assert foreachTypeElement != null;
return isWildcardRequired(typeElement, foreachTypeElement, JavaGenericsUtil.getCollectionItemType(iteratedValue));
PsiForeachDeclarationElement declaration = foreachStatement.getIterationDeclaration();
//patterns check before
if (declaration instanceof PsiParameter iterationParameter) {
final PsiTypeElement foreachTypeElement = iterationParameter.getTypeElement();
assert foreachTypeElement != null;
return isWildcardRequired(typeElement, foreachTypeElement, JavaGenericsUtil.getCollectionItemType(iteratedValue));
}
else if (ancestor instanceof PsiPatternVariable patternVariable) {
PsiType type = JavaPsiPatternUtil.getDeconstructedImplicitPatternVariableType(patternVariable);
if (type == null) {
return true;
}
return isWildcardRequired(typeElement, patternVariable.getTypeElement(), type);
}
}
}
else if (ancestor instanceof PsiLocalVariable localVariable) {
@@ -0,0 +1,45 @@
package com.siyeh.igtest.inheritance.type_parameter_extends_final_class;
import java.util.*;
public class TypeParameterExtendsFinalClassJava20{
public static void testGenericWithWildcard(List<RecordWithGeneric<<warning descr="Wildcard type argument '?' extends 'final' class 'String'">?</warning> extends String>> list){
for (RecordWithGeneric<? extends String>(var x): list) {
System.out.println(x);
}
}
public static void testGenericWithoutWildcard(List<RecordWithGeneric<String>> list){
for (RecordWithGeneric<<warning descr="Wildcard type argument '?' extends 'final' class 'String'">?</warning> extends String>(var x): list) {
System.out.println(x);
}
}
public static void testRecordWithWildcard(){
List<RecordWithWildcard> lists2 = List.of(new RecordWithWildcard(List.of("1"), "2"));
for (RecordWithWildcard(List<? extends String> x, var y ) : lists2) {
System.out.println(x);
}
}
public static void testRecordWithoutWildcard(){
List<RecordWithoutWildcard> lists3 = List.of(new RecordWithoutWildcard(List.of("1"), "2"));
for (RecordWithoutWildcard(List<<warning descr="Wildcard type argument '?' extends 'final' class 'String'">?</warning> extends String> x, var y ) : lists3) {
System.out.println(x);
}
}
}
record RecordWithWildcard(List<<warning descr="Wildcard type argument '?' extends 'final' class 'String'">?</warning> extends String> x, String y){
}
record RecordWithoutWildcard(List<String> x, String y){
}
record RecordWithGeneric<T>(T x){
}
@@ -0,0 +1,25 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.siyeh.ig.inheritance;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.intellij.testFramework.LightProjectDescriptor;
import com.siyeh.ig.LightJavaInspectionTestCase;
import org.jetbrains.annotations.NotNull;
public class TypeParameterExtendsFinalClassJava20InspectionTest extends LightJavaInspectionTestCase {
public void testTypeParameterExtendsFinalClassJava20() {
doTest();
}
@Override
protected InspectionProfileEntry getInspection() {
return new TypeParameterExtendsFinalClassInspection();
}
@Override
@NotNull
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
}
}