Java: add synthetic default constructor on resolve (IDEA-376799)

GitOrigin-RevId: 71d783efd5095b0995ac1788863c8a50de759f77
This commit is contained in:
Bas Leijdekkers
2025-10-07 18:33:10 +00:00
committed by intellij-monorepo-bot
parent f0b97cbcd3
commit cd8ada5c65
41 changed files with 271 additions and 253 deletions
@@ -287,7 +287,6 @@ new.expression.diamond.not.applicable=Diamond operator is not applicable to non-
new.expression.diamond.inference.failure={0}
new.expression.diamond.anonymous.inner.non.private=Cannot use '<>' due to a non-private method which doesn't override or implement a method from a supertype
new.expression.anonymous.implements.interface.with.type.arguments=Anonymous class implements interface; cannot have type arguments
new.expression.arguments.to.default.constructor.call=Default constructor is invoked with arguments
new.expression.unresolved.constructor=Cannot resolve constructor ''{0}''
new.expression.type.parameter=Type parameter ''{0}'' cannot be instantiated directly
@@ -19,7 +19,6 @@ import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.impl.IncompleteModelUtil;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ImplicitClassSearch;
@@ -259,13 +258,11 @@ final class ExpressionChecker {
void checkMethodCall(@NotNull PsiMethodCallExpression methodCall) {
PsiExpressionList list = methodCall.getArgumentList();
PsiReferenceExpression referenceToMethod = methodCall.getMethodExpression();
JavaResolveResult[] results = referenceToMethod.multiResolve(true);
JavaResolveResult resolveResult = results.length == 1 ? results[0] : JavaResolveResult.EMPTY;
PsiElement resolved = resolveResult.getElement();
boolean isDummy = isDummyConstructorCall(methodCall, list, referenceToMethod);
if (isDummy) return;
PsiSubstitutor substitutor = resolveResult.getSubstitutor();
if (resolved instanceof PsiMethod psiMethod && resolveResult.isValidResult()) {
checkUnhandledExceptions(methodCall);
@@ -411,13 +408,12 @@ final class ExpressionChecker {
if (!(type instanceof PsiClassType classType)) return;
PsiClassType.ClassResolveResult typeResult = classType.resolveGenerics();
PsiClass aClass = typeResult.getElement();
if (aClass == null) return;
if (aClass instanceof PsiAnonymousClass anonymousClass) {
classType = anonymousClass.getBaseClassType();
typeResult = classType.resolveGenerics();
aClass = typeResult.getElement();
if (aClass == null) return;
}
if (aClass == null || aClass instanceof PsiTypeParameter) return;
PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
checkConstructorCall(typeResult, expression, classReference);
@@ -1126,23 +1122,6 @@ final class ExpressionChecker {
myVisitor.report(JavaErrorKinds.EXCEPTION_UNHANDLED.create(element, unhandled));
}
boolean isDummyConstructorCall(@NotNull PsiMethodCallExpression methodCall,
@NotNull PsiExpressionList list,
@NotNull PsiReferenceExpression referenceToMethod) {
boolean isThisOrSuper = referenceToMethod.getReferenceNameElement() instanceof PsiKeyword;
if (isThisOrSuper) {
// super(..) or this(..)
if (list.isEmpty()) { // implicit ctr call
CandidateInfo[] candidates = PsiResolveHelper.getInstance(myVisitor.project())
.getReferencedMethodCandidates(methodCall, true);
if (candidates.length == 1 && !candidates[0].getElement().isPhysical()) {
return true; // dummy constructor
}
}
}
return false;
}
void checkConstructorCall(@NotNull PsiClassType.ClassResolveResult typeResolveResult,
@NotNull PsiConstructorCall constructorCall,
@Nullable PsiJavaCodeReferenceElement classReference) {
@@ -1163,11 +1142,8 @@ final class ExpressionChecker {
}
PsiMethod[] constructors = aClass.getConstructors();
if (constructors.length == 0) {
if (!list.isEmpty()) {
myVisitor.report(JavaErrorKinds.NEW_EXPRESSION_ARGUMENTS_TO_DEFAULT_CONSTRUCTOR_CALL.create(constructorCall));
}
else if (classReference != null && aClass.hasModifierProperty(PsiModifier.PROTECTED) &&
callingProtectedConstructorFromDerivedClass(constructorCall, aClass)) {
if (classReference != null && aClass.hasModifierProperty(PsiModifier.PROTECTED) &&
callingProtectedConstructorFromDerivedClass(constructorCall, aClass)) {
myVisitor.myModifierChecker.reportAccessProblem(classReference, aClass, typeResolveResult);
}
else if (aClass.isInterface() && constructorCall instanceof PsiNewExpression newExpression) {
@@ -1175,8 +1151,8 @@ final class ExpressionChecker {
if (typeArgumentList.getTypeArguments().length > 0) {
myVisitor.report(JavaErrorKinds.NEW_EXPRESSION_ANONYMOUS_IMPLEMENTS_INTERFACE_WITH_TYPE_ARGUMENTS.create(typeArgumentList));
}
return;
}
return;
}
JavaResolveResult[] results = constructorCall.multiResolve(false);
MethodCandidateInfo result = null;
@@ -1216,7 +1192,7 @@ final class ExpressionChecker {
constructorCall, new JavaErrorKinds.UnresolvedConstructorContext(aClass, results)));
return;
}
if (classReference != null &&
if (classReference != null && !constructor.isDefaultConstructor() &&
(!result.isAccessible() ||
constructor.hasModifierProperty(PsiModifier.PROTECTED) && callingProtectedConstructorFromDerivedClass(constructorCall, aClass))) {
myVisitor.myModifierChecker.reportAccessProblem(classReference, constructor, result);
@@ -313,7 +313,9 @@ final class GenericsChecker {
if (targetParametersNum == 0) {
boolean shouldSuppress = PsiTreeUtil.getParentOfType(referenceParameterList, PsiCall.class) != null &&
typeParameterListOwner instanceof PsiMethod psiMethod &&
(myVisitor.sdkVersion().isAtLeast(JavaSdkVersion.JDK_1_7) || hasSuperMethodsWithTypeParams(psiMethod));
(myVisitor.sdkVersion().isAtLeast(JavaSdkVersion.JDK_1_7)
|| hasSuperMethodsWithTypeParams(psiMethod)
|| psiMethod.isDefaultConstructor());
if (!shouldSuppress) {
if (typeParameterListOwner instanceof PsiMethod psiMethod) {
myVisitor.report(JavaErrorKinds.TYPE_PARAMETER_ABSENT_METHOD.create(referenceParameterList, psiMethod));
@@ -827,14 +827,11 @@ final class JavaErrorVisitor extends JavaElementVisitor {
if (parent instanceof PsiMethodCallExpression methodCallExpression &&
methodCallExpression.getMethodExpression() == expression &&
(!result.isAccessible() || !result.isStaticsScopeCorrect())) {
PsiExpressionList list = methodCallExpression.getArgumentList();
if (!myExpressionChecker.isDummyConstructorCall(methodCallExpression, list, expression)) {
myExpressionChecker.checkAmbiguousMethodCallIdentifier(results, result, methodCallExpression);
if (!PsiTreeUtil.findChildrenOfType(methodCallExpression.getArgumentList(), PsiLambdaExpression.class).isEmpty()) {
PsiElement nameElement = expression.getReferenceNameElement();
if (nameElement != null) {
myExpressionChecker.checkAmbiguousMethodCallArguments(results, result, methodCallExpression);
}
myExpressionChecker.checkAmbiguousMethodCallIdentifier(results, result, methodCallExpression);
if (!PsiTreeUtil.findChildrenOfType(methodCallExpression.getArgumentList(), PsiLambdaExpression.class).isEmpty()) {
PsiElement nameElement = expression.getReferenceNameElement();
if (nameElement != null) {
myExpressionChecker.checkAmbiguousMethodCallArguments(results, result, methodCallExpression);
}
}
}
@@ -1221,7 +1218,6 @@ final class JavaErrorVisitor extends JavaElementVisitor {
JavaResolveResult result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY;
if ((!result.isAccessible() || !result.isStaticsScopeCorrect()) &&
!myExpressionChecker.isDummyConstructorCall(expression, list, referenceExpression) &&
// this check is for fake expression from JspMethodCallImpl
referenceExpression.getParent() == expression &&
PsiTreeUtil.findChildrenOfType(expression.getArgumentList(), PsiLambdaExpression.class).isEmpty()) {
@@ -1126,10 +1126,6 @@ public final class JavaErrorKinds {
parameterized(PsiReferenceParameterList.class, PsiDiamondType.DiamondInferenceResult.class, "new.expression.diamond.inference.failure")
.withDescription(
(list, inferenceResult) -> message("new.expression.diamond.inference.failure", inferenceResult.getErrorMessage()));
public static final Simple<PsiConstructorCall> NEW_EXPRESSION_ARGUMENTS_TO_DEFAULT_CONSTRUCTOR_CALL =
error(PsiConstructorCall.class, "new.expression.arguments.to.default.constructor.call")
.withAnchor(call -> call.getArgumentList())
.withNavigationShift(1);
public static final Parameterized<PsiConstructorCall, UnresolvedConstructorContext> NEW_EXPRESSION_UNRESOLVED_CONSTRUCTOR =
parameterized(PsiConstructorCall.class, UnresolvedConstructorContext.class, "new.expression.unresolved.constructor")
.withAnchor(PsiCall::getArgumentList)