mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 11:53:49 +07:00
[lombok] IDEA-255688 Using existing functionality to skip checking expressions from field initializer
and to skip checking field initializer expression GitOrigin-RevId: 67211ecbad65889dabe6385678cc1b7c47a96deb
This commit is contained in:
committed by
intellij-monorepo-bot
parent
7b19a2dd37
commit
4222be044e
@@ -34,8 +34,6 @@
|
||||
<extensionPoint qualifiedName="com.intellij.codeInsight.changeVariableTypeQuickFixProvider" interface="com.intellij.codeInsight.quickfix.ChangeVariableTypeQuickFixProvider" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.lang.jvm.annotationPackageSupport" interface="com.intellij.codeInsight.annoPackages.AnnotationPackageSupport" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.lang.jvm.ignoreAnnotationParamSupport" interface="com.intellij.codeInspection.DefaultAnnotationParamInspection$IgnoreAnnotationParamSupport" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.lang.jvm.ignoreVariableInitializedBeforeUsageSupport" interface="com.intellij.codeInsight.daemon.impl.analysis.VariableInitializedBeforeUsageSupport" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.lang.jvm.ignoreMethodCallExpressionNPESupport" interface="com.intellij.codeInspection.dataFlow.MethodCallProduceNPESupport" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.javaLanguageLevelPusherCustomizer" interface="com.intellij.openapi.roots.impl.JavaLanguageLevelPusherCustomizer" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.propertyAccessorDetector" interface="com.intellij.psi.util.PropertyAccessorDetector" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.virtualManifestProvider" interface="com.intellij.codeInsight.daemon.impl.analysis.VirtualManifestProvider" dynamic="true"/>
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.controlFlow.*;
|
||||
import com.intellij.psi.impl.light.LightRecordCanonicalConstructor;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
@@ -318,10 +319,6 @@ public final class HighlightControlFlowUtil {
|
||||
boolean ignoreFinality) {
|
||||
if (variable instanceof ImplicitVariable) return null;
|
||||
if (!PsiUtil.isAccessedForReading(expression)) return null;
|
||||
if (ContainerUtil.exists(VariableInitializedBeforeUsageSupport.EP_NAME.getExtensionList(),
|
||||
ext -> ext.ignoreVariableExpression(expression, variable))) {
|
||||
return null;
|
||||
}
|
||||
int startOffset = expression.getTextRange().getStartOffset();
|
||||
PsiElement topBlock;
|
||||
if (variable.hasInitializer()) {
|
||||
@@ -394,6 +391,9 @@ public final class HighlightControlFlowUtil {
|
||||
isFieldInitializedInClassInitializer(field, true, aClass.getInitializers())) {
|
||||
return null;
|
||||
}
|
||||
if(anotherField!=null && anotherField.hasInitializer() && !PsiAugmentProvider.canTrustFieldInitializer(anotherField)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int offset = startOffset;
|
||||
if (anotherField != null && anotherField.getContainingClass() == aClass && !field.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.psi.PsiReferenceExpression;
|
||||
import com.intellij.psi.PsiVariable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Allows skipping 'Variable might not have been initialized' highlighting for specific PsiReference
|
||||
*/
|
||||
public interface VariableInitializedBeforeUsageSupport {
|
||||
ExtensionPointName<VariableInitializedBeforeUsageSupport> EP_NAME =
|
||||
ExtensionPointName.create("com.intellij.lang.jvm.ignoreVariableInitializedBeforeUsageSupport");
|
||||
/**
|
||||
* Checks if the given expression should be ignored for inspection.
|
||||
*
|
||||
* @param psiExpression the expression to be checked for ignoring the initializer
|
||||
* @param psiVariable the variable from the expression resolving
|
||||
* @return true if the inspection should be skipped for the {@code psiExpression},
|
||||
* otherwise false
|
||||
*/
|
||||
default boolean ignoreVariableExpression(@NotNull PsiReferenceExpression psiExpression, @NotNull PsiVariable psiVariable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
/**
|
||||
* This interface provides support for checking whether a method call expression should be ignored
|
||||
* for inspection that checks for potential null pointer exceptions (NPE).
|
||||
*/
|
||||
public interface MethodCallProduceNPESupport {
|
||||
ExtensionPointName<MethodCallProduceNPESupport> EP_NAME =
|
||||
ExtensionPointName.create("com.intellij.lang.jvm.ignoreMethodCallExpressionNPESupport");
|
||||
/**
|
||||
* Checks if the given expression should be ignored for inspection.
|
||||
*
|
||||
* @param psiExpression expression which can actually violates the nullability
|
||||
* @return true if the inspection should be skipped for the {@code psiExpression},
|
||||
* otherwise false
|
||||
*/
|
||||
default boolean ignoreMethodCallExpression(@NotNull PsiExpression psiExpression) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -181,10 +181,6 @@ public final class NullabilityProblemKind<T extends PsiElement> {
|
||||
if (parameter != null) {
|
||||
return getParameterProblem(parameter, expression, context);
|
||||
}
|
||||
if (ContainerUtil.exists(MethodCallProduceNPESupport.EP_NAME.getExtensionList(),
|
||||
ext -> ext.ignoreMethodCallExpression(expression))) {
|
||||
return null;
|
||||
}
|
||||
return callNPE.problem((PsiMethodCallExpression)grandParent, expression);
|
||||
}
|
||||
return fieldAccessNPE.problem(context, expression);
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.intellij.codeInspection.dataFlow.value.DfaControlTransferValue.Trap;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.impl.source.tree.java.PsiEmptyExpressionImpl;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
@@ -101,7 +102,8 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
addInstruction(new FlushFieldsInstruction());
|
||||
}
|
||||
for (PsiElement element = psiClass.getFirstChild(); element != null; element = element.getNextSibling()) {
|
||||
if ((element instanceof PsiField field && field.hasInitializer() || element instanceof PsiClassInitializer) &&
|
||||
if ((element instanceof PsiField field &&
|
||||
field.hasInitializer() && PsiAugmentProvider.canTrustFieldInitializer(field) || element instanceof PsiClassInitializer) &&
|
||||
((PsiMember)element).hasModifierProperty(PsiModifier.STATIC) == isStatic) {
|
||||
element.accept(this);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.psi.augment.PsiExtensionMethod;
|
||||
import com.intellij.psi.impl.source.PsiExtensibleClass;
|
||||
import com.siyeh.ig.psiutils.InitializationUtils;
|
||||
import de.plushnikov.intellij.plugin.LombokClassNames;
|
||||
import de.plushnikov.intellij.plugin.processor.LombokProcessorManager;
|
||||
import de.plushnikov.intellij.plugin.processor.Processor;
|
||||
@@ -12,6 +13,7 @@ import de.plushnikov.intellij.plugin.processor.ValProcessor;
|
||||
import de.plushnikov.intellij.plugin.processor.method.ExtensionMethodsHelper;
|
||||
import de.plushnikov.intellij.plugin.processor.modifier.ModifierProcessor;
|
||||
import de.plushnikov.intellij.plugin.util.PsiAnnotationSearchUtil;
|
||||
import de.plushnikov.intellij.plugin.util.PsiAnnotationUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -61,13 +63,40 @@ public class LombokAugmentProvider extends PsiAugmentProvider {
|
||||
/*
|
||||
* The final fields that are marked with Builder.Default contains only possible value
|
||||
* because user can set another value during the creation of the object.
|
||||
*
|
||||
* The fields marked with Getter(lazy=true) contains a value that will be calculated only at first access to the getter-Method
|
||||
*/
|
||||
//see de.plushnikov.intellij.plugin.inspection.DataFlowInspectionTest.testDefaultBuilderFinalValueInspectionIsAlwaysThat
|
||||
//see de.plushnikov.intellij.plugin.inspection.PointlessBooleanExpressionInspectionTest.testPointlessBooleanExpressionBuilderDefault
|
||||
//see com.intellij.java.lomboktest.LombokHighlightingTest.testBuilderWithDefaultRedundantInitializer
|
||||
//see com.intellij.java.lomboktest.LombokHighlightingTest.testGetterLazyInvocationProduceNPE
|
||||
//see com.intellij.java.lomboktest.LombokHighlightingTest.testGetterLazyVariableNotInitialized
|
||||
@Override
|
||||
protected boolean fieldInitializerMightBeChanged(@NotNull PsiField field) {
|
||||
return PsiAnnotationSearchUtil.isAnnotatedWith(field, LombokClassNames.BUILDER_DEFAULT);
|
||||
if (field.hasAnnotation(LombokClassNames.BUILDER_DEFAULT)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final PsiAnnotation getterAnnotation = PsiAnnotationSearchUtil.findAnnotation(field, LombokClassNames.GETTER);
|
||||
final boolean isLazyGetter = null != getterAnnotation &&
|
||||
PsiAnnotationUtil.getBooleanAnnotationValue(getterAnnotation, "lazy", false);
|
||||
|
||||
if (isLazyGetter) {
|
||||
final PsiExpression fieldInitializer = field.getInitializer();
|
||||
if (fieldInitializer instanceof PsiMethodCallExpression methodCallExpression) {
|
||||
final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
|
||||
if (qualifierExpression instanceof PsiReferenceExpression qualifierReferenceExpression) {
|
||||
final PsiElement referencedElement = qualifierReferenceExpression.resolve();
|
||||
if (referencedElement instanceof PsiField referencedField) {
|
||||
final PsiClass containingClass = referencedField.getContainingClass();
|
||||
if (containingClass != null) {
|
||||
return InitializationUtils.isInitializedInConstructors(referencedField, containingClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return isLazyGetter;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package de.plushnikov.intellij.plugin.provider;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.MethodCallProduceNPESupport;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.ig.psiutils.InitializationUtils;
|
||||
import de.plushnikov.intellij.plugin.LombokClassNames;
|
||||
import de.plushnikov.intellij.plugin.util.PsiAnnotationSearchUtil;
|
||||
import de.plushnikov.intellij.plugin.util.PsiAnnotationUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LombokMethodCallExpressionNPESupport implements MethodCallProduceNPESupport {
|
||||
@Override
|
||||
public boolean ignoreMethodCallExpression(@NotNull PsiExpression psiExpression) {
|
||||
final PsiField field = PsiTreeUtil.getParentOfType(psiExpression, PsiField.class);
|
||||
if (field == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiAnnotation getterAnnotation = PsiAnnotationSearchUtil.findAnnotation(field, LombokClassNames.GETTER);
|
||||
final boolean isLazyGetter = null != getterAnnotation && PsiAnnotationUtil.getBooleanAnnotationValue(getterAnnotation, "lazy", false);
|
||||
|
||||
if (isLazyGetter) {
|
||||
final PsiReference reference = psiExpression.getReference();
|
||||
if (reference != null) {
|
||||
PsiElement referencedElement = reference.resolve();
|
||||
if (!(referencedElement instanceof PsiField referencedField)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PsiClass containingClass = referencedField.getContainingClass();
|
||||
if (containingClass != null) {
|
||||
return InitializationUtils.isInitializedInConstructors(referencedField, containingClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
return isLazyGetter;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package de.plushnikov.intellij.plugin.provider;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.VariableInitializedBeforeUsageSupport;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import de.plushnikov.intellij.plugin.LombokClassNames;
|
||||
import de.plushnikov.intellij.plugin.util.PsiAnnotationUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
/**
|
||||
* A class that implements the VariableInitializedBeforeUsageSupport interface to provide support for Lombok annotated variables.
|
||||
* It checks if a variable expression should be ignored based on Lombok annotations.
|
||||
*/
|
||||
public class LombokVariableInitializedBeforeUsageSupport implements VariableInitializedBeforeUsageSupport {
|
||||
@Override
|
||||
public boolean ignoreVariableExpression(@NotNull PsiReferenceExpression psiExpression, @NotNull PsiVariable psiVariable) {
|
||||
final PsiField field = PsiTreeUtil.getParentOfType(psiExpression, PsiField.class);
|
||||
if (field == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiAnnotation getterAnnotation = field.getAnnotation(LombokClassNames.GETTER);
|
||||
return null != getterAnnotation && PsiAnnotationUtil.getBooleanAnnotationValue(getterAnnotation, "lazy", false);
|
||||
}
|
||||
}
|
||||
@@ -53,8 +53,6 @@
|
||||
<lang.psiAugmentProvider implementation="de.plushnikov.intellij.plugin.provider.LombokAugmentProvider"/>
|
||||
<lang.jvm.annotationPackageSupport implementation="de.plushnikov.intellij.plugin.provider.LombokAnnotationSupport"/>
|
||||
<lang.jvm.ignoreAnnotationParamSupport implementation="de.plushnikov.intellij.plugin.provider.LombokDefaultAnnotationParamSupport"/>
|
||||
<lang.jvm.ignoreVariableInitializedBeforeUsageSupport implementation="de.plushnikov.intellij.plugin.provider.LombokVariableInitializedBeforeUsageSupport"/>
|
||||
<lang.jvm.ignoreMethodCallExpressionNPESupport implementation="de.plushnikov.intellij.plugin.provider.LombokMethodCallExpressionNPESupport"/>
|
||||
<implicitUsageProvider implementation="de.plushnikov.intellij.plugin.provider.LombokImplicitUsageProvider"/>
|
||||
<projectConfigurable groupId="language"
|
||||
key="plugin.settings.title" bundle="messages.LombokBundle"
|
||||
|
||||
@@ -14,6 +14,7 @@ public class GetterLazyInvocationProduceNPE {
|
||||
}
|
||||
|
||||
private Bar <warning descr="Field 'bar' may be 'final'">bar</warning>;
|
||||
private Bar <warning descr="Private field 'bar2' is never assigned">bar2</warning>;
|
||||
private Car car;
|
||||
|
||||
public GetterLazyInvocationProduceNPE(Bar bar, Car car) {
|
||||
@@ -21,11 +22,15 @@ public class GetterLazyInvocationProduceNPE {
|
||||
this.car = car;
|
||||
}
|
||||
|
||||
// without warning
|
||||
// without warning, because of lazy getter and initialized in constructor
|
||||
@Getter(lazy = true)
|
||||
private final String barString = bar.sayHello();
|
||||
|
||||
//with warning!
|
||||
// with warning, because of lazy getter and NOT initialized in constructor
|
||||
@Getter(lazy = true)
|
||||
private final String bar2String = bar2.<warning descr="Method invocation 'sayHello' will produce 'NullPointerException'">sayHello</warning>();
|
||||
|
||||
//with warning, because of NOT lazy getter
|
||||
@Getter
|
||||
private final String carString = car.<warning descr="Method invocation 'sayHello' will produce 'NullPointerException'">sayHello</warning>();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user