IDEA-56195 Groovy 1.7.3: check if class is annotated with @InheritConstructors

This commit is contained in:
Maxim Medvedev
2010-07-03 11:51:24 +04:00
parent 2950544d15
commit a2c358c27d
17 changed files with 200 additions and 14 deletions
+1
View File
@@ -51,6 +51,7 @@
<membersContributor implementation="org.jetbrains.plugins.groovy.lang.psi.impl.GdkMembersContributor"/>
<membersContributor implementation="org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicMembersContributor"/>
<membersContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.noncode.ImmutableAnnotationProcessor"/>
<membersContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.noncode.GrInheritConstructorContributor"/>
<libraryManager implementation="org.jetbrains.plugins.groovy.config.GroovyLibraryManager"/>
<libraryManager implementation="org.jetbrains.plugins.groovy.gant.GantLibraryManager" order="last"/>
<libraryManager implementation="org.jetbrains.plugins.groovy.gradle.GradleLibraryManager" order="last"/>
@@ -91,6 +91,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import org.jetbrains.plugins.groovy.lang.resolve.noncode.GrInheritConstructorContributor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor;
import org.jetbrains.plugins.groovy.overrideImplement.GroovyOverrideImplementUtil;
import org.jetbrains.plugins.groovy.overrideImplement.quickFix.ImplementMethodsQuickFix;
@@ -289,6 +290,8 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
final PsiClass superClass = typeDefinition.getSuperClass();
if (superClass == null) return;
if (GrInheritConstructorContributor.hasInheritConstructorsAnnotation(typeDefinition)) return;
PsiMethod defConstructor = getDefaultConstructor(superClass);
boolean hasImplicitDefConstructor = superClass.getConstructors().length ==0;
@@ -32,6 +32,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
@@ -48,6 +49,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClassTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils.*;
@@ -287,7 +289,14 @@ public class GroovyCompletionUtil {
}
public static boolean hasConstructorParameters(PsiClass clazz) {
final PsiMethod[] constructors = clazz.getConstructors();
final PsiMethod[] constructors;
if (clazz instanceof GroovyPsiElement) {
constructors = ResolveUtil.getAllClassConstructors(clazz, (GroovyPsiElement)clazz, PsiSubstitutor.EMPTY);
}
else {
constructors = clazz.getConstructors();
}
for (PsiMethod constructor : constructors) {
if (constructor.getParameterList().getParametersCount() > 0) return true;
}
@@ -30,6 +30,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationNameValuePair;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression;
@@ -37,6 +38,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import java.util.Arrays;
@@ -114,7 +116,7 @@ public class GroovyInsertHandler implements InsertHandler<LookupElement> {
parent.getParent() instanceof GrNewExpression &&
(offset == text.length() || !text.substring(offset).trim().startsWith("("))) {
document.insertString(offset, "()");
final PsiMethod[] methods = clazz.getConstructors();
final PsiMethod[] methods = ResolveUtil.getAllClassConstructors(clazz, (GroovyPsiElement)parent, PsiSubstitutor.EMPTY);
for (PsiMethod method : methods) {
if (method.getParameterList().getParameters().length > 0) {
caretModel.moveToOffset(offset + 1);
@@ -28,11 +28,12 @@ import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
/**
* @author Maxim.Medvedev
@@ -47,13 +48,16 @@ public class AfterNewClassInsertHandler implements InsertHandler<LookupItem<PsiC
}
public void handleInsert(InsertionContext context, LookupItem<PsiClassType> item) {
final PsiClass psiClass = PsiUtil.resolveClassInType(myClassType);
final PsiClassType.ClassResolveResult resolveResult = myClassType.resolveGenerics();
final PsiClass psiClass = resolveResult.getElement();
if (psiClass == null || !psiClass.isValid()) {
return;
}
PsiMethod[] constructors = psiClass.getConstructors();
PsiElement place = myPlace;
if (!(place instanceof GroovyPsiElement)) {
place = myPlace.getContainingFile();
}
PsiMethod[] constructors = ResolveUtil.getAllClassConstructors(psiClass, (GroovyPsiElement)place, resolveResult.getSubstitutor());
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(psiClass.getProject()).getResolveHelper();
boolean hasParams = ContainerUtil.or(constructors, new Condition<PsiMethod>() {
public boolean value(PsiMethod psiMethod) {
@@ -151,8 +155,8 @@ public class AfterNewClassInsertHandler implements InsertHandler<LookupItem<PsiC
manager.commitDocument(document);
final PsiReference ref = file.findReferenceAt(offset);
if (ref instanceof GrCodeReferenceElement) {
org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.shortenReference((GrCodeReferenceElement)ref);
org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.shortenReferences((GroovyPsiElement)ref);
PsiUtil.shortenReference((GrCodeReferenceElement)ref);
PsiUtil.shortenReferences((GroovyPsiElement)ref);
}
}
}
@@ -38,8 +38,10 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path.GrCallExpressionImpl;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@@ -193,6 +195,8 @@ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewEx
boolean isAccessible = helper.isAccessible(constructor, this, null);
result.add(new GroovyResolveResultImpl(constructor, null, classResult.getSubstitutor(), isAccessible, true));
}
final GroovyResolveResult[] results = ResolveUtil.getNonCodeConstructors((PsiClass)element, this, classResult.getSubstitutor());
result.addAll(Arrays.asList(results));
}
}
@@ -158,7 +158,7 @@ public class GrClosureSignatureUtil {
}
if (cur == params.length) return null;
if (params[cur].isOptional()) optionalArgs--;
if (!TypesUtil.isAssignable(params[cur].getType(), typeComputer.fun(args[i]), context, false)) return null;
if (!TypesUtil.isAssignableByMethodCallConversion(params[cur].getType(), typeComputer.fun(args[i]), context)) return null;
map[cur] = new ArgInfo<Arg>(args[i]);
}
for (int i = 0; i < map.length; i++) {
@@ -222,7 +222,7 @@ public class GrClosureSignatureUtil {
if (curParam == paramLength) break;
if (params[curParam].isOptional()) {
if (TypesUtil.isAssignable(params[curParam].getType(), types[curArg], context, false) &&
if (TypesUtil.isAssignableByMethodCallConversion(params[curParam].getType(), types[curArg], context) &&
isApplicableInternal(curParam + 1, curArg + 1, false, notOptional)) {
map[curParam] = new ArgInfo<Arg>(args[curArg]);
return true;
@@ -230,7 +230,7 @@ public class GrClosureSignatureUtil {
skipOptionals = true;
}
else {
if (!TypesUtil.isAssignable(params[curParam].getType(), types[curArg], context, false)) {
if (!TypesUtil.isAssignableByMethodCallConversion(params[curParam].getType(), types[curArg], context)) {
for (int i = startParam; i < curParam; i++) map[i] = null;
return false;
}
@@ -243,7 +243,7 @@ public class GrClosureSignatureUtil {
List<Arg> varargs = new ArrayList<Arg>();
for (; curArg < args.length; curArg++) {
if (!TypesUtil.isAssignable(vararg, types[curArg], context, false)) {
if (!TypesUtil.isAssignableByMethodCallConversion(vararg, types[curArg], context)) {
for (int i = startParam; i < curParam; i++) map[i] = null;
return false;
}
@@ -51,6 +51,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGd
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassResolverProcessor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
@@ -503,4 +504,27 @@ public class ResolveUtil {
}
return variants;
}
public static GroovyResolveResult[] getNonCodeConstructors(PsiClass psiClass, GroovyPsiElement place, PsiSubstitutor substitutor) {
final PsiClassType qualifierType = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass);
final MethodResolverProcessor processor = new MethodResolverProcessor(psiClass.getName(), place, true, null, null, PsiType.EMPTY_ARRAY);
NonCodeMembersContributor
.runContributors(qualifierType, processor, place, ResolveState.initial().put(PsiSubstitutor.KEY, substitutor));
return processor.getCandidates();
}
public static PsiMethod[] getAllClassConstructors(PsiClass psiClass, GroovyPsiElement place, PsiSubstitutor substitutor) {
final PsiMethod[] realConstructors = psiClass.getConstructors();
final GroovyResolveResult[] nonCodeConstructors = getNonCodeConstructors(psiClass, place, substitutor);
PsiMethod[] constructors = new PsiMethod[realConstructors.length + nonCodeConstructors.length];
System.arraycopy(realConstructors, 0, constructors, 0, realConstructors.length);
for (int i = 0; i < nonCodeConstructors.length; i++) {
GroovyResolveResult nonCodeConstructor = nonCodeConstructors[i];
final PsiElement element = nonCodeConstructor.getElement();
if (element instanceof PsiMethod) {
constructors[i + realConstructors.length] = (PsiMethod)element;
}
}
return constructors;
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.lang.resolve.noncode;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.TypeConversionUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor;
/**
* @author Maxim.Medvedev
*/
public class GrInheritConstructorContributor extends NonCodeMembersContributor {
public static final String INHERIT_CONSTRUCTOR_NAME = "groovy.transform.InheritConstructors";
@Override
public void processDynamicElements(@NotNull PsiType qualifierType, PsiScopeProcessor processor, PsiElement place, ResolveState state) {
if (!(qualifierType instanceof PsiClassType)) return;
final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)qualifierType).resolveGenerics();
final PsiClass psiClass = resolveResult.getElement();
if (!(psiClass instanceof GrTypeDefinition) ||
((GrTypeDefinition)psiClass).isAnonymous() ||
psiClass.isInterface() ||
psiClass.isEnum()) {
return;
}
if (!hasInheritConstructorsAnnotation(psiClass)) return;
final PsiClass superClass = psiClass.getSuperClass();
if (superClass == null) return;
final PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY);
final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, psiClass, substitutor);
final ResolveState currentState = state.put(PsiSubstitutor.KEY, superClassSubstitutor);
final PsiMethod[] constructors = superClass.getConstructors();
for (PsiMethod constructor : constructors) {
if (!processor.execute(constructor, currentState)) return;
}
}
public static boolean hasInheritConstructorsAnnotation(PsiClass psiClass) {
final PsiModifierList modifierList = psiClass.getModifierList();
if (modifierList == null) return false;
final PsiAnnotation[] annotations = modifierList.getAnnotations();
boolean hasInheritConstructors = false;
for (PsiAnnotation annotation : annotations) {
if (INHERIT_CONSTRUCTOR_NAME.equals(annotation.getQualifiedName())) {
hasInheritConstructors = true;
break;
}
}
return hasInheritConstructors;
}
}
@@ -293,4 +293,17 @@ public class GroovyCompletionTest extends LightCodeInsightFixtureTestCase {
public void testIncSmartCompletion() throws Exception {
doSmartCompletion("a", "b");
}
public void testInheritConstructorsAnnotation() throws Throwable {
myFixture.addFileToProject("groovy/transform/InheritConstructors.java", "package groovy.transform;\n" +
"\n" +
"import java.lang.annotation.ElementType;\n" +
"import java.lang.annotation.Retention;\n" +
"import java.lang.annotation.RetentionPolicy;\n" +
"import java.lang.annotation.Target;@Retention(RetentionPolicy.SOURCE)\n" +
"@Target({ElementType.TYPE})\n" +
"public @interface InheritConstructors {\n" +
"}");
doSmartTest();
}
}
@@ -1,3 +1,18 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.gant;
@@ -270,4 +270,8 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase {
public void testSignatureIsNotApplicableToList() throws Exception {
doTest();
}
public void testInheritConstructorsAnnotation() throws Exception {
doTest();
}
}
@@ -63,7 +63,7 @@ public abstract class TestUtils {
}
public static String getMockGroovy1_7LibraryName() {
return getMockGroovy1_7LibraryHome()+"/groovy-all-1.7.jar";
return getMockGroovy1_7LibraryHome()+"/groovy-all-1.7.3.jar";
}
public static PsiFile createPseudoPhysicalGroovyFile(final Project project, final String text) throws IncorrectOperationException {
@@ -0,0 +1,12 @@
import groovy.transform.InheritConstructors
class Base {
def Base(Date x) {}
}
@InheritConstructors
class Inheritor extends Base {
}
Inheritor i = new Inheri<caret>
@@ -0,0 +1,12 @@
import groovy.transform.InheritConstructors
class Base {
def Base(Date x) {}
}
@InheritConstructors
class Inheritor extends Base {
}
Inheritor i = new Inheritor(<caret>)
@@ -0,0 +1,13 @@
import groovy.transform.InheritConstructors
class Base<T> {
def Base(T x) {}
}
@InheritConstructors
class Inheritor extends Base<Date> {
}
Inheritor i = new Inheritor(new Date())
Inheritor i2 = new Inheritor<warning descr="'Base' in 'Base<java.util.Date>' cannot be applied to '(java.lang.Integer)'">(2)</warning>
Binary file not shown.