2e2f43ec0bea31a7259b2cf1146b2075cfc239c3
[idea/community.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / psi / impl / statements / typedef / GrTypeDefinitionImpl.java
1 /*
2  * Copyright 2000-2009 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
17 package org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef;
18
19 import com.intellij.lang.ASTNode;
20 import com.intellij.navigation.ItemPresentation;
21 import com.intellij.openapi.editor.colors.TextAttributesKey;
22 import com.intellij.openapi.util.Pair;
23 import com.intellij.openapi.vfs.VirtualFile;
24 import com.intellij.psi.*;
25 import com.intellij.psi.codeStyle.CodeStyleSettings;
26 import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
27 import com.intellij.psi.impl.*;
28 import com.intellij.psi.impl.source.tree.LeafPsiElement;
29 import com.intellij.psi.impl.source.tree.java.ClassElement;
30 import com.intellij.psi.scope.PsiScopeProcessor;
31 import com.intellij.psi.stubs.IStubElementType;
32 import com.intellij.ui.RowIcon;
33 import com.intellij.util.ArrayUtil;
34 import com.intellij.util.IncorrectOperationException;
35 import com.intellij.util.VisibilityIcons;
36 import org.jetbrains.annotations.NonNls;
37 import org.jetbrains.annotations.NotNull;
38 import org.jetbrains.annotations.Nullable;
39 import org.jetbrains.plugins.groovy.GroovyFileType;
40 import org.jetbrains.plugins.groovy.GroovyIcons;
41 import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment;
42 import org.jetbrains.plugins.groovy.lang.groovydoc.psi.impl.GrDocCommentUtil;
43 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
44 import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
45 import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
46 import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
47 import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
48 import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
49 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
50 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrClassInitializer;
51 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
52 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
53 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause;
54 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause;
55 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
56 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody;
57 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
58 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMembersDeclaration;
59 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
60 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
61 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameter;
62 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList;
63 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrWildcardTypeArgument;
64 import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyBaseElementImpl;
65 import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyFileImpl;
66 import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
67 import org.jetbrains.plugins.groovy.lang.psi.stubs.GrTypeDefinitionStub;
68 import org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil;
69 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
70
71 import javax.swing.*;
72 import java.util.ArrayList;
73 import java.util.Collection;
74 import java.util.List;
75
76 /**
77  * @author ilyas
78  */
79 public abstract class GrTypeDefinitionImpl extends GroovyBaseElementImpl<GrTypeDefinitionStub> implements GrTypeDefinition {
80
81   private PsiMethod[] myMethods;
82   private GrMethod[] myGroovyMethods;
83   private GrMethod[] myConstructors;
84
85   public GrTypeDefinitionImpl(@NotNull ASTNode node) {
86     super(node);
87   }
88
89   protected GrTypeDefinitionImpl(GrTypeDefinitionStub stub, IStubElementType nodeType) {
90     super(stub, nodeType);
91   }
92
93   public void accept(GroovyElementVisitor visitor) {
94     visitor.visitTypeDefinition(this);
95   }
96
97   public int getTextOffset() {
98     return getNameIdentifierGroovy().getTextRange().getStartOffset();
99   }
100
101   @Nullable
102   public String getQualifiedName() {
103     final GrTypeDefinitionStub stub = getStub();
104     if (stub != null) {
105       return stub.getQualifiedName();
106     }
107
108     final PsiClass containingClass = getContainingClass();
109     if (containingClass != null) {
110       return containingClass.getQualifiedName() + "." + getName();
111     }
112
113     PsiElement parent = getParent();
114     if (parent instanceof GroovyFile) {
115       String packageName = ((GroovyFile)parent).getPackageName();
116       return packageName.length() > 0 ? packageName + "." + getName() : getName();
117     }
118
119     return null;
120   }
121
122   public GrWildcardTypeArgument[] getTypeParametersGroovy() {
123     return findChildrenByClass(GrWildcardTypeArgument.class);
124   }
125
126   @Nullable
127   public GrTypeDefinitionBody getBody() {
128     return (GrTypeDefinitionBody)findChildByType(GroovyElementTypes.CLASS_BODY);
129   }
130
131   @NotNull
132   public GrMembersDeclaration[] getMemberDeclarations() {
133     GrTypeDefinitionBody body = getBody();
134     if (body == null) return GrMembersDeclaration.EMPTY_ARRAY;
135     return body.getMemberDeclarations();
136   }
137
138   public ItemPresentation getPresentation() {
139     return new ItemPresentation() {
140       public String getPresentableText() {
141         return getName();
142       }
143
144       @Nullable
145       public String getLocationString() {
146         PsiFile file = getContainingFile();
147         if (file instanceof GroovyFile) {
148           GroovyFile groovyFile = (GroovyFile)file;
149
150           return groovyFile.getPackageName().length() > 0 ? "(" + groovyFile.getPackageName() + ")" : "";
151         }
152         return "";
153       }
154
155       @Nullable
156       public Icon getIcon(boolean open) {
157         return GrTypeDefinitionImpl.this.getIcon(ICON_FLAG_VISIBILITY | ICON_FLAG_READ_STATUS);
158       }
159
160       @Nullable
161       public TextAttributesKey getTextAttributesKey() {
162         return null;
163       }
164     };
165   }
166
167   @Nullable
168   public GrExtendsClause getExtendsClause() {
169     return (GrExtendsClause)findChildByType(GroovyElementTypes.EXTENDS_CLAUSE);
170   }
171
172   @Nullable
173   public GrImplementsClause getImplementsClause() {
174     return (GrImplementsClause)findChildByType(GroovyElementTypes.IMPLEMENTS_CLAUSE);
175   }
176
177   public String[] getSuperClassNames() {
178     final GrTypeDefinitionStub stub = getStub();
179     if (stub != null) {
180       return stub.getSuperClassNames();
181     }
182     return ArrayUtil.mergeArrays(getExtendsNames(), getImplementsNames(), String.class);
183   }
184
185   protected String[] getImplementsNames() {
186     GrImplementsClause implementsClause = getImplementsClause();
187     GrCodeReferenceElement[] implementsRefs =
188       implementsClause != null ? implementsClause.getReferenceElements() : GrCodeReferenceElement.EMPTY_ARRAY;
189     ArrayList<String> implementsNames = new ArrayList<String>(implementsRefs.length);
190     for (GrCodeReferenceElement ref : implementsRefs) {
191       String name = ref.getReferenceName();
192       if (name != null) implementsNames.add(name);
193     }
194
195     return ArrayUtil.toStringArray(implementsNames);
196   }
197
198   protected String[] getExtendsNames() {
199     GrExtendsClause extendsClause = getExtendsClause();
200     GrCodeReferenceElement[] extendsRefs =
201       extendsClause != null ? extendsClause.getReferenceElements() : GrCodeReferenceElement.EMPTY_ARRAY;
202     ArrayList<String> extendsNames = new ArrayList<String>(extendsRefs.length);
203     for (GrCodeReferenceElement ref : extendsRefs) {
204       String name = ref.getReferenceName();
205       if (name != null) extendsNames.add(name);
206     }
207     return ArrayUtil.toStringArray(extendsNames);
208   }
209
210   @NotNull
211   public PsiElement getNameIdentifierGroovy() {
212     PsiElement result = findChildByType(TokenSets.PROPERTY_NAMES);
213     assert result != null;
214     return result;
215   }
216
217   public void checkDelete() throws IncorrectOperationException {
218   }
219
220   public void delete() throws IncorrectOperationException {
221     PsiElement parent = getParent();
222     if (parent instanceof GroovyFileImpl) {
223       GroovyFileImpl file = (GroovyFileImpl)parent;
224       if (file.getTypeDefinitions().length == 1 && !file.isScript()) {
225         file.delete();
226         return;
227       }
228     }
229
230     ASTNode astNode = parent.getNode();
231     if (astNode != null) {
232       astNode.removeChild(getNode());
233     }
234   }
235
236   public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
237                                      @NotNull ResolveState state,
238                                      @Nullable PsiElement lastParent,
239                                      @NotNull PsiElement place) {
240     return GrClassImplUtil.processDeclarations(this, processor, state, lastParent, place);
241   }
242
243   public String getName() {
244     final GrTypeDefinitionStub stub = getStub();
245     if (stub != null) {
246       return stub.getName();
247     }
248     return PsiImplUtil.getName(this);
249   }
250
251   @Override
252   public boolean isEquivalentTo(PsiElement another) {
253     return GrClassImplUtil.isClassEquivalentTo(this, another);
254   }
255
256   public boolean isInterface() {
257     return false;
258   }
259
260   public boolean isAnnotationType() {
261     return false;
262   }
263
264   public boolean isEnum() {
265     return false;
266   }
267
268   @Nullable
269   public PsiReferenceList getExtendsList() {
270     return null;
271   }
272
273   @Nullable
274   public PsiReferenceList getImplementsList() {
275     return null;
276   }
277
278   @NotNull
279   public PsiClassType[] getExtendsListTypes() {
280     return GrClassImplUtil.getExtendsListTypes(this);
281   }
282
283   @NotNull
284   public PsiClassType[] getImplementsListTypes() {
285     return GrClassImplUtil.getImplementsListTypes(this);
286   }
287
288   @Nullable
289   public PsiClass getSuperClass() {
290     return GrClassImplUtil.getSuperClass(this);
291   }
292
293   public PsiClass[] getInterfaces() {
294     return GrClassImplUtil.getInterfaces(this);
295   }
296
297   @NotNull
298   public final PsiClass[] getSupers() {
299     return GrClassImplUtil.getSupers(this);
300   }
301
302   @NotNull
303   public PsiClassType[] getSuperTypes() {
304     return GrClassImplUtil.getSuperTypes(this);
305   }
306
307   @NotNull
308   public GrField[] getFields() {
309     GrTypeDefinitionBody body = getBody();
310     if (body != null) {
311       return body.getFields();
312     }
313
314     return GrField.EMPTY_ARRAY;
315   }
316
317   @NotNull
318   public GrClassInitializer[] getInitializersGroovy() {
319     GrTypeDefinitionBody body = getBody();
320     if (body != null) {
321       return body.getInitializers();
322     }
323
324     return GrClassInitializer.EMPTY_ARRAY;
325   }
326
327   @NotNull
328   public PsiMethod[] getMethods() {
329     if (myMethods == null) {
330       List<PsiMethod> result = new ArrayList<PsiMethod>();
331       GrTypeDefinitionBody body = getBody();
332       if (body != null) {
333         result.addAll(body.getMethods());
334       }
335       GrClassImplUtil.addGroovyObjectMethods(this, result);
336       myMethods = result.toArray(new PsiMethod[result.size()]);
337     }
338     return myMethods;
339   }
340
341   @NotNull
342   public GrMethod[] getGroovyMethods() {
343     if (myGroovyMethods == null) {
344       GrTypeDefinitionBody body = getBody();
345       if (body != null) {
346         myGroovyMethods = body.getGroovyMethods();
347       }
348       else {
349         myGroovyMethods = GrMethod.EMPTY_ARRAY;
350       }
351     }
352     return myGroovyMethods;
353   }
354
355   public void subtreeChanged() {
356     myMethods = null;
357     myConstructors = null;
358     myGroovyMethods = null;
359     super.subtreeChanged();
360   }
361
362   @NotNull
363   public PsiMethod[] getConstructors() {
364     if (myConstructors == null) {
365       List<GrMethod> result = new ArrayList<GrMethod>();
366       for (final PsiMethod method : getMethods()) {
367         if (method.isConstructor()) {
368           result.add((GrMethod)method);
369         }
370       }
371
372       myConstructors = result.toArray(new GrMethod[result.size()]);
373       return myConstructors;
374     }
375     return myConstructors;
376   }
377
378   @NotNull
379   public PsiClass[] getInnerClasses() {
380     final GrTypeDefinitionBody body = getBody();
381     if (body != null) {
382       return body.getInnerClasses();
383     }
384
385     return PsiClass.EMPTY_ARRAY;
386   }
387
388   @NotNull
389   public PsiClassInitializer[] getInitializers() {
390     return PsiClassInitializer.EMPTY_ARRAY;
391   }
392
393   @NotNull
394   public PsiField[] getAllFields() {
395     return GrClassImplUtil.getAllFields(this);
396   }
397
398   @NotNull
399   public PsiMethod[] getAllMethods() {
400     return GrClassImplUtil.getAllMethods(this);
401   }
402
403   @NotNull
404   public PsiClass[] getAllInnerClasses() {
405     return PsiClassImplUtil.getAllInnerClasses(this);
406   }
407
408   @Nullable
409   public PsiField findFieldByName(String name, boolean checkBases) {
410     return GrClassImplUtil.findFieldByName(this, name, checkBases);
411   }
412
413   @Nullable
414   public PsiMethod findMethodBySignature(PsiMethod patternMethod, boolean checkBases) {
415     return GrClassImplUtil.findMethodBySignature(this, patternMethod, checkBases);
416   }
417
418   @NotNull
419   public PsiMethod[] findMethodsBySignature(PsiMethod patternMethod, boolean checkBases) {
420     return GrClassImplUtil.findMethodsBySignature(this, patternMethod, checkBases);
421   }
422
423   @NotNull
424   public PsiMethod[] findCodeMethodsBySignature(PsiMethod patternMethod, boolean checkBases) {
425     return GrClassImplUtil.findCodeMethodsBySignature(this, patternMethod, checkBases);
426   }
427
428   @NotNull
429   public PsiMethod[] findMethodsByName(@NonNls String name, boolean checkBases) {
430     return GrClassImplUtil.findMethodsByName(this, name, checkBases);
431   }
432
433   @NotNull
434   public PsiMethod[] findCodeMethodsByName(@NonNls String name, boolean checkBases) {
435     return GrClassImplUtil.findCodeMethodsByName(this, name, checkBases);
436   }
437
438   @NotNull
439   public List<Pair<PsiMethod, PsiSubstitutor>> findMethodsAndTheirSubstitutorsByName(String name, boolean checkBases) {
440     return GrClassImplUtil.findMethodsAndTheirSubstitutorsByName(this, name, checkBases);
441   }
442
443   @NotNull
444   public List<Pair<PsiMethod, PsiSubstitutor>> getAllMethodsAndTheirSubstitutors() {
445     return GrClassImplUtil.getAllMethodsAndTheirSubstitutors(this);
446   }
447
448   @Nullable
449   public PsiClass findInnerClassByName(String name, boolean checkBases) {
450     return null;
451   }
452
453   @Nullable
454   public PsiJavaToken getLBrace() {
455     return null;
456   }
457
458   @Nullable
459   public PsiJavaToken getRBrace() {
460     return null;
461   }
462
463   @Nullable
464   public PsiElement getLBraceGroovy() {
465     GrTypeDefinitionBody body = getBody();
466     if (body == null) return null;
467     return body.getLBrace();
468   }
469
470   @Nullable
471   public PsiElement getRBraceGroovy() {
472     GrTypeDefinitionBody body = getBody();
473     if (body == null) return null;
474     return body.getRBrace();
475   }
476
477   public boolean isAnonymous() {
478     return false;
479   }
480
481   @Nullable
482   public PsiIdentifier getNameIdentifier() {
483     return PsiUtil.getJavaNameIdentifier(this);
484   }
485
486   @Nullable
487   public PsiElement getScope() {
488     return null;
489   }
490
491   public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
492     return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep);
493   }
494
495   public boolean isInheritorDeep(PsiClass baseClass, @Nullable PsiClass classToByPass) {
496     return InheritanceImplUtil.isInheritorDeep(this, baseClass, classToByPass);
497   }
498
499   @Nullable
500   public PsiClass getContainingClass() {
501     PsiElement parent = getParent();
502     if (parent instanceof GrTypeDefinitionBody) {
503       final PsiElement pparent = parent.getParent();
504       if (pparent instanceof PsiClass) {
505         return (PsiClass)pparent;
506       }
507     }
508
509     return null;
510   }
511
512   @NotNull
513   public Collection<HierarchicalMethodSignature> getVisibleSignatures() {
514     return PsiSuperMethodImplUtil.getVisibleSignatures(this);
515   }
516
517   public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
518     boolean renameFile = isRenameFileOnClassRenaming();
519
520     PsiImplUtil.setName(name, getNameIdentifierGroovy());
521
522     if (renameFile) {
523       final GroovyFileBase file = (GroovyFileBase)getContainingFile();
524       file.setName(name + "." + GroovyFileType.GROOVY_FILE_TYPE.getDefaultExtension());
525     }
526
527     return this;
528   }
529
530   @Nullable
531   public GrModifierList getModifierList() {
532     return (GrModifierList)findChildByType(GroovyElementTypes.MODIFIERS);
533   }
534
535   public boolean hasModifierProperty(@NonNls @NotNull String name) {
536     PsiModifierList modifierList = getModifierList();
537     return modifierList != null && modifierList.hasModifierProperty(name);
538   }
539
540   @Nullable
541   public GrDocComment getDocComment() {
542     return GrDocCommentUtil.findDocComment(this);
543   }
544
545   public boolean isDeprecated() {
546     return com.intellij.psi.impl.PsiImplUtil.isDeprecatedByDocTag(this) || com.intellij.psi.impl.PsiImplUtil.isDeprecatedByAnnotation(this);
547   }
548
549   public boolean hasTypeParameters() {
550     return getTypeParameters().length > 0;
551   }
552
553   @Nullable
554   public GrTypeParameterList getTypeParameterList() {
555     return findChildByClass(GrTypeParameterList.class);
556   }
557
558   @NotNull
559   public GrTypeParameter[] getTypeParameters() {
560     final GrTypeParameterList list = getTypeParameterList();
561     if (list != null) {
562       return list.getTypeParameters();
563     }
564
565     return GrTypeParameter.EMPTY_ARRAY;
566   }
567
568   @Nullable
569   public Icon getIcon(int flags) {
570     Icon icon = getIconInner();
571     final boolean isLocked = (flags & ICON_FLAG_READ_STATUS) != 0 && !isWritable();
572     RowIcon rowIcon = ElementBase.createLayeredIcon(icon, ElementPresentationUtil.getFlags(this, isLocked));
573     if ((flags & ICON_FLAG_VISIBILITY) != 0) {
574       VisibilityIcons.setVisibilityIcon(getModifierList(), rowIcon);
575     }
576     return rowIcon;
577   }
578
579   private Icon getIconInner() {
580     if (isAnnotationType()) return GroovyIcons.ANNOTATION_TYPE;
581
582     if (isInterface()) return GroovyIcons.INTERFACE;
583
584     if (isEnum()) return GroovyIcons.ENUM;
585
586     if (hasModifierProperty(PsiModifier.ABSTRACT)) return GroovyIcons.ABSTRACT_CLASS;
587
588     return GroovyIcons.CLASS;
589   }
590
591   private boolean isRenameFileOnClassRenaming() {
592     final PsiFile file = getContainingFile();
593     if (!(file instanceof GroovyFile)) return false;
594     final GroovyFile groovyFile = (GroovyFile)file;
595     if (groovyFile.isScript()) return false;
596     final GrTypeDefinition[] typeDefinitions = groovyFile.getTypeDefinitions();
597     if (typeDefinitions.length > 1) return false;
598     final String name = getName();
599     final VirtualFile vFile = groovyFile.getVirtualFile();
600     return vFile != null && name != null && name.equals(vFile.getNameWithoutExtension());
601   }
602
603   public PsiElement getOriginalElement() {
604     return PsiImplUtil.getOriginalElement(this, getContainingFile());
605   }
606
607   public PsiElement addAfter(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException {
608     if (anchor == null) {
609       return add(element);
610     }
611     final GrTypeDefinitionBody body = getBody();
612     assert anchor.getParent() == body;
613
614     final PsiElement nextChild = anchor.getNextSibling();
615     if (nextChild == null) {
616       add(element);
617       return element;
618     }
619
620     ASTNode node = element.getNode();
621     assert node != null;
622     //body.getNode().addLeaf(GroovyElementTypes.mNLS, "\n", nextChild.getNode());
623     return body.addBefore(element, nextChild);
624   }
625
626   public PsiElement addBefore(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException {
627     if (anchor == null) {
628       add(element);
629       return element;
630     }
631
632     final GrTypeDefinitionBody body = getBody();
633     assert anchor.getParent() == body;
634
635     ASTNode node = element.getNode();
636     assert node != null;
637     final ASTNode bodyNode = body.getNode();
638     final ASTNode anchorNode = anchor.getNode();
639     bodyNode.addChild(node, anchorNode);
640     bodyNode.addLeaf(GroovyTokenTypes.mWS, " ", node);
641     bodyNode.addLeaf(GroovyTokenTypes.mNLS, "\n", anchorNode);
642     return element;
643   }
644
645   public PsiElement add(@NotNull PsiElement psiElement) throws IncorrectOperationException {
646     final GrTypeDefinitionBody body = getBody();
647
648     if (body == null) throw new IncorrectOperationException("Class must have body");
649
650     final PsiElement lBrace = body.getLBrace();
651
652     if (lBrace == null) throw new IncorrectOperationException("No left brace");
653
654     PsiMember member = getAnyMember(psiElement);
655     PsiElement anchor = member != null ? getDefaultAnchor(body, member) : null;
656     if (anchor == null) {
657       anchor = lBrace.getNextSibling();
658     }
659
660     ASTNode bodyNode = body.getNode();
661     if (anchor != null) {
662       ASTNode node = anchor.getNode();
663       assert node != null;
664       if (GroovyElementTypes.mSEMI.equals(node.getElementType())) {
665         anchor = anchor.getNextSibling();
666       }
667       psiElement = body.addBefore(psiElement, anchor);
668     }
669     else {
670       bodyNode.addChild(psiElement.getNode());
671     }
672
673     return psiElement;
674   }
675
676   @Nullable
677   private static PsiMember getAnyMember(@Nullable PsiElement psiElement) {
678     if (psiElement instanceof PsiMember) {
679       return (PsiMember)psiElement;
680     }
681     if (psiElement instanceof GrVariableDeclaration) {
682       final GrMember[] members = ((GrVariableDeclaration)psiElement).getMembers();
683       if (members.length > 0) {
684         return members[0];
685       }
686     }
687     return null;
688   }
689
690   @Nullable
691   private PsiElement getDefaultAnchor(GrTypeDefinitionBody body, PsiMember member) {
692     CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject());
693
694     int order = ClassElement.getMemberOrderWeight(member, settings);
695     if (order < 0) return null;
696
697     PsiElement lastMember = null;
698     for (PsiElement child = body.getFirstChild(); child != null; child = child.getNextSibling()) {
699       int order1 = ClassElement.getMemberOrderWeight(getAnyMember(child), settings);
700       if (order1 < 0) continue;
701       if (order1 > order) {
702         final PsiElement lBrace = body.getLBrace();
703         if (lastMember != null) {
704           PsiElement nextSibling = lastMember.getNextSibling();
705           while (nextSibling instanceof LeafPsiElement && (nextSibling.getText().equals(",") || nextSibling.getText().equals(";"))) {
706             nextSibling = nextSibling.getNextSibling();
707           }
708           return nextSibling == null && lBrace != null ? lBrace.getNextSibling() : nextSibling;
709         }
710         else if (lBrace != null) {
711           return lBrace.getNextSibling();
712         }
713       }
714       lastMember = child;
715     }
716     return body.getRBrace();
717   }
718
719
720   public <T extends GrMembersDeclaration> T addMemberDeclaration(@NotNull T decl, PsiElement anchorBefore)
721     throws IncorrectOperationException {
722
723     if (anchorBefore == null) {
724       return (T)add(decl);
725     }
726
727     GrTypeDefinitionBody body = getBody();
728     if (body == null) throw new IncorrectOperationException("Type definition without a body");
729     ASTNode anchorNode;
730     anchorNode = anchorBefore.getNode();
731     ASTNode bodyNode = body.getNode();
732     bodyNode.addChild(decl.getNode(), anchorNode);
733     bodyNode.addLeaf(GroovyTokenTypes.mWS, " ", decl.getNode()); //add whitespaces before and after to hack over incorrect auto reformat
734     bodyNode.addLeaf(GroovyTokenTypes.mWS, " ", anchorNode);
735     return decl;
736   }
737
738 }