mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-56195 Groovy 1.7.3: check if class is annotated with @InheritConstructors
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
+10
-1
@@ -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;
|
||||
}
|
||||
|
||||
+3
-1
@@ -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);
|
||||
|
||||
+11
-7
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+70
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -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 {
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import groovy.transform.InheritConstructors
|
||||
|
||||
class Base {
|
||||
def Base(Date x) {}
|
||||
}
|
||||
|
||||
@InheritConstructors
|
||||
class Inheritor extends Base {
|
||||
|
||||
}
|
||||
|
||||
Inheritor i = new Inheri<caret>
|
||||
+12
@@ -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.
Reference in New Issue
Block a user