mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Error highlighting for records: compact constructors (8.10.5) IDEA-228460
GitOrigin-RevId: d2ffbe570a06768989e48bf88eaf503a847574d4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
662cb5deae
commit
53986a2bd7
+1
@@ -247,6 +247,7 @@ public class HighlightControlFlowUtil {
|
||||
PsiField field = JavaPsiRecordUtil.getFieldForComponent(component);
|
||||
if (field == null) return null;
|
||||
if (variableDefinitelyAssignedIn(field, body)) return null;
|
||||
if (JavaPsiRecordUtil.isCompactConstructor(canonicalConstructor) && variableDefinitelyNotAssignedIn(field, body)) return null;
|
||||
String description = JavaErrorMessages.message("record.component.not.initialized", field.getName());
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(identifier).descriptionAndTooltip(description).create();
|
||||
}
|
||||
|
||||
+4
-1
@@ -1277,7 +1277,8 @@ public class HighlightMethodUtil {
|
||||
if (codeBlock instanceof PsiCodeBlock) {
|
||||
PsiMethod ctor = ObjectUtils.tryCast(codeBlock.getParent(), PsiMethod.class);
|
||||
if (ctor != null && ctor.isConstructor()) {
|
||||
if (JavaPsiRecordUtil.isCanonicalConstructor(ctor)) {
|
||||
if (JavaPsiRecordUtil.isCompactConstructor(ctor) ||
|
||||
JavaPsiRecordUtil.isCanonicalConstructor(ctor)) {
|
||||
String message = JavaErrorMessages.message("record.constructor.call.in.canonical");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(methodCall).descriptionAndTooltip(message).create();
|
||||
}
|
||||
@@ -1967,6 +1968,8 @@ public class HighlightMethodUtil {
|
||||
}
|
||||
}
|
||||
return checkRecordSpecialMethodDeclaration(method, JavaErrorMessages.message("record.canonical.constructor"));
|
||||
} else if (JavaPsiRecordUtil.isCompactConstructor(method)) {
|
||||
return checkRecordSpecialMethodDeclaration(method, JavaErrorMessages.message("record.compact.constructor"));
|
||||
}
|
||||
else {
|
||||
// Non-canonical constructor
|
||||
|
||||
+12
-5
@@ -1648,11 +1648,18 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
try {
|
||||
PsiElement parent = PsiTreeUtil.getParentOfType(statement, PsiFile.class, PsiClassInitializer.class,
|
||||
PsiLambdaExpression.class, PsiMethod.class);
|
||||
HighlightInfo info = parent != null ? HighlightUtil.checkReturnStatementType(statement, parent) : null;
|
||||
if (info != null && parent instanceof PsiMethod) {
|
||||
PsiMethod method = (PsiMethod)parent;
|
||||
PsiType expectedType = myExpectedReturnTypes.computeIfAbsent(method, HighlightMethodUtil::determineReturnType);
|
||||
if (expectedType != null && !PsiType.VOID.equals(expectedType)) HighlightUtil.registerReturnTypeFixes(info, method, expectedType);
|
||||
HighlightInfo info;
|
||||
if (parent instanceof PsiMethod && JavaPsiRecordUtil.isCompactConstructor((PsiMethod)parent)) {
|
||||
info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement)
|
||||
.descriptionAndTooltip(JavaErrorMessages.message("record.compact.constructor.return")).create();
|
||||
} else {
|
||||
info = parent != null ? HighlightUtil.checkReturnStatementType(statement, parent) : null;
|
||||
if (info != null && parent instanceof PsiMethod) {
|
||||
PsiMethod method = (PsiMethod)parent;
|
||||
PsiType expectedType = myExpectedReturnTypes.computeIfAbsent(method, HighlightMethodUtil::determineReturnType);
|
||||
if (expectedType != null && !PsiType.VOID.equals(expectedType))
|
||||
HighlightUtil.registerReturnTypeFixes(info, method, expectedType);
|
||||
}
|
||||
}
|
||||
myHolder.add(info);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class JavaPsiRecordUtil {
|
||||
|
||||
/**
|
||||
* @param method method to check
|
||||
* @return true if given method is a canonical constructor for a record class
|
||||
* @return true if given method is a canonical (non-compact) constructor for a record class
|
||||
*/
|
||||
public static boolean isCanonicalConstructor(@NotNull PsiMethod method) {
|
||||
if (!method.isConstructor()) return false;
|
||||
@@ -78,8 +78,8 @@ public class JavaPsiRecordUtil {
|
||||
|
||||
/**
|
||||
* @param recordClass record class
|
||||
* @return first explicitly declared canonical constructor;
|
||||
* null if no canonical constructor declared or the supplied class is not a record
|
||||
* @return first explicitly declared canonical or compact constructor;
|
||||
* null if no canonical and compact constructor declared or the supplied class is not a record
|
||||
*/
|
||||
@Nullable
|
||||
public static PsiMethod findCanonicalConstructor(@NotNull PsiClass recordClass) {
|
||||
@@ -88,7 +88,7 @@ public class JavaPsiRecordUtil {
|
||||
if (constructors.length == 0) return null;
|
||||
PsiRecordComponent[] components = recordClass.getRecordComponents();
|
||||
for (PsiMethod constructor : constructors) {
|
||||
if (hasCanonicalSignature(constructor, components)) {
|
||||
if (isCompactConstructor(constructor) || hasCanonicalSignature(constructor, components)) {
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -928,6 +928,7 @@ public class ExceptionUtil {
|
||||
*/
|
||||
public static boolean canDeclareThrownExceptions(@NotNull PsiMethod method) {
|
||||
return JavaPsiRecordUtil.getRecordComponentForAccessor(method) == null &&
|
||||
!JavaPsiRecordUtil.isCompactConstructor(method) &&
|
||||
!JavaPsiRecordUtil.isCanonicalConstructor(method);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,9 +482,11 @@ record.special.method.type.parameters={0} cannot have type parameters
|
||||
record.special.method.non.public={0} must be ''public''
|
||||
record.special.method.throws={0} cannot declare thrown exceptions
|
||||
record.canonical.constructor=Canonical constructor
|
||||
record.compact.constructor=Compact constructor
|
||||
record.accessor=Record component accessor
|
||||
record.component.not.initialized=Record component ''{0}'' might not be initialized in canonical constructor
|
||||
compact.constructor.in.regular.class=Parameter list expected
|
||||
record.compact.constructor.return='return' statement is not allowed in compact constructor
|
||||
|
||||
feature.generics=Generics
|
||||
feature.annotations=Annotations
|
||||
|
||||
+46
@@ -1,5 +1,51 @@
|
||||
class NotRecord {
|
||||
public <error descr="Parameter list expected">NotRecord</error> {
|
||||
|
||||
}
|
||||
}
|
||||
record NonPublic(int x) {
|
||||
<error descr="Compact constructor must be 'public'">NonPublic</error> {
|
||||
|
||||
}
|
||||
}
|
||||
record Throws(int x) {
|
||||
public Throws<error descr="Identifier expected"> </error><error descr="Unexpected token">throws</error> <error descr="Invalid method declaration; return type required">Throwable</error> {}
|
||||
}
|
||||
record Generic() {
|
||||
public <error descr="Canonical constructor cannot have type parameters"><T></error> Generic() {}
|
||||
}
|
||||
record Delegate(int x) {
|
||||
public Delegate {
|
||||
<error descr="Canonical constructor cannot delegate to another constructor">this("")</error>;
|
||||
}
|
||||
<error descr="Non-canonical record constructor must delegate to another constructor">Delegate</error>(String s) {
|
||||
|
||||
}
|
||||
}
|
||||
record ReturnInCompact(int x) {
|
||||
public ReturnInCompact {
|
||||
if (Math.random() > 0.5) <error descr="'return' statement is not allowed in compact constructor">return;</error>
|
||||
}
|
||||
}
|
||||
record NotInitialized(int x,
|
||||
int <error descr="Record component 'y' might not be initialized in canonical constructor">y</error>,
|
||||
int z) {
|
||||
public NotInitialized {
|
||||
this.x = 0;
|
||||
if (Math.random() > 0.5) this.y = 1;
|
||||
}
|
||||
}
|
||||
record TwoCompacts(int x, int y) {
|
||||
<error descr="'TwoCompacts()' is already defined in 'TwoCompacts'">public TwoCompacts </error>{}
|
||||
<error descr="'TwoCompacts()' is already defined in 'TwoCompacts'">public TwoCompacts </error>{}
|
||||
}
|
||||
record CompactAndCanonical(int x, int y) {
|
||||
// TODO
|
||||
public CompactAndCanonical(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
public CompactAndCanonical {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
record A(String s) {
|
||||
A {
|
||||
public A {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -129,9 +129,11 @@ public class ChangeModifierIntention extends BaseElementAtCaretIntentionAction {
|
||||
return ALL_MODIFIERS;
|
||||
}
|
||||
if (member instanceof PsiMethod) {
|
||||
if (containingClass == null || containingClass.isEnum() && ((PsiMethod)member).isConstructor()) return Collections.emptyList();
|
||||
if (JavaPsiRecordUtil.getRecordComponentForAccessor((PsiMethod)member) != null ||
|
||||
JavaPsiRecordUtil.isCanonicalConstructor((PsiMethod)member)) {
|
||||
PsiMethod method = (PsiMethod)member;
|
||||
if (containingClass == null || containingClass.isEnum() && method.isConstructor()) return Collections.emptyList();
|
||||
if (JavaPsiRecordUtil.getRecordComponentForAccessor(method) != null ||
|
||||
JavaPsiRecordUtil.isCompactConstructor(method) ||
|
||||
JavaPsiRecordUtil.isCanonicalConstructor(method)) {
|
||||
return Collections.singletonList(AccessModifier.PUBLIC);
|
||||
}
|
||||
if (containingClass.isInterface()) {
|
||||
@@ -140,7 +142,7 @@ public class ChangeModifierIntention extends BaseElementAtCaretIntentionAction {
|
||||
}
|
||||
return Collections.singletonList(AccessModifier.PUBLIC);
|
||||
}
|
||||
AccessModifier minAccess = getMinAccess((PsiMethod)member);
|
||||
AccessModifier minAccess = getMinAccess(method);
|
||||
if (minAccess != AccessModifier.PRIVATE) {
|
||||
return ContainerUtil.filter(ALL_MODIFIERS, mod -> mod.compareTo(minAccess) <= 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user