IDEA-48678: No error message when there is no default constructor in superclass

This commit is contained in:
Maxim Medvedev
2010-06-28 14:43:46 +04:00
parent bc38d5eade
commit 9eb540d2a7
4 changed files with 77 additions and 3 deletions
@@ -340,3 +340,4 @@ method.doesnot.override.super=Method does not override method from its super cla
method.duplicate=Method with signature {0} is already defined in the class ''{1}''
ambiguous.code.block=Ambiguous code block
cyclic.inheritance.involving.0=Cyclic inheritance involving ''{0}''
there.is.no.default.constructor.available.in.class.0=There is no default constructor available in class ''{0}''
@@ -281,6 +281,41 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
final GrTypeDefinitionBody body = typeDefinition.getBody();
if (body != null) checkDuplicateMethod(body.getGroovyMethods(), myHolder);
checkImplementedMethodsOfClass(myHolder, typeDefinition);
checkConstructors(myHolder, typeDefinition);
}
private static void checkConstructors(AnnotationHolder holder, GrTypeDefinition typeDefinition) {
if (typeDefinition.isEnum() || typeDefinition.isInterface() || typeDefinition.isAnonymous()) return;
final PsiClass superClass = typeDefinition.getSuperClass();
if (superClass == null) return;
PsiMethod defConstructor = getDefaultConstructor(superClass);
boolean hasImplicitDefConstructor = superClass.getConstructors().length ==0;
final PsiMethod[] constructors = typeDefinition.getConstructors();
final String qName = superClass.getQualifiedName();
if (constructors.length == 0) {
if (!hasImplicitDefConstructor && (defConstructor == null || !PsiUtil.isAccessible(typeDefinition, defConstructor))) {
final TextRange range = getHeaderTextRange(typeDefinition);
holder.createErrorAnnotation(range, GroovyBundle.message("there.is.no.default.constructor.available.in.class.0", qName));
}
return;
}
for (PsiMethod method : constructors) {
if (method instanceof GrMethod) {
final GrOpenBlock block = ((GrMethod)method).getBlock();
if (block == null) continue;
final GrStatement[] statements = block.getStatements();
if (statements.length > 0) {
if (statements[0] instanceof GrConstructorInvocation) continue;
}
if (!hasImplicitDefConstructor && (defConstructor == null || !PsiUtil.isAccessible(typeDefinition, defConstructor))) {
final TextRange range = getMethodHeaderTextRange((GrMethod)method);
holder.createErrorAnnotation(range, GroovyBundle.message("there.is.no.default.constructor.available.in.class.0", qName));
}
}
}
}
@Override
@@ -289,6 +324,18 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
checkInnerMethod(myHolder, method);
}
@Nullable
private static PsiMethod getDefaultConstructor(PsiClass clazz) {
final String className = clazz.getName();
if (className == null) return null;
final PsiMethod[] byName = clazz.findMethodsByName(className, true);
if (byName.length == 0) return null;
for (PsiMethod method : byName) {
if (method.getParameterList().getParametersCount() == 0) return method;
}
return null;
}
@Override
public void visitVariableDeclaration(GrVariableDeclaration variableDeclaration) {
@@ -753,13 +800,26 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
assert element instanceof PsiNamedElement;
String notImplementedMethodName = ((PsiNamedElement)element).getName();
final int startOffset = typeDefinition.getTextOffset();
int endOffset = typeDefinition.getNameIdentifierGroovy().getTextRange().getEndOffset();
final Annotation annotation = holder.createErrorAnnotation(new TextRange(startOffset, endOffset),
final TextRange range = getHeaderTextRange(typeDefinition);
final Annotation annotation = holder.createErrorAnnotation(range,
GroovyBundle.message("method.is.not.implemented", notImplementedMethodName));
registerImplementsMethodsFix(typeDefinition, annotation);
}
private static TextRange getHeaderTextRange(GrNamedElement namedElement) {
final int startOffset = namedElement.getTextOffset();
int endOffset = namedElement.getNameIdentifierGroovy().getTextRange().getEndOffset();
return new TextRange(startOffset, endOffset);
}
private static TextRange getMethodHeaderTextRange(GrMethod method) {
final int startOffset = method.getTextOffset();
final ASTNode node = method.getNode().findChildByType(GroovyTokenTypes.mRPAREN);
assert node != null;
int endOffset = node.getTextRange().getEndOffset();
return new TextRange(startOffset, endOffset);
}
private static void registerImplementsMethodsFix(GrTypeDefinition typeDefinition, Annotation annotation) {
annotation.registerFix(new ImplementMethodsQuickFix(typeDefinition));
}
@@ -251,4 +251,6 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase {
public void testDuplicateParameterInClosableBlock() throws Exception {doTest();}
public void testCyclicInheritance() throws Exception {doTest();}
public void testNoDefaultConstructor() throws Exception {doTest();}
}
@@ -0,0 +1,11 @@
class X {
X(int a) {}
}
class Y extends X {
<error descr="There is no default constructor available in class 'X'">Y()</error> {
}
}