check constructor only implicitly called constructor (IDEA-164500)

This commit is contained in:
Anna.Kozlova
2016-11-25 12:50:54 +01:00
parent 9049591435
commit df3abfd8c3
3 changed files with 53 additions and 59 deletions
@@ -527,70 +527,24 @@ public class HighlightClassUtil {
PsiMethod[] constructors = baseClass.getConstructors();
if (constructors.length == 0) return null;
final HighlightInfo highlightInfo = constructors.length > 1 ? checkAmbiguityOfImplicitConstructorCall(constructors, range, aClass, baseClass) : null;
if (highlightInfo != null) {
return highlightInfo;
}
for (PsiMethod constructor : constructors) {
if (resolveHelper.isAccessible(constructor, aClass, null)) {
if (constructor.getParameterList().getParametersCount() == 0 ||
constructor.getParameterList().getParametersCount() == 1 && constructor.isVarArgs()
) {
// it is an error if base ctr throws exceptions
String description = checkDefaultConstructorThrowsException(constructor, handledExceptions);
if (description != null) {
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(description).create();
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createCreateConstructorMatchingSuperFix(aClass));
return info;
}
if (refCountHolder != null) {
refCountHolder.registerLocallyReferenced(constructor);
}
return null;
}
}
}
String description = JavaErrorMessages.message("no.default.constructor.available", HighlightUtil.formatClass(baseClass));
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(description).create();
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createCreateConstructorMatchingSuperFix(aClass));
return info;
}
@Nullable
private static HighlightInfo checkAmbiguityOfImplicitConstructorCall(@NotNull PsiMethod[] constructors,
@NotNull TextRange range,
@NotNull PsiClass subClass,
@NotNull PsiClass superClass) {
Project project = subClass.getProject();
PsiElement resolved = JavaResolveUtil.resolveImaginarySuperCallInThisPlace(subClass, project, superClass);
if (resolved != null) {
return null;
}
// find two ambiguous var-args-only constructors
List<PsiMethod> varargConstructors = Arrays.stream(constructors)
.filter(constructor -> constructor.getParameterList().getParameters().length == 1)
.filter(constructor -> constructor.getParameterList().getParameters()[0].isVarArgs())
.filter(constructor -> PsiResolveHelper.SERVICE.getInstance(project).isAccessible(constructor, subClass, subClass))
PsiElement resolved = JavaResolveUtil.resolveImaginarySuperCallInThisPlace(aClass, aClass.getProject(), baseClass);
List<PsiMethod> constructorCandidates = (resolved != null ? Collections.singletonList((PsiMethod)resolved)
: Arrays.asList(constructors))
.stream()
.filter(constructor -> {
PsiParameter[] parameters = constructor.getParameterList().getParameters();
return (parameters.length == 0 || parameters.length == 1 && parameters[0].isVarArgs()) &&
resolveHelper.isAccessible(constructor, aClass, null);
})
.limit(2).collect(Collectors.toList());
//List<PsiMethod> varargConstructors = Arrays.stream(constructors)
// .map(constructor -> Pair.create(constructor, constructor.getParameterList().getParameters()))
// .filter(p -> p.second.length == 1 && p.second[0].isVarArgs() && PsiResolveHelper.SERVICE.getInstance(project).isAccessible(p.first, subClass, subClass))
// .map(p -> p.first)
// .limit(2).collect(Collectors.toList());
//
if (varargConstructors.size() == 2) {
final String m1 = PsiFormatUtil.formatMethod(varargConstructors.get(0), PsiSubstitutor.EMPTY,
if (constructorCandidates.size() >= 2) {// two ambiguous var-args-only constructors
final String m1 = PsiFormatUtil.formatMethod(constructorCandidates.get(0), PsiSubstitutor.EMPTY,
PsiFormatUtilBase.SHOW_CONTAINING_CLASS |
PsiFormatUtilBase.SHOW_NAME |
PsiFormatUtilBase.SHOW_PARAMETERS,
PsiFormatUtilBase.SHOW_TYPE);
final String m2 = PsiFormatUtil.formatMethod(varargConstructors.get(1), PsiSubstitutor.EMPTY,
final String m2 = PsiFormatUtil.formatMethod(constructorCandidates.get(1), PsiSubstitutor.EMPTY,
PsiFormatUtilBase.SHOW_CONTAINING_CLASS |
PsiFormatUtilBase.SHOW_NAME |
PsiFormatUtilBase.SHOW_PARAMETERS,
@@ -600,7 +554,27 @@ public class HighlightClassUtil {
.descriptionAndTooltip(JavaErrorMessages.message("ambiguous.method.call", m1, m2))
.create();
}
return null;
if (!constructorCandidates.isEmpty()) {
PsiMethod constructor = constructorCandidates.get(0);
String description = checkDefaultConstructorThrowsException(constructor, handledExceptions);
if (description != null) {
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(description).create();
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createCreateConstructorMatchingSuperFix(aClass));
return info;
}
if (refCountHolder != null) {
refCountHolder.registerLocallyReferenced(constructor);
}
return null;
}
String description = JavaErrorMessages.message("no.default.constructor.available", HighlightUtil.formatClass(baseClass));
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(description).create();
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createCreateConstructorMatchingSuperFix(aClass));
return info;
}
@Nullable
@@ -0,0 +1,17 @@
class Base {
String[] items;
public Base(String ... items) throws Exception {
this.items = items;
}
public Base() {
this.items = null;
}
}
class Derived extends Base {
public Derived() {}
}
class Derived1 extends Base {}
@@ -86,4 +86,7 @@ public class LightAdvHighlightingJdk6Test extends LightDaemonAnalyzerTestCase {
public void testAmbiguityChecksForImplicitSuperConstructorCall() {
doTest(false, false);
}
public void testSpeculateOnUnhandledExceptionsOverResolvedConstructorOnly() throws Exception {
}
}