create groovy method from usage in java file

This commit is contained in:
Maxim.Medvedev
2012-05-16 10:45:34 +04:00
parent e2ed85b95d
commit a6b7faa32e
14 changed files with 360 additions and 45 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -18,6 +18,8 @@ package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.*;
import com.intellij.codeInsight.completion.proc.VariablesProcessor;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.generation.OverrideImplementUtil;
import com.intellij.codeInsight.generation.PsiGenerationInfo;
import com.intellij.codeInsight.intention.impl.CreateClassDialog;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
@@ -129,7 +131,7 @@ public class CreateFromUsageUtils {
returnType = PsiType.VOID;
}
PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
JVMElementFactory factory = JVMElementFactories.getFactory(aClass.getLanguage(), aClass.getProject());
LOG.assertTrue(!aClass.isInterface(), "Interface bodies should be already set up");
@@ -190,7 +192,7 @@ public class CreateFromUsageUtils {
PsiElement r = PsiTreeUtil.skipSiblingsBackward(body.getRBrace(), PsiWhiteSpace.class);
if (l != null && r != null) {
int start = l.getTextRange().getStartOffset();
int end = r.getTextRange().getEndOffset();
int end = r.getTextRange().getEndOffset();
newEditor.getCaretModel().moveToOffset(Math.max(start, end));
if (end < start) {
newEditor.getCaretModel().moveToOffset(end + 1);
@@ -200,8 +202,11 @@ public class CreateFromUsageUtils {
PsiDocumentManager manager = PsiDocumentManager.getInstance(method.getProject());
manager.doPostponedOperationsAndUnblockDocument(manager.getDocument(containingFile));
EditorModificationUtil.insertStringAtCaret(newEditor, lineIndent);
} else {
newEditor.getSelectionModel().setSelection(Math.min(start, end), Math.max(start, end));
}
else {
//correct position caret for groovy and java methods
final PsiGenerationInfo<PsiMethod> info = OverrideImplementUtil.createGenerationInfo(method);
info.positionCaret(newEditor, true);
}
newEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
}
@@ -225,13 +230,13 @@ public class CreateFromUsageUtils {
final PsiSubstitutor substitutor, final List<Pair<PsiExpression, PsiType>> arguments)
throws IncorrectOperationException {
PsiManager psiManager = method.getManager();
PsiElementFactory factory = JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory();
JVMElementFactory factory = JVMElementFactories.getFactory(method.getLanguage(), method.getProject());
PsiParameterList parameterList = method.getParameterList();
GlobalSearchScope resolveScope = method.getResolveScope();
GuessTypeParameters guesser = new GuessTypeParameters(factory);
GuessTypeParameters guesser = new GuessTypeParameters(JavaPsiFacade.getElementFactory(method.getProject()));
final PsiClass containingClass = method.getContainingClass();
final boolean isInterface = containingClass != null && containingClass.isInterface();
@@ -943,6 +948,7 @@ public class CreateFromUsageUtils {
@Nullable
private static String getQualifiedName(final PsiClass aClass) {
return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@Nullable
@Override
public String compute() {
return aClass.getQualifiedName();
@@ -993,7 +999,16 @@ public class CreateFromUsageUtils {
assert file != null;
PsiElement elementAt = file.findElementAt(offset);
PsiParameterList parameterList = PsiTreeUtil.getParentOfType(elementAt, PsiParameterList.class);
if (parameterList == null) return LookupElement.EMPTY_ARRAY;
if (parameterList == null) {
if (elementAt == null) return LookupElement.EMPTY_ARRAY;
final PsiElement parent = elementAt.getParent();
if (parent instanceof PsiMethod) {
parameterList = ((PsiMethod)parent).getParameterList();
}
else {
return LookupElement.EMPTY_ARRAY;
}
}
PsiParameter parameter = PsiTreeUtil.getParentOfType(elementAt, PsiParameter.class);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -142,7 +142,10 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
String methodName = ref.getReferenceName();
LOG.assertTrue(methodName != null);
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
JVMElementFactory factory = JVMElementFactories.getFactory(targetClass.getLanguage(), project);
if (factory == null) {
return;
}
PsiMethod method = factory.createMethod(methodName, PsiType.VOID);
@@ -251,7 +254,13 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
if (typeParameters.length > 0) {
for (PsiTypeParameter typeParameter : typeParameters) {
if (checkTypeParam( method, typeParameter)) {
method.getTypeParameterList().add(typeParameter);
final JVMElementFactory factory = JVMElementFactories.getFactory(method.getLanguage(), method.getProject());
PsiTypeParameterList list = method.getTypeParameterList();
if (list == null) {
PsiTypeParameterList newList = factory.createTypeParameterList();
list = (PsiTypeParameterList)method.addAfter(newList, method.getModifierList());
}
list.add(factory.createTypeParameter(typeParameter.getName(),typeParameter.getExtendsList().getReferencedTypes()));
}
}
}
@@ -276,32 +285,59 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
}
}
private static boolean checkTypeParam(final PsiElement typeElement,
final PsiTypeParameter typeParameter) {
private static boolean checkTypeParam(final PsiMethod method, final PsiTypeParameter typeParameter) {
final String typeParameterName = typeParameter.getName();
final boolean[] found = new boolean[] {false};
typeElement.accept(new JavaRecursiveElementWalkingVisitor(){
final PsiTypeVisitor<Boolean> visitor = new PsiTypeVisitor<Boolean>() {
@Override
public void visitElement(PsiElement element) {
if (found[0]) return;
super.visitElement(element);
}
@Override
public void visitTypeElement(PsiTypeElement type) {
super.visitTypeElement(type);
final PsiClass psiClass = PsiUtil.resolveClassInType(type.getType());
public Boolean visitClassType(PsiClassType classType) {
final PsiClass psiClass = classType.resolve();
if (psiClass instanceof PsiTypeParameter &&
PsiTreeUtil.isAncestor(((PsiTypeParameter)psiClass).getOwner(), typeElement, true)) {
return;
PsiTreeUtil.isAncestor(((PsiTypeParameter)psiClass).getOwner(), method, true)) {
return false;
}
if (Comparing.strEqual(typeParameterName, type.getText())) {
found[0] = true;
if (Comparing.strEqual(typeParameterName, classType.getCanonicalText())) {
return true;
}
for (PsiType p : classType.getParameters()) {
if (p.accept(this)) return true;
}
return false;
}
});
return found[0];
@Override
public Boolean visitPrimitiveType(PsiPrimitiveType primitiveType) {
return false;
}
@Override
public Boolean visitArrayType(PsiArrayType arrayType) {
return arrayType.getComponentType().accept(this);
}
@Override
public Boolean visitWildcardType(PsiWildcardType wildcardType) {
final PsiType bound = wildcardType.getBound();
if (bound != null) {
return bound.accept(this);
}
return false;
}
};
final PsiTypeElement rElement = method.getReturnTypeElement();
if (rElement != null) {
if (rElement.getType().accept(visitor)) return true;
}
for (PsiParameter parameter : method.getParameterList().getParameters()) {
final PsiTypeElement element = parameter.getTypeElement();
if (element != null) {
if (element.getType().accept(visitor)) return true;
}
}
return false;
}
protected boolean shouldBeAbstract(PsiClass targetClass) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -128,5 +128,12 @@ public interface JVMElementFactory {
@NotNull
PsiElement createExpressionFromText(@NotNull @NonNls String text, @Nullable PsiElement context) throws IncorrectOperationException;
@NotNull
PsiElement createReferenceElementByType(PsiClassType type);
@NotNull
PsiTypeParameterList createTypeParameterList();
@NotNull
PsiTypeParameter createTypeParameter(String name, PsiClassType[] superTypes);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -169,6 +169,34 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps
return new LightClassReference(myManager, type.getPresentableText(), refClass, resolveResult.getSubstitutor());
}
@NotNull
@Override
public PsiTypeParameterList createTypeParameterList() {
return createMethodFromText("void foo()", null).getTypeParameterList();
}
@NotNull
@Override
public PsiTypeParameter createTypeParameter(String name, PsiClassType[] superTypes) {
StringBuilder builder = new StringBuilder();
builder.append("public <").append(name);
if (superTypes.length > 0) {
builder.append(" extends ");
for (PsiClassType type : superTypes) {
builder.append(type.getCanonicalText()).append(',');
}
builder.delete(builder.length() - 1, builder.length());
}
builder.append("> void foo(){}");
try {
return createMethodFromText(builder.toString(), null).getTypeParameters()[0];
}
catch (RuntimeException e) {
throw new IncorrectOperationException("type parameter text: " + builder.toString());
}
}
@NotNull
@Override
public PsiField createField(@NotNull final String name, @NotNull final PsiType type) throws IncorrectOperationException {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -85,12 +85,17 @@ public class ParameterDeclaration implements GroovyElementTypes {
PsiBuilder.Marker rb = builder.mark();
TypeSpec.parseStrict(builder);
final ReferenceElement.ReferenceElementResult result = TypeSpec.parseStrict(builder);
if (mIDENT.equals(builder.getTokenType()) || (mTRIPLE_DOT.equals(builder.getTokenType()))) {
rb.drop();
}
else {
else if (result == ReferenceElement.ReferenceElementResult.mustBeType) {
rb.drop();
pdMarker.error(GroovyBundle.message("identifier.expected"));
return true;
}
else {
rb.rollbackTo();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -158,6 +158,7 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory {
return (GrExpression) topStatements[0];
}
@NotNull
@Override
public GrCodeReferenceElement createReferenceElementByType(PsiClassType type) {
if (type instanceof GrClassReferenceType) {
@@ -173,6 +174,34 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory {
return createCodeReferenceElementFromText(type.getPresentableText());
}
@NotNull
@Override
public PsiTypeParameterList createTypeParameterList() {
return createMethodFromText("def <> void foo(){}").getTypeParameterList();
}
@NotNull
@Override
public PsiTypeParameter createTypeParameter(String name, PsiClassType[] superTypes) {
StringBuilder builder = new StringBuilder();
builder.append("def <").append(name);
if (superTypes.length > 0) {
builder.append(" extends ");
for (PsiClassType type : superTypes) {
builder.append(type.getCanonicalText()).append(',');
}
builder.delete(builder.length() - 1, builder.length());
}
builder.append("> void foo(){}");
try {
return createMethodFromText(builder.toString()).getTypeParameters()[0];
}
catch (RuntimeException e) {
throw new IncorrectOperationException("type parameter text: " + builder.toString());
}
}
public GrVariableDeclaration createVariableDeclaration(@Nullable String[] modifiers,
@Nullable GrExpression initializer,
@Nullable PsiType type,
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -73,6 +73,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.arithme
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.arithmetic.GrMultiplicativeExpressionImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.arithmetic.GrRangeExpressionImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrSyntheticCodeBlock;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrSyntheticTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
@@ -90,6 +91,7 @@ public class PsiImplUtil {
private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil");
private static final String MAIN_METHOD = "main";
public static final Key<SoftReference<PsiCodeBlock>> PSI_CODE_BLOCK = Key.create("Psi_code_block");
public static final Key<SoftReference<PsiTypeElement>> PSI_TYPE_ELEMENT = Key.create("psi.type.element");
private PsiImplUtil() {
}
@@ -535,6 +537,17 @@ public class PsiImplUtil {
return newBody;
}
public static PsiTypeElement getOrCreateTypeElement(@Nullable GrTypeElement typeElement) {
if (typeElement==null) return null;
final SoftReference<PsiTypeElement> ref = typeElement.getUserData(PSI_TYPE_ELEMENT);
final PsiTypeElement element = ref == null ? null : ref.get();
if (element != null) return element;
final GrSyntheticTypeElement newTypeElement = new GrSyntheticTypeElement(typeElement);
typeElement.putUserData(PSI_TYPE_ELEMENT, new SoftReference<PsiTypeElement>(newTypeElement));
return newTypeElement;
}
public static <T extends GrCondition> T replaceBody(T newBody, GrStatement body, ASTNode node, Project project) {
if (body == null || newBody == null) {
throw new IncorrectOperationException();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -77,7 +77,7 @@ public abstract class GrVariableBaseImpl<T extends StubElement> extends GrStubEl
@Nullable
public PsiTypeElement getTypeElement() {
return null;
return PsiImplUtil.getOrCreateTypeElement(getTypeElementGroovy());
}
@Nullable
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -292,7 +292,7 @@ public abstract class GrMethodBaseImpl extends GrStubElementBase<GrMethodStub> i
@Nullable
public PsiTypeElement getReturnTypeElement() {
return null;
return PsiImplUtil.getOrCreateTypeElement(getReturnTypeElementGroovy());
}
@NotNull
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -19,7 +19,9 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.members;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList;
import org.jetbrains.plugins.groovy.lang.psi.stubs.GrMethodStub;
/**
@@ -36,6 +38,16 @@ public class GrMethodImpl extends GrMethodBaseImpl implements GrMethod {
super(stub, GroovyElementTypes.METHOD_DEFINITION);
}
@Override
public ASTNode addInternal(ASTNode first, ASTNode last, ASTNode anchor, Boolean before) {
if (first == last && first.getPsi() instanceof GrTypeParameterList) {
if (!getModifierList().hasExplicitVisibilityModifiers()) {
getModifierList().setModifierProperty(GrModifier.DEF, true);
}
}
return super.addInternal(first, last, anchor, before);
}
public String toString() {
return "Method";
}
@@ -0,0 +1,123 @@
/*
* Copyright 2000-2012 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.psi.impl.synthetic;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightElement;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
/**
* @author Max Medvedev
*/
public class GrSyntheticTypeElement extends LightElement implements PsiTypeElement {
@NotNull private final GrTypeElement myElement;
public GrSyntheticTypeElement(@NotNull GrTypeElement element) {
super(element.getManager(), element.getLanguage());
myElement = element;
}
@NotNull
@Override
public PsiType getType() {
return myElement.getType();
}
@Override
public PsiJavaCodeReferenceElement getInnermostComponentReferenceElement() {
return null;
}
@Override
public PsiAnnotationOwner getOwner(PsiAnnotation annotation) {
return null;
}
@Override
public PsiType getTypeNoResolve(@NotNull PsiElement context) {
return myElement.getType();
}
@NotNull
@Override
public PsiAnnotation[] getAnnotations() {
return PsiAnnotation.EMPTY_ARRAY;
}
@NotNull
@Override
public PsiAnnotation[] getApplicableAnnotations() {
return PsiAnnotation.EMPTY_ARRAY;
}
@Override
public PsiAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
return null;
}
@NotNull
@Override
public PsiAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
return "Synthetic PsiTypeElement";
}
@Override
public TextRange getTextRange() {
return myElement.getTextRange();
}
@Override
public int getTextOffset() {
return myElement.getTextOffset();
}
@Override
public String getText() {
return myElement.getText();
}
@Override
public boolean isValid() {
return myElement.isValid();
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor)visitor).visitTypeElement(this);
}
}
@Override
public void acceptChildren(@NotNull PsiElementVisitor visitor) {
final PsiElement[] children = myElement.getChildren();
for (PsiElement child : children) {
if (child instanceof GrTypeElement) {
PsiImplUtil.getOrCreateTypeElement((GrTypeElement)child).accept(visitor);
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -23,6 +23,7 @@ import com.intellij.psi.StubBasedPsiElement;
import com.intellij.psi.stubs.EmptyStub;
import com.intellij.util.ArrayFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameter;
@@ -74,4 +75,35 @@ public class GrTypeParameterListImpl extends GrStubElementBase<EmptyStub> implem
public void accept(GroovyElementVisitor visitor) {
visitor.visitTypeParameterList(this);
}
@Override
public ASTNode addInternal(ASTNode first, ASTNode last, ASTNode anchor, Boolean before) {
if (first == last && first.getPsi() instanceof GrTypeParameter) {
boolean hasParams = getTypeParameters().length > 0;
final ASTNode _anchor;
if (anchor == null) {
if (before.booleanValue()) {
_anchor = getLastChild().getNode();
}
else {
_anchor = getFirstChild().getNode();
}
}
else {
_anchor = anchor;
}
final ASTNode node = super.addInternal(first, last, _anchor, before);
if (hasParams) {
getNode().addLeaf(GroovyTokenTypes.mCOMMA, ",", anchor != null ? anchor : node);
}
return node;
}
else {
return super.addInternal(first, last, anchor, before);
}
}
}
@@ -1,3 +1,18 @@
/*
* Copyright 2000-2012 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.
*/
class GClass {
public test(def p = 1) {}
public void test(def p = 1) {}
}