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