Merge commit 'origin/master'
[idea/community.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / refactoring / move / MoveGroovyClassUtil.java
1 /*
2  * Copyright 2000-2010 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.plugins.groovy.refactoring.move;
17
18 import com.intellij.psi.*;
19 import com.intellij.psi.impl.source.tree.Factory;
20 import com.intellij.psi.impl.source.tree.TreeElement;
21 import com.intellij.psi.javadoc.PsiDocComment;
22 import com.intellij.psi.search.LocalSearchScope;
23 import com.intellij.psi.search.searches.ReferencesSearch;
24 import org.jetbrains.annotations.NotNull;
25 import org.jetbrains.annotations.Nullable;
26 import org.jetbrains.plugins.groovy.GroovyFileType;
27 import org.jetbrains.plugins.groovy.actions.GroovyTemplatesFactory;
28 import org.jetbrains.plugins.groovy.actions.NewGroovyActionBase;
29 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
30 import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
31 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
32 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
33 import org.jetbrains.plugins.groovy.refactoring.GroovyChangeContextUtil;
34
35 /**
36  * @author Maxim.Medvedev
37  */
38 public class MoveGroovyClassUtil {
39   private MoveGroovyClassUtil() {
40   }
41
42   @Nullable
43   public static PsiClass moveGroovyClass(@NotNull PsiClass aClass, @NotNull PsiDirectory moveDestination) {
44     if (!aClass.getLanguage().equals(GroovyFileType.GROOVY_LANGUAGE)) return null;
45     PsiFile file = aClass.getContainingFile();
46     final PsiPackage newPackage = JavaDirectoryService.getInstance().getPackage(moveDestination);
47
48     GroovyChangeContextUtil.encodeContextInfo(aClass);
49
50     PsiClass newClass = null;
51     if (file instanceof GroovyFile) {
52       if (((GroovyFile)file).isScript() || ((GroovyFile)file).getClasses().length > 1) {
53         correctSelfReferences(aClass, newPackage);
54         final PsiClass created = ((GroovyFile)GroovyTemplatesFactory
55           .createFromTemplate(moveDestination, aClass.getName(), aClass.getName() + NewGroovyActionBase.GROOVY_EXTENSION,
56                               "GroovyClass.groovy")).getClasses()[0];
57         if (aClass.getDocComment() == null) {
58           final PsiDocComment createdDocComment = created.getDocComment();
59           if (createdDocComment != null) {
60             aClass.addBefore(createdDocComment, null);
61           }
62         }
63         newClass = (PsiClass)created.replace(aClass);
64         correctOldClassReferences(newClass, aClass);
65         aClass.delete();
66       }
67       else if (!moveDestination.equals(file.getContainingDirectory()) && moveDestination.findFile(file.getName()) != null) {
68         // moving second of two classes which were in the same file to a different directory (IDEADEV-3089)
69         correctSelfReferences(aClass, newPackage);
70         PsiFile newFile = moveDestination.findFile(file.getName());
71         TreeElement enter = Factory.createSingleLeafElement(GroovyTokenTypes.mNLS, "\n", 0, 1, null, aClass.getManager());
72         newFile.getNode().addChild(enter);
73         newClass = (GrTypeDefinition)newFile.add(aClass);
74         aClass.delete();
75       }
76       else if (!moveDestination.equals(file.getContainingDirectory()) && moveDestination.findFile(file.getName()) == null) {
77         if (!moveDestination.equals(file.getContainingDirectory())) {
78           aClass.getManager().moveFile(file, moveDestination);
79           newClass = ((GroovyFile)file).getClasses()[0];
80           if (newPackage != null) {
81             ((PsiClassOwner)file).setPackageName(newPackage.getQualifiedName());
82           }
83         }
84       }
85     }
86     if (newClass != null) GroovyChangeContextUtil.decodeContextInfo(newClass, null, null);
87     return newClass;
88   }
89
90   private static void correctOldClassReferences(final PsiClass newClass, final PsiClass oldClass) {
91     for (PsiReference reference : ReferencesSearch.search(oldClass, new LocalSearchScope(newClass)).findAll()) {
92       reference.bindToElement(newClass);
93     }
94   }
95
96   private static void correctSelfReferences(final PsiClass aClass, final PsiPackage newContainingPackage) {
97     final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(aClass.getContainingFile().getContainingDirectory());
98     if (aPackage == null) {
99       return;
100     }
101
102     for (PsiReference reference : ReferencesSearch.search(aClass, new LocalSearchScope(aClass)).findAll()) {
103       if (reference instanceof GrCodeReferenceElement) {
104         final GrCodeReferenceElement qualifier = ((GrCodeReferenceElement)reference).getQualifier();
105         if (qualifier != null) {
106           qualifier.bindToElement(newContainingPackage);
107         }
108       }
109     }
110   }
111 }