mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-48678: No error message when there is no default constructor in superclass
This commit is contained in:
@@ -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> {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user