mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[Java. Inspections] IDEA-381448 Show exact place for nullability conflict in return statements
GitOrigin-RevId: fe03e0582080b4717f7ee85f68b581780518cec4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b8942e68ca
commit
6a33175cfe
@@ -132,8 +132,15 @@ annotate.overridden.methods.parameters=Annotate overriding method parameters as
|
||||
anonymous.ref.loc.can.be.replaced.with.0=Anonymous #ref #loc can be replaced with {0}
|
||||
anonymous.ref.loc.can.be.replaced.with.lambda=Anonymous #ref #loc can be replaced with lambda
|
||||
assigning.a.collection.of.nullable.elements=Assigning a collection of nullable elements into a collection of non-null elements
|
||||
returning.a.class.with.nullable.arguments=Returning a class with nullable type arguments when a class with not-null type arguments is expected
|
||||
returning.a.class.with.notnull.arguments=Returning a class with not-null type arguments when a class with nullable type arguments is expected
|
||||
returning.a.class.with.nullable.arguments=\
|
||||
<html><body>\
|
||||
Returning a class with nullable type arguments when a class with not-null type arguments is expected{0}\
|
||||
</body></html>
|
||||
returning.a.class.with.notnull.arguments=\
|
||||
<html><body>\
|
||||
Returning a class with not-null type arguments when a class with nullable type arguments is expected{0}\
|
||||
</body></html>
|
||||
returning.a.type.nullability.conflict.message=Return type:
|
||||
conflicting.nullability.annotations=Conflicting nullability annotations
|
||||
nullable.stuff.error.overriding.nullable.with.notnull=Overriding a collection of nullable elements with a collection of non-null elements
|
||||
nullable.stuff.error.overriding.notnull.with.nullable=Overriding a collection of non-null elements with a collection of nullable elements
|
||||
|
||||
+22
-9
@@ -533,13 +533,16 @@ public class NullableStuffInspectionBase extends AbstractBaseJavaLocalInspection
|
||||
private void checkGenericClassOnReturn(@Nullable PsiType expectedType,
|
||||
@NotNull PsiExpression returnValue) {
|
||||
PsiType returnType = returnValue.getType();
|
||||
JavaTypeNullabilityUtil.NullabilityConflict
|
||||
conflict = JavaTypeNullabilityUtil.getNullabilityConflictInAssignment(expectedType, returnType,
|
||||
REPORT_NOT_NULL_TO_NULLABLE_CONFLICTS_IN_ASSIGNMENTS);
|
||||
if (conflict == JavaTypeNullabilityUtil.NullabilityConflict.UNKNOWN) return;
|
||||
String messageKey = conflict == JavaTypeNullabilityUtil.NullabilityConflict.NOT_NULL_TO_NULL ?
|
||||
JavaTypeNullabilityUtil.NullabilityConflictContext
|
||||
context = JavaTypeNullabilityUtil.getNullabilityConflictInAssignment(expectedType, returnType,
|
||||
REPORT_NOT_NULL_TO_NULLABLE_CONFLICTS_IN_ASSIGNMENTS);
|
||||
if (context.nullabilityConflict == JavaTypeNullabilityUtil.NullabilityConflict.UNKNOWN) return;
|
||||
String messageKey = context.nullabilityConflict == JavaTypeNullabilityUtil.NullabilityConflict.NOT_NULL_TO_NULL ?
|
||||
"returning.a.class.with.notnull.arguments" : "returning.a.class.with.nullable.arguments";
|
||||
reportProblem(holder, returnValue, messageKey);
|
||||
|
||||
reportProblem(holder, returnValue, LocalQuickFix.EMPTY_ARRAY,
|
||||
messageKey, new Object[]{""},
|
||||
messageKey, new Object[]{NullableStuffInspectionUtil.getTypePresentationInNullabilityConflict(context)});
|
||||
}
|
||||
|
||||
private void checkCollectionNullityOnAssignment(@NotNull PsiElement errorElement,
|
||||
@@ -587,9 +590,19 @@ public class NullableStuffInspectionBase extends AbstractBaseJavaLocalInspection
|
||||
|
||||
protected void reportProblem(@NotNull ProblemsHolder holder, @NotNull PsiElement anchor, @NotNull LocalQuickFix @NotNull [] fixes,
|
||||
@NotNull @PropertyKey(resourceBundle = JavaAnalysisBundle.BUNDLE) String messageKey, Object... args) {
|
||||
holder.registerProblem(anchor,
|
||||
JavaAnalysisBundle.message(messageKey, args),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fixes);
|
||||
reportProblem(holder, anchor, fixes, messageKey, args, messageKey, args);
|
||||
}
|
||||
|
||||
protected void reportProblem(@NotNull ProblemsHolder holder, @NotNull PsiElement anchor, @NotNull LocalQuickFix @NotNull [] fixes,
|
||||
@NotNull @PropertyKey(resourceBundle = JavaAnalysisBundle.BUNDLE) String descriptionKey, @NotNull Object @NotNull[] descriptionArgs,
|
||||
@NotNull @PropertyKey(resourceBundle = JavaAnalysisBundle.BUNDLE) String tooltipKey, @NotNull Object @NotNull[] tooltipArgs) {
|
||||
ProblemsHolder.ProblemBuilder builder = holder.problem(anchor, JavaAnalysisBundle.message(descriptionKey, descriptionArgs))
|
||||
.tooltip(JavaAnalysisBundle.message(tooltipKey, tooltipArgs))
|
||||
.highlight(ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
|
||||
for (LocalQuickFix quickFix : fixes) {
|
||||
builder.fix(quickFix);
|
||||
}
|
||||
builder.register();
|
||||
}
|
||||
|
||||
private static boolean isNullableNotNullCollectionConflict(@Nullable PsiType expectedType,
|
||||
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInspection.nullable;
|
||||
|
||||
import com.intellij.java.analysis.JavaAnalysisBundle;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.openapi.util.text.HtmlChunk;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.JavaTypeNullabilityUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
final class NullableStuffInspectionUtil {
|
||||
static @NotNull @NlsSafe String getTypePresentationInNullabilityConflict(@NotNull JavaTypeNullabilityUtil.NullabilityConflictContext context) {
|
||||
PsiElement place = context.getPlace();
|
||||
if (place == null) return "";
|
||||
int dimensionsInArray = (context.type instanceof PsiArrayType type) ? type.getArrayDimensions() : 0;
|
||||
|
||||
PsiTypeElement topmostType = PsiTreeUtil.getTopmostParentOfType(place, PsiTypeElement.class);
|
||||
if (topmostType == null) return "";
|
||||
|
||||
PsiTypeElement target = PsiTreeUtil.getParentOfType(place, PsiTypeElement.class, false);
|
||||
if (target == null) return "";
|
||||
|
||||
PsiType outerType = topmostType.getType();
|
||||
if (target == topmostType) {
|
||||
// Presentation is not handling with the whole type
|
||||
return "";
|
||||
}
|
||||
|
||||
List<Integer> path = computeTypeArgumentPath(topmostType, target, dimensionsInArray);
|
||||
if (path == null) return "";
|
||||
|
||||
Context presentationContext = getPresentationContext(outerType, path, outerType instanceof PsiArrayType);
|
||||
|
||||
String typeText = presentationContext.sb.toString();
|
||||
String annotationText = getAnnotationText(context);
|
||||
if (presentationContext.position == null || annotationText == null) return "";
|
||||
HtmlChunk result = generateHtmlChunk(typeText, "@" + annotationText, presentationContext.position);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static @Nullable String getAnnotationText(@NotNull JavaTypeNullabilityUtil.NullabilityConflictContext context) {
|
||||
PsiAnnotation annotation = context.getAnnotation();
|
||||
if (annotation == null) return null;
|
||||
PsiJavaCodeReferenceElement ref = annotation.getNameReferenceElement();
|
||||
if (ref == null) return null;
|
||||
return ref.getReferenceName();
|
||||
}
|
||||
|
||||
private static @NotNull HtmlChunk generateHtmlChunk(@NlsSafe String text,
|
||||
@NlsSafe String annotationText,
|
||||
int position) {
|
||||
HtmlChunk result = HtmlChunk.p().child(
|
||||
HtmlChunk.fragment(
|
||||
HtmlChunk.text(JavaAnalysisBundle.message("returning.a.type.nullability.conflict.message")),
|
||||
HtmlChunk.text(" "),
|
||||
HtmlChunk.text(text.substring(0, position)),
|
||||
HtmlChunk.tag("b").children(HtmlChunk.text(annotationText)),
|
||||
HtmlChunk.text(" "),
|
||||
HtmlChunk.text(text.substring(position))
|
||||
)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static @Nullable List<@NotNull Integer> computeTypeArgumentPath(@NotNull PsiTypeElement top, @NotNull PsiTypeElement target, int firstArrayDepth) {
|
||||
List<Integer> indices = new ArrayList<>();
|
||||
PsiTypeElement current = target;
|
||||
boolean isFirstArrayOccurence = true;
|
||||
while (true) {
|
||||
PsiTypeElement parentTypeElement = PsiTreeUtil.getParentOfType(current, PsiTypeElement.class, true);
|
||||
if (parentTypeElement == null) return null;
|
||||
PsiType parentType = parentTypeElement.getType();
|
||||
if (parentType instanceof PsiClassType) {
|
||||
PsiJavaCodeReferenceElement ref = parentTypeElement.getInnermostComponentReferenceElement();
|
||||
if (ref == null) return null;
|
||||
PsiReferenceParameterList params = ref.getParameterList();
|
||||
if (params == null) return null;
|
||||
PsiTypeElement[] args = params.getTypeParameterElements();
|
||||
int found = -1;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i] == current) {
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found < 0) return null;
|
||||
indices.add(found);
|
||||
}
|
||||
else if (parentType instanceof PsiWildcardType ||
|
||||
parentType instanceof PsiCapturedWildcardType) {
|
||||
indices.add(0);
|
||||
} else if (parentType instanceof PsiArrayType arrayType) {
|
||||
int candidateArrayDepth = arrayType.getArrayDimensions();
|
||||
int numberToAdd;
|
||||
if (isFirstArrayOccurence && candidateArrayDepth == firstArrayDepth) {
|
||||
numberToAdd = 0;
|
||||
} else if (isFirstArrayOccurence && firstArrayDepth > 0) {
|
||||
numberToAdd = firstArrayDepth;
|
||||
} else {
|
||||
numberToAdd = candidateArrayDepth;
|
||||
}
|
||||
for (int i = 0; i < numberToAdd; i++) {
|
||||
indices.add(0);
|
||||
}
|
||||
}
|
||||
if (parentTypeElement == top) break;
|
||||
current = parentTypeElement;
|
||||
isFirstArrayOccurence = false;
|
||||
}
|
||||
Collections.reverse(indices);
|
||||
return indices;
|
||||
}
|
||||
|
||||
private static @NotNull Context getPresentationContext(@NotNull PsiType type, List<Integer> path, boolean isInsideArray) {
|
||||
Context context = new Context();
|
||||
buildTextRepresentation(type, context, path, 0, isInsideArray);
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the simplified presentable view of the type and detects the place in which the nullability annotation should be inserted.
|
||||
* The result of this method is stored in the {@link Context#sb} member.
|
||||
* @param isInsideArray - Corresponds to the state whether the method is called within the array dimension. It is used to distinguish
|
||||
* cases {@code @Nullable String[]} and {@code String @Nullable [][]}.
|
||||
*/
|
||||
private static void buildTextRepresentation(@NotNull PsiType type,
|
||||
@NotNull Context context,
|
||||
@NotNull List<@NotNull Integer> path,
|
||||
int depth,
|
||||
boolean isInsideArray) {
|
||||
if (depth == path.size()) {
|
||||
if (type instanceof PsiArrayType arrayType && isInsideArray) {
|
||||
context.sb.append(arrayType.getPresentableText(false));
|
||||
context.sb.append(" ");
|
||||
context.position = context.sb.length();
|
||||
}
|
||||
else if (type instanceof PsiArrayType arrayType) {
|
||||
context.sb.append(arrayType.getDeepComponentType().getPresentableText(false));
|
||||
context.sb.append(" ");
|
||||
context.position = context.sb.length();
|
||||
context.sb.repeat("[]", Math.max(0, arrayType.getArrayDimensions()));
|
||||
}
|
||||
else {
|
||||
String text = type.getPresentableText(false);
|
||||
context.position = context.sb.length();
|
||||
context.sb.append(text);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (type instanceof PsiArrayType arrayType) {
|
||||
PsiType component = arrayType.getComponentType();
|
||||
buildTextRepresentation(component, context, path, depth + 1, true);
|
||||
context.sb.append("[]");
|
||||
return;
|
||||
}
|
||||
if (type instanceof PsiWildcardType wc) {
|
||||
String prefix = wc.isExtends() ? "? extends " : wc.isSuper() ? "? super " : "?";
|
||||
context.sb.append(prefix);
|
||||
PsiType bound = wc.getBound();
|
||||
if (bound != null) {
|
||||
buildTextRepresentation(bound, context, path, depth + 1, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (type instanceof PsiClassType cls) {
|
||||
String name = cls.getClassName();
|
||||
if (name == null) name = cls.getPresentableText(false);
|
||||
context.sb.append(name);
|
||||
PsiType[] params = cls.getParameters();
|
||||
if (params.length > 0) {
|
||||
context.sb.append('<');
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
if (i > 0) context.sb.append(", ");
|
||||
if (i == path.get(depth)) {
|
||||
buildTextRepresentation(params[i], context, path, depth + 1, false);
|
||||
}
|
||||
else {
|
||||
context.sb.append(params[i].getPresentableText(false));
|
||||
}
|
||||
}
|
||||
context.sb.append('>');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
context.sb.append(type.getPresentableText(false));
|
||||
}
|
||||
|
||||
private static final class Context {
|
||||
private @Nullable Integer position = null;
|
||||
private final @NotNull StringBuilder sb = new StringBuilder();
|
||||
}
|
||||
}
|
||||
@@ -2043,6 +2043,7 @@
|
||||
implementationClass="com.intellij.codeInspection.wrongPackageStatement.WrongPackageStatementInspection"/>
|
||||
<localInspection groupPathKey="group.path.names.probable.bugs" language="JAVA" shortName="NullableProblems" bundle="messages.JavaBundle"
|
||||
key="inspection.nullable.problems.display.name"
|
||||
hasStaticDescription="true"
|
||||
groupKey="group.names.nullability.problems" groupBundle="messages.InspectionsBundle" enabledByDefault="true"
|
||||
level="WARNING"
|
||||
implementationClass="com.intellij.codeInspection.nullable.NullableStuffInspection"/>
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.intellij.codeInspection.options.OptPane;
|
||||
import com.intellij.codeInspection.options.OptionController;
|
||||
import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -25,6 +26,7 @@ import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.codeInspection.options.OptPane.checkbox;
|
||||
import static com.intellij.codeInspection.options.OptPane.pane;
|
||||
@@ -54,6 +56,15 @@ public class NullableStuffInspection extends NullableStuffInspectionBase {
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable @Nls String getStaticDescription() {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return "";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull OptionController getOptionController() {
|
||||
return super.getOptionController()
|
||||
|
||||
@@ -11,10 +11,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Helper methods to compute nullability of Java types.
|
||||
@@ -23,14 +20,14 @@ import java.util.Set;
|
||||
public final class JavaTypeNullabilityUtil {
|
||||
/**
|
||||
* Computes the class type nullability
|
||||
*
|
||||
*
|
||||
* @param type type to compute nullability for
|
||||
* @return type nullability
|
||||
*/
|
||||
public static @NotNull TypeNullability getTypeNullability(@NotNull PsiClassType type) {
|
||||
return getTypeNullability(type, null, !isLocal(type));
|
||||
}
|
||||
|
||||
|
||||
private static @NotNull TypeNullability getTypeNullability(@NotNull PsiClassType type,
|
||||
@Nullable Set<PsiClassType> visited,
|
||||
boolean checkContainer) {
|
||||
@@ -77,7 +74,7 @@ public final class JavaTypeNullabilityUtil {
|
||||
}
|
||||
return TypeNullability.UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
private static boolean isLocal(PsiClassType classType) {
|
||||
PsiElement context = classType.getPsiContext();
|
||||
return context instanceof PsiJavaCodeReferenceElement &&
|
||||
@@ -115,27 +112,27 @@ public final class JavaTypeNullabilityUtil {
|
||||
* @param rightType assigned value
|
||||
* @param checkNotNullToNull whether to check for nullability conflict when assigning not-null to null value
|
||||
*
|
||||
* @see JavaTypeNullabilityUtil#getNullabilityConflictType(PsiType, PsiType)
|
||||
* @see JavaTypeNullabilityUtil#getNullabilityConflictTypeContext(PsiType, PsiType)
|
||||
*/
|
||||
public static @NotNull NullabilityConflict getNullabilityConflictInAssignment(@Nullable PsiType leftType,
|
||||
public static @NotNull NullabilityConflictContext getNullabilityConflictInAssignment(@Nullable PsiType leftType,
|
||||
@Nullable PsiType rightType,
|
||||
boolean checkNotNullToNull) {
|
||||
return getNullabilityConflictInAssignment(leftType, rightType, checkNotNullToNull, false);
|
||||
}
|
||||
|
||||
private static @NotNull NullabilityConflict getNullabilityConflictInAssignment(@Nullable PsiType leftType,
|
||||
private static @NotNull NullabilityConflictContext getNullabilityConflictInAssignment(@Nullable PsiType leftType,
|
||||
@Nullable PsiType rightType,
|
||||
boolean checkNotNullToNull,
|
||||
boolean checkConflictInInitialType) {
|
||||
if (checkConflictInInitialType) {
|
||||
NullabilityConflict nullabilityConflict = getNullabilityConflictType(leftType, rightType);
|
||||
if (isAllowedNullabilityConflictType(checkNotNullToNull, nullabilityConflict)) return nullabilityConflict;
|
||||
NullabilityConflictContext context = getNullabilityConflictTypeContext(leftType, rightType);
|
||||
if (isAllowedNullabilityConflictType(checkNotNullToNull, context)) return context;
|
||||
}
|
||||
|
||||
if (leftType == null || TypeConversionUtil.isNullType(leftType) ||
|
||||
rightType == null || TypeConversionUtil.isNullType(rightType)
|
||||
) {
|
||||
return NullabilityConflict.UNKNOWN;
|
||||
return NullabilityConflictContext.UNKNOWN;
|
||||
}
|
||||
|
||||
if (rightType instanceof PsiIntersectionType) {
|
||||
@@ -163,7 +160,7 @@ public final class JavaTypeNullabilityUtil {
|
||||
}
|
||||
|
||||
if (!(leftType instanceof PsiClassType) || !(rightType instanceof PsiClassType)) {
|
||||
return NullabilityConflict.UNKNOWN;
|
||||
return NullabilityConflictContext.UNKNOWN;
|
||||
}
|
||||
|
||||
return getNullabilityConflictInTypeArguments(leftType, rightType, checkNotNullToNull);
|
||||
@@ -178,35 +175,34 @@ public final class JavaTypeNullabilityUtil {
|
||||
* @param checkNotNullToNull whether to check for nullability conflict when assigning not-null to null value.
|
||||
* @return first inconsistency in nullability inside generic class type arguments.
|
||||
*/
|
||||
private static @NotNull NullabilityConflict getNullabilityConflictInTypeArguments(@NotNull PsiType leftType,
|
||||
private static @NotNull NullabilityConflictContext getNullabilityConflictInTypeArguments(@NotNull PsiType leftType,
|
||||
@NotNull PsiType rightType,
|
||||
boolean checkNotNullToNull) {
|
||||
if (isRawType(leftType) || isRawType(rightType)) return NullabilityConflict.UNKNOWN;
|
||||
if (isRawType(leftType) || isRawType(rightType)) return NullabilityConflictContext.UNKNOWN;
|
||||
PsiClass leftClass = PsiTypesUtil.getPsiClass(leftType);
|
||||
if (leftClass == null) return NullabilityConflict.UNKNOWN;
|
||||
|
||||
if (leftClass == null) return NullabilityConflictContext.UNKNOWN;
|
||||
List<PsiType> leftParameterTypeList = getParentParameterTypeListFromDerivedType(leftType, leftClass);
|
||||
List<PsiType> rightParameterTypeList = getParentParameterTypeListFromDerivedType(rightType, leftClass);
|
||||
if (leftParameterTypeList == null ||
|
||||
rightParameterTypeList == null ||
|
||||
leftParameterTypeList.size() != rightParameterTypeList.size()) {
|
||||
return NullabilityConflict.UNKNOWN;
|
||||
return NullabilityConflictContext.UNKNOWN;
|
||||
}
|
||||
|
||||
for (int i = 0; i < leftParameterTypeList.size(); i++) {
|
||||
PsiType leftParameterType = leftParameterTypeList.get(i);
|
||||
PsiType rightParameterType = rightParameterTypeList.get(i);
|
||||
|
||||
NullabilityConflict nullabilityConflict = getNullabilityConflictInAssignment(
|
||||
NullabilityConflictContext context = getNullabilityConflictInAssignment(
|
||||
leftParameterType,
|
||||
rightParameterType,
|
||||
checkNotNullToNull,
|
||||
true
|
||||
);
|
||||
if (nullabilityConflict != NullabilityConflict.UNKNOWN) return nullabilityConflict;
|
||||
if (context.nullabilityConflict != NullabilityConflict.UNKNOWN) return context;
|
||||
}
|
||||
|
||||
return NullabilityConflict.UNKNOWN;
|
||||
return NullabilityConflictContext.UNKNOWN;
|
||||
}
|
||||
|
||||
private static boolean isRawType(@NotNull PsiType type) {
|
||||
@@ -225,9 +221,9 @@ public final class JavaTypeNullabilityUtil {
|
||||
return PsiUtil.substituteTypeParameters(derivedType, superClass, true);
|
||||
}
|
||||
|
||||
private static boolean isAllowedNullabilityConflictType(boolean checkNotNullToNull, @NotNull NullabilityConflict nullabilityConflict) {
|
||||
return nullabilityConflict != NullabilityConflict.UNKNOWN &&
|
||||
(checkNotNullToNull || nullabilityConflict != NullabilityConflict.NOT_NULL_TO_NULL);
|
||||
private static boolean isAllowedNullabilityConflictType(boolean checkNotNullToNull, @NotNull NullabilityConflictContext context) {
|
||||
return context.nullabilityConflict != NullabilityConflict.UNKNOWN &&
|
||||
(checkNotNullToNull || context.nullabilityConflict != NullabilityConflict.NOT_NULL_TO_NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,18 +232,73 @@ public final class JavaTypeNullabilityUtil {
|
||||
* @param rightType assigned value
|
||||
* @see NullabilityConflict
|
||||
*/
|
||||
public static @NotNull NullabilityConflict getNullabilityConflictType(@Nullable PsiType leftType, @Nullable PsiType rightType) {
|
||||
if (leftType == null || rightType == null) return NullabilityConflict.UNKNOWN;
|
||||
public static @NotNull NullabilityConflictContext getNullabilityConflictTypeContext(@Nullable PsiType leftType, @Nullable PsiType rightType) {
|
||||
if (leftType == null || rightType == null) return NullabilityConflictContext.UNKNOWN;
|
||||
TypeNullability leftTypeNullability = leftType.getNullability();
|
||||
TypeNullability rightTypeNullability = rightType.getNullability();
|
||||
Nullability leftNullability = leftTypeNullability.nullability();
|
||||
Nullability rightNullability = rightTypeNullability.nullability();
|
||||
|
||||
if (leftNullability == Nullability.NOT_NULL && rightNullability == Nullability.NULLABLE) return NullabilityConflict.NULL_TO_NOT_NULL;
|
||||
if (leftNullability == Nullability.NOT_NULL && rightNullability == Nullability.NULLABLE) {
|
||||
return new NullabilityConflictContext(NullabilityConflict.NULL_TO_NOT_NULL, rightType);
|
||||
}
|
||||
// It is not possible to have NOT_NULL_TO_NULL conflict when left type is wildcard with upper bound,
|
||||
// e.g., this assignment is legal {@code List<? extends @Nullable Object> = List<@NotNull String>}
|
||||
else if (leftNullability == Nullability.NULLABLE && rightNullability == Nullability.NOT_NULL && !GenericsUtil.isWildcardWithExtendsBound(leftType)) return NullabilityConflict.NOT_NULL_TO_NULL;
|
||||
return NullabilityConflict.UNKNOWN;
|
||||
else if (leftNullability == Nullability.NULLABLE && rightNullability == Nullability.NOT_NULL && !GenericsUtil.isWildcardWithExtendsBound(leftType)) {
|
||||
return new NullabilityConflictContext(NullabilityConflict.NOT_NULL_TO_NULL, rightType);
|
||||
}
|
||||
return NullabilityConflictContext.UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holds information about the nullability conflict that might be used to provide more descriptive error messages.
|
||||
*/
|
||||
public static class NullabilityConflictContext {
|
||||
public final @NotNull NullabilityConflict nullabilityConflict;
|
||||
public final @Nullable PsiType type;
|
||||
|
||||
public static final NullabilityConflictContext UNKNOWN = new NullabilityConflictContext(NullabilityConflict.UNKNOWN, null);
|
||||
|
||||
public NullabilityConflictContext(@NotNull NullabilityConflict nullabilityConflict, @Nullable PsiType type) {
|
||||
this.type = type;
|
||||
this.nullabilityConflict = nullabilityConflict;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return type argument or array type in which the conflict is occurred.
|
||||
*/
|
||||
public @Nullable PsiElement getPlace() {
|
||||
return getPlace(type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return nullability annotation that produces the conflict.
|
||||
*/
|
||||
public @Nullable PsiAnnotation getAnnotation() {
|
||||
if (type == null) return null;
|
||||
TypeNullability nullability = type.getNullability();
|
||||
NullabilityAnnotationInfo info = nullability.toNullabilityAnnotationInfo();
|
||||
if (info == null) return null;
|
||||
return info.getAnnotation();
|
||||
}
|
||||
|
||||
private static @Nullable PsiElement getPlace(PsiType placeHolder) {
|
||||
if (placeHolder instanceof PsiClassType) {
|
||||
return ((PsiClassType)placeHolder).getPsiContext();
|
||||
}
|
||||
else if (placeHolder instanceof PsiCapturedWildcardType) {
|
||||
return getPlace(((PsiCapturedWildcardType) placeHolder).getWildcard());
|
||||
}
|
||||
else if (placeHolder instanceof PsiWildcardType) {
|
||||
return getPlace(((PsiWildcardType)placeHolder).getBound());
|
||||
}
|
||||
else if (placeHolder instanceof PsiArrayType) {
|
||||
return getPlace(placeHolder.getDeepComponentType());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,4 +318,4 @@ public final class JavaTypeNullabilityUtil {
|
||||
*/
|
||||
UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
-14
@@ -1,20 +1,21 @@
|
||||
import org.jspecify.annotations.NotNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
class B<T> {
|
||||
B<@NotNull String> simpleNullableToNotNull(B<@Nullable String> arg) {
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected">arg</warning>;
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected" tooltip="Returning a class with nullable type arguments when a class with not-null type arguments is expected<p>Return type: B<<b>@Nullable</b> String></p>">arg</warning>;
|
||||
}
|
||||
|
||||
B<@Nullable String> simpleNotNullToNullable(B<@NotNull String> arg) {
|
||||
return <warning descr="Returning a class with not-null type arguments when a class with nullable type arguments is expected">arg</warning>;
|
||||
return <warning descr="Returning a class with not-null type arguments when a class with nullable type arguments is expected" tooltip="Returning a class with not-null type arguments when a class with nullable type arguments is expected<p>Return type: B<<b>@NotNull</b> String></p>">arg</warning>;
|
||||
}
|
||||
|
||||
B<B<@NotNull String>> nested(B<B<@Nullable String>> arg) {
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected">arg</warning>;
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected" tooltip="Returning a class with nullable type arguments when a class with not-null type arguments is expected<p>Return type: B<B<<b>@Nullable</b> String>></p>">arg</warning>;
|
||||
}
|
||||
|
||||
B<? extends @Nullable Object> extendsWildcardNullable(B<@NotNull Object> arg) {
|
||||
@@ -22,7 +23,7 @@ class B<T> {
|
||||
}
|
||||
|
||||
B<? extends @NotNull Object> extendsWildcardNotNull(B<@Nullable String> arg) {
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected">arg</warning>;
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected" tooltip="Returning a class with nullable type arguments when a class with not-null type arguments is expected<p>Return type: B<<b>@Nullable</b> String></p>">arg</warning>;
|
||||
}
|
||||
|
||||
B<? super @NotNull String> SupperWildcard(B<@Nullable Object> arg) {
|
||||
@@ -30,7 +31,7 @@ class B<T> {
|
||||
}
|
||||
|
||||
B<? extends @NotNull Object> extendsWildcardBothNotNull(B<? extends @Nullable Object> arg) {
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected">arg</warning>;
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected" tooltip="Returning a class with nullable type arguments when a class with not-null type arguments is expected<p>Return type: B<? extends <b>@Nullable</b> Object></p>">arg</warning>;
|
||||
}
|
||||
|
||||
B<? extends @Nullable Object> extendsWildcardBothNullable(B<? extends @NotNull Object> arg) {
|
||||
@@ -42,35 +43,35 @@ class B<T> {
|
||||
}
|
||||
|
||||
B<? extends B<@NotNull Object>> nestedWithWildcard(B<B<@Nullable Object>> arg) {
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected">arg</warning>;
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected" tooltip="Returning a class with nullable type arguments when a class with not-null type arguments is expected<p>Return type: B<B<<b>@Nullable</b> Object>></p>">arg</warning>;
|
||||
}
|
||||
|
||||
Map<List<String>, List<@Nullable String>> checkIsPerformedIfSecondTypeArgumentIsTheSame(Map<List<String>, List<@NotNull String>> arg) {
|
||||
return <warning descr="Returning a class with not-null type arguments when a class with nullable type arguments is expected">arg</warning>;
|
||||
return <warning descr="Returning a class with not-null type arguments when a class with nullable type arguments is expected" tooltip="Returning a class with not-null type arguments when a class with nullable type arguments is expected<p>Return type: Map<List<String>, List<<b>@NotNull</b> String>></p>">arg</warning>;
|
||||
}
|
||||
|
||||
B<@NotNull String>[] array(B<@Nullable String>[] arg) {
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected">arg</warning>;
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected" tooltip="Returning a class with nullable type arguments when a class with not-null type arguments is expected<p>Return type: B<<b>@Nullable</b> String>[]</p>">arg</warning>;
|
||||
}
|
||||
|
||||
Object[] @NotNull [] nullabilityInNestedArray(Object[] @Nullable [] arg) {
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected">arg</warning>;
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected" tooltip="Returning a class with nullable type arguments when a class with not-null type arguments is expected<p>Return type: Object[] <b>@Nullable</b> []</p>">arg</warning>;
|
||||
}
|
||||
|
||||
B<@NotNull String>[][] multiDimensionalArray(B<@Nullable String>[][] arg) {
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected">arg</warning>;
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected" tooltip="Returning a class with nullable type arguments when a class with not-null type arguments is expected<p>Return type: B<<b>@Nullable</b> String>[][]</p>">arg</warning>;
|
||||
}
|
||||
|
||||
static class C<T, V> {
|
||||
C<Object, @NotNull String> secondArgument(C<Object, @Nullable String> arg) {
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected">arg</warning>;
|
||||
return <warning descr="Returning a class with nullable type arguments when a class with not-null type arguments is expected" tooltip="Returning a class with nullable type arguments when a class with not-null type arguments is expected<p>Return type: C<Object, <b>@Nullable</b> String></p>">arg</warning>;
|
||||
}
|
||||
}
|
||||
|
||||
interface I {}
|
||||
|
||||
List<@Nullable String> intersectionSimple(Object arg) {
|
||||
return <warning descr="Returning a class with not-null type arguments when a class with nullable type arguments is expected">(List<@NotNull String> & I) arg</warning>;
|
||||
return <warning descr="Returning a class with not-null type arguments when a class with nullable type arguments is expected" tooltip="Returning a class with not-null type arguments when a class with nullable type arguments is expected">(List<@NotNull String> & I) arg</warning>;
|
||||
}
|
||||
|
||||
Collection<@Nullable String> intersectionTreatsFirstMatchingUnknown(Object arg) {
|
||||
@@ -78,11 +79,11 @@ class B<T> {
|
||||
}
|
||||
|
||||
Collection<@Nullable String> intersectionTreatsFirstMatchingMismatch(Object arg) {
|
||||
return <warning descr="Returning a class with not-null type arguments when a class with nullable type arguments is expected">(Collection<@NotNull String> & List<@NotNull String> & I) arg</warning>;
|
||||
return <warning descr="Returning a class with not-null type arguments when a class with nullable type arguments is expected" tooltip="Returning a class with not-null type arguments when a class with nullable type arguments is expected">(Collection<@NotNull String> & List<@NotNull String> & I) arg</warning>;
|
||||
}
|
||||
|
||||
List<List<@Nullable String>> nestedIntersection(Object arg) {
|
||||
return <warning descr="Returning a class with not-null type arguments when a class with nullable type arguments is expected">(List<List<@NotNull String>> & I) arg</warning>;
|
||||
return <warning descr="Returning a class with not-null type arguments when a class with nullable type arguments is expected" tooltip="Returning a class with not-null type arguments when a class with nullable type arguments is expected">(List<List<@NotNull String>> & I) arg</warning>;
|
||||
}
|
||||
|
||||
static class NoStackOverflow {
|
||||
@@ -96,4 +97,11 @@ class B<T> {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
@NullMarked
|
||||
static class ReturnWithNullMarked {
|
||||
static List<@Nullable String> f(List<String> arg) {
|
||||
return <warning descr="Returning a class with not-null type arguments when a class with nullable type arguments is expected" tooltip="Returning a class with not-null type arguments when a class with nullable type arguments is expected<p>Return type: List<<b>@NullMarked</b> String></p>">arg</warning>;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -7,6 +7,7 @@ import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.codeInspection.ex.InspectionManagerEx;
|
||||
import com.intellij.codeInspection.nullable.NullableStuffInspection;
|
||||
import com.intellij.java.analysis.JavaAnalysisBundle;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
@@ -31,6 +32,7 @@ import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
|
||||
import one.util.streamex.EntryStream;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.PropertyKey;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -221,11 +223,10 @@ public class JSpecifyConformanceAnnotationTest extends LightJavaCodeInsightFixtu
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reportProblem(@NotNull ProblemsHolder holder,
|
||||
@NotNull PsiElement anchor,
|
||||
LocalQuickFix @NotNull [] fixes,
|
||||
@NotNull String messageKey, Object... args) {
|
||||
switch (messageKey) {
|
||||
protected void reportProblem(@NotNull ProblemsHolder holder, @NotNull PsiElement anchor, @NotNull LocalQuickFix @NotNull [] fixes,
|
||||
@NotNull @PropertyKey(resourceBundle = JavaAnalysisBundle.BUNDLE) String descriptionKey, @NotNull Object @NotNull[] descriptionArgs,
|
||||
@NotNull @PropertyKey(resourceBundle = JavaAnalysisBundle.BUNDLE) String tooltipKey, @NotNull Object @NotNull[] tooltipArgs) {
|
||||
switch (descriptionKey) {
|
||||
case "inspection.nullable.problems.primitive.type.annotation",
|
||||
"inspection.nullable.problems.at.throws",
|
||||
"inspection.nullable.problems.at.type.parameter",
|
||||
|
||||
+6
-5
@@ -14,6 +14,7 @@ import com.intellij.codeInspection.dataFlow.NullabilityProblemKind;
|
||||
import com.intellij.codeInspection.ex.InspectionManagerEx;
|
||||
import com.intellij.codeInspection.nullable.NotNullFieldNotInitializedInspection;
|
||||
import com.intellij.codeInspection.nullable.NullableStuffInspection;
|
||||
import com.intellij.java.analysis.JavaAnalysisBundle;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.module.Module;
|
||||
@@ -41,6 +42,7 @@ import one.util.streamex.EntryStream;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.PropertyKey;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
@@ -561,11 +563,10 @@ public class JSpecifyFilteredAnnotationTest extends LightJavaCodeInsightFixtureT
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reportProblem(@NotNull ProblemsHolder holder,
|
||||
@NotNull PsiElement anchor,
|
||||
LocalQuickFix @NotNull [] fixes,
|
||||
@NotNull String messageKey, Object... args) {
|
||||
switch (messageKey) {
|
||||
protected void reportProblem(@NotNull ProblemsHolder holder, @NotNull PsiElement anchor, @NotNull LocalQuickFix @NotNull [] fixes,
|
||||
@NotNull @PropertyKey(resourceBundle = JavaAnalysisBundle.BUNDLE) String descriptionKey, @NotNull Object @NotNull[] descriptionArgs,
|
||||
@NotNull @PropertyKey(resourceBundle = JavaAnalysisBundle.BUNDLE) String tooltipKey, @NotNull Object @NotNull[] tooltipArgs) {
|
||||
switch (descriptionKey) {
|
||||
case "inspection.nullable.problems.primitive.type.annotation", "inspection.nullable.problems.receiver.annotation",
|
||||
"inspection.nullable.problems.outer.type", "inspection.nullable.problems.at.reference.list",
|
||||
"inspection.nullable.problems.at.constructor", "inspection.nullable.problems.at.enum.constant" ->
|
||||
|
||||
+1
@@ -511,6 +511,7 @@ public class NullableStuffInspectionTest extends LightJavaCodeInsightFixtureTest
|
||||
|
||||
public void testReturnIncompatibilitiesWithGeneric() {
|
||||
myInspection.REPORT_NOT_NULL_TO_NULLABLE_CONFLICTS_IN_ASSIGNMENTS = true;
|
||||
addJSpecifyNullMarked(myFixture);
|
||||
setupTypeUseAnnotations("org.jspecify.annotations", myFixture);
|
||||
doTest();
|
||||
}
|
||||
|
||||
@@ -287,6 +287,8 @@ com.intellij.codeInspection.HintAction
|
||||
- com.intellij.codeInsight.intention.IntentionAction
|
||||
- fixSilently(com.intellij.openapi.editor.Editor):Z
|
||||
- a:showHint(com.intellij.openapi.editor.Editor):Z
|
||||
a:com.intellij.codeInspection.InspectionManager
|
||||
- a:createProblemDescriptor(com.intellij.psi.PsiElement,com.intellij.openapi.util.TextRange,java.lang.String,com.intellij.codeInspection.ProblemHighlightType,java.lang.String,Z,com.intellij.codeInspection.LocalQuickFix[]):com.intellij.codeInspection.ProblemDescriptor
|
||||
com.intellij.codeInspection.InspectionProfile
|
||||
- java.lang.Comparable
|
||||
- sf:DEFAULT_PROFILE_NAME:java.lang.String
|
||||
@@ -347,6 +349,8 @@ com.intellij.codeInspection.ProblemDescriptor
|
||||
- a:setProblemGroup(com.intellij.lang.annotation.ProblemGroup):V
|
||||
- a:setTextAttributes(com.intellij.openapi.editor.colors.TextAttributesKey):V
|
||||
- a:showTooltip():Z
|
||||
f:com.intellij.codeInspection.ProblemsHolder$ProblemBuilder
|
||||
- tooltip(java.lang.String):com.intellij.codeInspection.ProblemsHolder$ProblemBuilder
|
||||
com.intellij.codeInspection.QuickFix
|
||||
- com.intellij.openapi.application.WriteActionAware
|
||||
- sf:EMPTY_ARRAY:com.intellij.codeInspection.QuickFix[]
|
||||
|
||||
@@ -81,6 +81,14 @@ public abstract class InspectionManager {
|
||||
boolean onTheFly,
|
||||
@NotNull LocalQuickFix @Nullable ... fixes);
|
||||
|
||||
public abstract @NotNull ProblemDescriptor createProblemDescriptor(@NotNull PsiElement psiElement,
|
||||
@Nullable("null means the text range of the element") TextRange rangeInElement,
|
||||
@NotNull @InspectionMessage String descriptionTemplate,
|
||||
@NotNull ProblemHighlightType highlightType,
|
||||
@NotNull String tooltipMessage,
|
||||
boolean onTheFly,
|
||||
@NotNull LocalQuickFix @Nullable ... fixes);
|
||||
|
||||
@Contract(pure = true)
|
||||
public abstract @NotNull ProblemDescriptor createProblemDescriptor(@NotNull PsiElement psiElement,
|
||||
@NotNull @InspectionMessage String descriptionTemplate,
|
||||
|
||||
@@ -244,10 +244,12 @@ public class ProblemsHolder {
|
||||
private @NotNull ProblemHighlightType myHighlightType = ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
|
||||
private @Nullable TextRange myRange;
|
||||
private final @NotNull List<LocalQuickFix> myFixes = new ArrayList<>();
|
||||
private @NotNull String myTooltip;
|
||||
|
||||
private ProblemBuilder(@NotNull PsiElement element, @InspectionMessage @NotNull String template) {
|
||||
myPsiElement = element;
|
||||
myDescriptionTemplate = template;
|
||||
myTooltip = myDescriptionTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,8 +316,24 @@ public class ProblemsHolder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tooltip a message that is visible in the editor. It might contain HTML markup.
|
||||
* @return this builder
|
||||
*/
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
public ProblemBuilder tooltip(@NotNull String tooltip) {
|
||||
myTooltip = tooltip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void register() {
|
||||
registerProblem(myPsiElement, myDescriptionTemplate, myHighlightType, myRange, myFixes.toArray(LocalQuickFix.EMPTY_ARRAY));
|
||||
ProblemDescriptor descriptor = getManager()
|
||||
.createProblemDescriptor(myPsiElement,
|
||||
myRange,
|
||||
myDescriptionTemplate,
|
||||
myHighlightType, myTooltip, myOnTheFly,
|
||||
myFixes.toArray(LocalQuickFix.EMPTY_ARRAY));
|
||||
registerProblem(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,6 +246,8 @@ com.intellij.codeInsight.template.impl.TemplateOptionalProcessor
|
||||
com.intellij.codeInsight.template.impl.TemplatePreprocessor
|
||||
- sf:EP_NAME:com.intellij.openapi.extensions.ExtensionPointName
|
||||
- a:preprocessTemplate(com.intellij.openapi.editor.Editor,com.intellij.psi.PsiFile,I,java.lang.String,java.lang.String):V
|
||||
a:com.intellij.codeInspection.InspectionManagerBase
|
||||
- createProblemDescriptor(com.intellij.psi.PsiElement,com.intellij.openapi.util.TextRange,java.lang.String,com.intellij.codeInspection.ProblemHighlightType,java.lang.String,Z,com.intellij.codeInspection.LocalQuickFix[]):com.intellij.codeInspection.ProblemDescriptor
|
||||
com.intellij.codeInspection.InspectionToolResultExporter
|
||||
- com.intellij.codeInspection.ProblemDescriptionsProcessor
|
||||
- a:addProblemElement(com.intellij.codeInspection.reference.RefEntity,Z,com.intellij.codeInspection.CommonProblemDescriptor[]):V
|
||||
|
||||
@@ -98,6 +98,18 @@ public abstract class InspectionManagerBase extends InspectionManager {
|
||||
return new ProblemDescriptorBase(psiElement, psiElement, descriptionTemplate, fixes, highlightType, false, rangeInElement, tooltip, onTheFly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ProblemDescriptor createProblemDescriptor(@NotNull PsiElement psiElement,
|
||||
@Nullable("null means the text range of the element") TextRange rangeInElement,
|
||||
@NotNull String descriptionTemplate,
|
||||
@NotNull ProblemHighlightType highlightType,
|
||||
@Nullable String tooltipMessage,
|
||||
boolean onTheFly,
|
||||
@NotNull LocalQuickFix @Nullable ... fixes) {
|
||||
boolean showTooltip = highlightType != ProblemHighlightType.INFORMATION;
|
||||
return new ProblemDescriptorBase(psiElement, psiElement, descriptionTemplate, fixes, highlightType, false, rangeInElement, showTooltip, onTheFly, tooltipMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ProblemDescriptor createProblemDescriptor(@NotNull PsiElement psiElement,
|
||||
@NotNull @InspectionMessage String descriptionTemplate,
|
||||
|
||||
Reference in New Issue
Block a user