java inspections: use modern ReadAction instead of variable sharing
[idea/community.git] / java / java-analysis-impl / src / com / intellij / codeInspection / reference / RefMethodImpl.java
1 /*
2  * Copyright 2000-2015 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 com.intellij.codeInspection.reference;
17
18 import com.intellij.codeInsight.ExceptionUtil;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.application.ReadAction;
21 import com.intellij.openapi.util.Comparing;
22 import com.intellij.psi.*;
23 import com.intellij.psi.search.GlobalSearchScope;
24 import com.intellij.psi.util.*;
25 import com.intellij.util.IncorrectOperationException;
26 import com.intellij.util.SmartList;
27 import org.jetbrains.annotations.NonNls;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
30
31 import java.util.*;
32
33 /**
34  * @author max
35  * Date: Oct 21, 2001
36  */
37 public class RefMethodImpl extends RefJavaElementImpl implements RefMethod {
38   private static final List<RefMethod> EMPTY_METHOD_LIST = Collections.emptyList();
39   private static final RefParameter[] EMPTY_PARAMS_ARRAY = new RefParameter[0];
40
41   private static final int IS_APPMAIN_MASK = 0x10000;
42   private static final int IS_LIBRARY_OVERRIDE_MASK = 0x20000;
43   private static final int IS_CONSTRUCTOR_MASK = 0x40000;
44   private static final int IS_ABSTRACT_MASK = 0x80000;
45   private static final int IS_BODY_EMPTY_MASK = 0x100000;
46   private static final int IS_ONLY_CALLS_SUPER_MASK = 0x200000;
47   private static final int IS_RETURN_VALUE_USED_MASK = 0x400000;
48
49   private static final int IS_TEST_METHOD_MASK = 0x4000000;
50   private static final int IS_CALLED_ON_SUBCLASS_MASK = 0x8000000;
51
52   private static final String RETURN_VALUE_UNDEFINED = "#";
53
54   private List<RefMethod> mySuperMethods;
55   private List<RefMethod> myDerivedMethods;
56   private List<String> myUnThrownExceptions;
57
58   private RefParameter[] myParameters;
59   private String myReturnValueTemplate;
60   protected final RefClass myOwnerClass;
61
62   RefMethodImpl(@NotNull RefClass ownerClass, PsiMethod method, RefManager manager) {
63     super(method, manager);
64
65     ((RefClassImpl)ownerClass).add(this);
66
67     myOwnerClass = ownerClass;
68   }
69
70   // To be used only from RefImplicitConstructor.
71   protected RefMethodImpl(@NotNull String name, @NotNull RefClass ownerClass) {
72     super(name, ownerClass);
73     myOwnerClass = ownerClass;
74     ((RefClassImpl)ownerClass).add(this);
75
76     addOutReference(getOwnerClass());
77     ((RefClassImpl)getOwnerClass()).addInReference(this);
78
79     setConstructor(true);
80   }
81
82   @Override
83   public void add(@NotNull RefEntity child) {
84     if (child instanceof RefParameter) {
85       return;
86     }
87     super.add(child);
88   }
89
90   @Override
91   public List<RefEntity> getChildren() {
92     List<RefEntity> superChildren = super.getChildren();
93     if (myParameters == null) return superChildren;
94     if (superChildren == null || superChildren.isEmpty()) return Arrays.<RefEntity>asList(myParameters);
95     
96     List<RefEntity> allChildren = new ArrayList<RefEntity>(superChildren.size() + myParameters.length);
97     allChildren.addAll(superChildren);
98     Collections.addAll(allChildren, myParameters);
99     return allChildren;
100   }
101
102   @Override
103   protected void initialize() {
104     final PsiMethod method = (PsiMethod)getElement();
105     LOG.assertTrue(method != null);
106     setConstructor(method.isConstructor());
107     final PsiType returnType = method.getReturnType();
108     setFlag(returnType == null || 
109             PsiType.VOID.equals(returnType) || 
110             returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID), IS_RETURN_VALUE_USED_MASK);
111
112     if (!isReturnValueUsed()) {
113       myReturnValueTemplate = RETURN_VALUE_UNDEFINED;
114     }
115
116     if (isConstructor()) {
117       addReference(getOwnerClass(), getOwnerClass().getElement(), method, false, true, null);
118     }
119
120     if (getOwnerClass().isInterface()) {
121       setAbstract(false);
122     } else {
123       setAbstract(method.hasModifierProperty(PsiModifier.ABSTRACT));
124     }
125
126
127     setAppMain(isAppMain(method, this));
128     setLibraryOverride(method.hasModifierProperty(PsiModifier.NATIVE));
129
130     initializeSuperMethods(method);
131     if (isExternalOverride()) {
132       ((RefClassImpl)getOwnerClass()).addLibraryOverrideMethod(this);
133     }
134
135     @NonNls final String name = method.getName();
136     if (getOwnerClass().isTestCase() && name.startsWith("test")) {
137       setTestMethod(true);
138     }
139
140     PsiParameter[] paramList = method.getParameterList().getParameters();
141     if (paramList.length > 0){
142       myParameters = new RefParameterImpl[paramList.length];
143       for (int i = 0; i < paramList.length; i++) {
144         PsiParameter parameter = paramList[i];
145         myParameters[i] = getRefJavaManager().getParameterReference(parameter, i);
146       }
147     }
148
149     if (method.hasModifierProperty(PsiModifier.NATIVE)) {
150       updateReturnValueTemplate(null);
151       updateThrowsList(null);
152     }
153     collectUncaughtExceptions(method);
154   }
155
156   private static boolean isAppMain(PsiMethod psiMethod, RefMethod refMethod) {
157     if (!refMethod.isStatic()) return false;
158     if (!PsiType.VOID.equals(psiMethod.getReturnType())) return false;
159
160     PsiMethod appMainPattern = ((RefMethodImpl)refMethod).getRefJavaManager().getAppMainPattern();
161     if (MethodSignatureUtil.areSignaturesEqual(psiMethod, appMainPattern)) return true;
162
163     PsiMethod appPremainPattern = ((RefMethodImpl)refMethod).getRefJavaManager().getAppPremainPattern();
164     if (MethodSignatureUtil.areSignaturesEqual(psiMethod, appPremainPattern)) return true;
165
166     PsiMethod appAgentmainPattern = ((RefMethodImpl)refMethod).getRefJavaManager().getAppAgentmainPattern();
167     return MethodSignatureUtil.areSignaturesEqual(psiMethod, appAgentmainPattern);
168   }
169
170   private void checkForSuperCall(PsiMethod method) {
171     if (isConstructor()) {
172       PsiCodeBlock body = method.getBody();
173       if (body == null) return;
174       PsiStatement[] statements = body.getStatements();
175       boolean isBaseExplicitlyCalled = false;
176       if (statements.length > 0) {
177         PsiStatement first = statements[0];
178         if (first instanceof PsiExpressionStatement) {
179           PsiExpression firstExpression = ((PsiExpressionStatement) first).getExpression();
180           if (firstExpression instanceof PsiMethodCallExpression) {
181             PsiExpression qualifierExpression = ((PsiMethodCallExpression)firstExpression).getMethodExpression().getQualifierExpression();
182             if (qualifierExpression instanceof PsiReferenceExpression) {
183               @NonNls String text = qualifierExpression.getText();
184               if ("super".equals(text) || text.equals("this")) {
185                 isBaseExplicitlyCalled = true;
186               }
187             }
188           }
189         }
190       }
191
192       if (!isBaseExplicitlyCalled) {
193         for (RefClass superClass : getOwnerClass().getBaseClasses()) {
194           RefMethodImpl superDefaultConstructor = (RefMethodImpl)superClass.getDefaultConstructor();
195
196           if (superDefaultConstructor != null) {
197             superDefaultConstructor.addInReference(this);
198             addOutReference(superDefaultConstructor);
199           }
200         }
201       }
202     }
203   }
204
205   @Override
206   @NotNull
207   public Collection<RefMethod> getSuperMethods() {
208     if (mySuperMethods == null) return EMPTY_METHOD_LIST;
209     if (mySuperMethods.size() > 10) {
210       LOG.info("method: " + getName() + " owner:" + getOwnerClass().getQualifiedName());
211     }
212     if (getRefManager().isOfflineView()) {
213       LOG.debug("Should not traverse graph offline");
214     }
215     return mySuperMethods;
216   }
217
218   @Override
219   @NotNull
220   public Collection<RefMethod> getDerivedMethods() {
221     if (myDerivedMethods == null) return EMPTY_METHOD_LIST;
222     return myDerivedMethods;
223   }
224
225   @Override
226   public boolean isBodyEmpty() {
227     return checkFlag(IS_BODY_EMPTY_MASK);
228   }
229
230   @Override
231   public boolean isOnlyCallsSuper() {
232     return checkFlag(IS_ONLY_CALLS_SUPER_MASK);
233   }
234
235   @Override
236   public boolean hasBody() {
237     return !isAbstract() && !getOwnerClass().isInterface() || !isBodyEmpty();
238   }
239
240   private void initializeSuperMethods(PsiMethod method) {
241     if (getRefManager().isOfflineView()) return;
242     for (PsiMethod psiSuperMethod : method.findSuperMethods()) {
243       if (getRefManager().belongsToScope(psiSuperMethod)) {
244         RefMethodImpl refSuperMethod = (RefMethodImpl)getRefManager().getReference(psiSuperMethod);
245         if (refSuperMethod != null) {
246           addSuperMethod(refSuperMethod);
247           refSuperMethod.markExtended(this);
248         }
249       }
250       else {
251         setLibraryOverride(true);
252       }
253     }
254   }
255
256   public void addSuperMethod(RefMethodImpl refSuperMethod) {
257     if (!getSuperMethods().contains(refSuperMethod) && !refSuperMethod.getSuperMethods().contains(this)) {
258       if (mySuperMethods == null){
259         mySuperMethods = new ArrayList<RefMethod>(1);
260       }
261       mySuperMethods.add(refSuperMethod);
262     }
263   }
264
265   public void markExtended(RefMethodImpl method) {
266     if (!getDerivedMethods().contains(method) && !method.getDerivedMethods().contains(this)) {
267       if (myDerivedMethods == null) {
268         myDerivedMethods = new ArrayList<RefMethod>(1);
269       }
270       myDerivedMethods.add(method);
271     }
272   }
273
274   @Override
275   @NotNull
276   public RefParameter[] getParameters() {
277     if (myParameters == null) return EMPTY_PARAMS_ARRAY;
278     return myParameters;
279   }
280
281   @Override
282   public void buildReferences() {
283     // Work on code block to find what we're referencing...
284     PsiMethod method = (PsiMethod) getElement();
285     if (method == null) return;
286     PsiCodeBlock body = method.getBody();
287     final RefJavaUtil refUtil = RefJavaUtil.getInstance();
288     refUtil.addReferences(method, this, body);
289     refUtil.addReferences(method, this, method.getModifierList());
290     checkForSuperCall(method);
291     setOnlyCallsSuper(refUtil.isMethodOnlyCallsSuper(method));
292
293     setBodyEmpty(isOnlyCallsSuper() || !isExternalOverride() && (body == null || body.getStatements().length == 0));
294
295     refUtil.addTypeReference(method, method.getReturnType(), getRefManager(), this);
296
297     for (RefParameter parameter : getParameters()) {
298       refUtil.setIsFinal(parameter, parameter.getElement().hasModifierProperty(PsiModifier.FINAL));
299     }
300
301     getRefManager().fireBuildReferences(this);
302   }
303
304   private void collectUncaughtExceptions(@NotNull PsiMethod method) {
305     if (isExternalOverride()) return;
306     if (getRefManager().isOfflineView()) return;
307     @NonNls final String name = method.getName();
308     if (getOwnerClass().isTestCase() && name.startsWith("test")) return;
309
310     if (getSuperMethods().isEmpty()) {
311       PsiClassType[] throwsList = method.getThrowsList().getReferencedTypes();
312       if (throwsList.length > 0) {
313         myUnThrownExceptions = throwsList.length == 1 ? new SmartList<String>() : new ArrayList<String>(throwsList.length);
314         for (final PsiClassType type : throwsList) {
315           PsiClass aClass = type.resolve();
316           String fqn = aClass == null ? null : aClass.getQualifiedName();
317           if (fqn != null) {
318             myUnThrownExceptions.add(fqn);
319           }
320         }
321       }
322     }
323
324     final PsiCodeBlock body = method.getBody();
325     if (body == null) return;
326
327     final Collection<PsiClassType> exceptionTypes = ExceptionUtil.collectUnhandledExceptions(body, method, false);
328     for (final PsiClassType exceptionType : exceptionTypes) {
329       updateThrowsList(exceptionType);
330     }
331   }
332
333   public void removeUnThrownExceptions(PsiClass unThrownException) {
334     if (myUnThrownExceptions != null) {
335       myUnThrownExceptions.remove(unThrownException.getQualifiedName());
336     }
337   }
338
339   @Override
340   public void accept(@NotNull final RefVisitor visitor) {
341     if (visitor instanceof RefJavaVisitor) {
342       ApplicationManager.getApplication().runReadAction(() -> ((RefJavaVisitor)visitor).visitMethod(RefMethodImpl.this));
343     } else {
344       super.accept(visitor);
345     }
346   }
347
348   @Override
349   public boolean isExternalOverride() {
350     return isLibraryOverride(new HashSet<RefMethod>());
351   }
352
353   private boolean isLibraryOverride(@NotNull Collection<RefMethod> processed) {
354     if (!processed.add(this)) return false;
355
356     if (checkFlag(IS_LIBRARY_OVERRIDE_MASK)) return true;
357     for (RefMethod superMethod : getSuperMethods()) {
358       if (((RefMethodImpl)superMethod).isLibraryOverride(processed)) {
359         setFlag(true, IS_LIBRARY_OVERRIDE_MASK);
360         return true;
361       }
362     }
363
364     return false;
365   }
366
367   @Override
368   public boolean isAppMain() {
369     return checkFlag(IS_APPMAIN_MASK);
370   }
371
372   @Override
373   public boolean isAbstract() {
374     return checkFlag(IS_ABSTRACT_MASK);
375   }
376
377   @Override
378   public boolean hasSuperMethods() {
379     return !getSuperMethods().isEmpty() || isExternalOverride();
380   }
381
382   @Override
383   public boolean isReferenced() {
384     // Directly called from somewhere..
385     for (RefElement refCaller : getInReferences()) {
386       if (!getDerivedMethods().contains(refCaller)) return true;
387     }
388
389     // Library override probably called from library code.
390     return isExternalOverride();
391   }
392
393   @Override
394   public boolean hasSuspiciousCallers() {
395     // Directly called from somewhere..
396     for (RefElement refCaller : getInReferences()) {
397       if (((RefElementImpl)refCaller).isSuspicious() && !getDerivedMethods().contains(refCaller)) return true;
398     }
399
400     // Library override probably called from library code.
401     if (isExternalOverride()) return true;
402
403     // Class isn't instantiated. Most probably we have problem with class, not method.
404     if (!isStatic() && !isConstructor()) {
405       if (((RefClassImpl)getOwnerClass()).isSuspicious()) return true;
406
407       // Is an override. Probably called via reference to base class.
408       for (RefMethod refSuper : getSuperMethods()) {
409         if (((RefMethodImpl)refSuper).isSuspicious()) return true;
410       }
411     }
412
413     return false;
414   }
415
416   @Override
417   public boolean isConstructor() {
418     return checkFlag(IS_CONSTRUCTOR_MASK);
419   }
420
421   @Override
422   public RefClass getOwnerClass() {
423     return (RefClass) getOwner();
424   }
425
426   @NotNull
427   @Override
428   public String getName() {
429     if (isValid()) {
430       return ReadAction.compute(() -> {
431         PsiMethod psiMethod = (PsiMethod) getElement();
432         if (psiMethod instanceof SyntheticElement) {
433           return psiMethod.getName();
434         }
435         else {
436           return PsiFormatUtil.formatMethod(psiMethod,
437                                                  PsiSubstitutor.EMPTY,
438                                                  PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS,
439                                                  PsiFormatUtilBase.SHOW_TYPE
440           );
441         }
442       });
443     } else {
444       return super.getName();
445     }
446   }
447
448   @Override
449   public String getExternalName() {
450     return ReadAction.compute(() -> {
451       final PsiMethod psiMethod = (PsiMethod)getElement();
452       LOG.assertTrue(psiMethod != null);
453       return PsiFormatUtil.getExternalName(psiMethod, true, Integer.MAX_VALUE);
454     });
455   }
456
457   @Nullable
458   public static RefMethod methodFromExternalName(RefManager manager, String externalName) {
459     return (RefMethod) manager.getReference(findPsiMethod(PsiManager.getInstance(manager.getProject()), externalName));
460   }
461
462   @Nullable
463   public static PsiMethod findPsiMethod(PsiManager manager, String externalName) {
464     final int spaceIdx = externalName.indexOf(' ');
465     final String className = externalName.substring(0, spaceIdx);
466     final PsiClass psiClass = ClassUtil.findPsiClass(manager, className);
467     if (psiClass == null) return null;
468     try {
469       PsiElementFactory factory = JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory();
470       String methodSignature = externalName.substring(spaceIdx + 1);
471       PsiMethod patternMethod = factory.createMethodFromText(methodSignature, psiClass);
472       return psiClass.findMethodBySignature(patternMethod, false);
473     } catch (IncorrectOperationException e) {
474       // Do nothing. Returning null is acceptable in this case.
475       return null;
476     }
477   }
478
479   @Override
480   public void referenceRemoved() {
481     if (getOwnerClass() != null) {
482       ((RefClassImpl)getOwnerClass()).methodRemoved(this);
483     }
484
485     super.referenceRemoved();
486
487     for (RefMethod superMethod : getSuperMethods()) {
488       superMethod.getDerivedMethods().remove(this);
489     }
490
491     for (RefMethod subMethod : getDerivedMethods()) {
492       subMethod.getSuperMethods().remove(this);
493     }
494
495     ArrayList<RefElement> deletedRefs = new ArrayList<RefElement>();
496     for (RefParameter parameter : getParameters()) {
497       getRefManager().removeRefElement(parameter, deletedRefs);
498     }
499   }
500
501   @Override
502   public boolean isSuspicious() {
503     if (isConstructor() && PsiModifier.PRIVATE.equals(getAccessModifier()) && getParameters().length == 0 && getOwnerClass().getConstructors().size() == 1) return false;
504     return super.isSuspicious();
505   }
506
507   public void setReturnValueUsed(boolean value) {
508     if (checkFlag(IS_RETURN_VALUE_USED_MASK) == value) return;
509     setFlag(value, IS_RETURN_VALUE_USED_MASK);
510     for (RefMethod refSuper : getSuperMethods()) {
511       ((RefMethodImpl)refSuper).setReturnValueUsed(value);
512     }
513   }
514
515   @Override
516   public boolean isReturnValueUsed() {
517     return checkFlag(IS_RETURN_VALUE_USED_MASK);
518   }
519
520   public void updateReturnValueTemplate(PsiExpression expression) {
521     if (myReturnValueTemplate == null) return;
522
523     if (!getSuperMethods().isEmpty()) {
524       for (final RefMethod refMethod : getSuperMethods()) {
525         RefMethodImpl refSuper = (RefMethodImpl)refMethod;
526         refSuper.updateReturnValueTemplate(expression);
527       }
528     }else {
529       String newTemplate = null;
530       final RefJavaUtil refUtil = RefJavaUtil.getInstance();
531       if (expression instanceof PsiLiteralExpression) {
532         PsiLiteralExpression psiLiteralExpression = (PsiLiteralExpression) expression;
533         newTemplate = psiLiteralExpression.getText();
534       } else if (expression instanceof PsiReferenceExpression) {
535         PsiReferenceExpression referenceExpression = (PsiReferenceExpression) expression;
536         PsiElement resolved = referenceExpression.resolve();
537         if (resolved instanceof PsiField) {
538           PsiField psiField = (PsiField) resolved;
539           if (psiField.hasModifierProperty(PsiModifier.STATIC) &&
540               psiField.hasModifierProperty(PsiModifier.FINAL) &&
541               refUtil.compareAccess(refUtil.getAccessModifier(psiField), getAccessModifier()) >= 0) {
542             newTemplate = PsiFormatUtil.formatVariable(psiField, PsiFormatUtilBase.SHOW_NAME |
543                                                                  PsiFormatUtilBase.SHOW_CONTAINING_CLASS |
544                                                                  PsiFormatUtilBase.SHOW_FQ_NAME, PsiSubstitutor.EMPTY);
545           }
546         }
547       } else if (refUtil.isCallToSuperMethod(expression, (PsiMethod) getElement())) return;
548
549       //noinspection StringEquality
550       if (myReturnValueTemplate == RETURN_VALUE_UNDEFINED) {
551         myReturnValueTemplate = newTemplate;
552       } else if (!Comparing.equal(myReturnValueTemplate, newTemplate)) {
553         myReturnValueTemplate = null;
554       }
555     }
556   }
557
558   public void updateParameterValues(PsiExpression[] args) {
559     if (isExternalOverride()) return;
560
561     if (!getSuperMethods().isEmpty()) {
562       for (RefMethod refSuper : getSuperMethods()) {
563         ((RefMethodImpl)refSuper).updateParameterValues(args);
564       }
565     } else {
566       final RefParameter[] params = getParameters();
567       if (params.length <= args.length && params.length > 0) {
568         for (int i = 0; i < args.length; i++) {
569           RefParameter refParameter;
570           if (params.length <= i){
571             refParameter = params[params.length - 1];
572           } else {
573             refParameter = params[i];
574           }
575           ((RefParameterImpl)refParameter).updateTemplateValue(args[i]);
576         }
577       }
578     }
579   }
580
581   @Override
582   public String getReturnValueIfSame() {
583     //noinspection StringEquality
584     if (myReturnValueTemplate == RETURN_VALUE_UNDEFINED) return null;
585     return myReturnValueTemplate;
586   }
587
588   public void updateThrowsList(PsiClassType exceptionType) {
589     if (!getSuperMethods().isEmpty()) {
590       for (RefMethod refSuper : getSuperMethods()) {
591         ((RefMethodImpl)refSuper).updateThrowsList(exceptionType);
592       }
593     }
594     else if (myUnThrownExceptions != null) {
595       if (exceptionType == null) {
596         myUnThrownExceptions = null;
597         return;
598       }
599       PsiClass exceptionClass = exceptionType.resolve();
600       JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject());
601       for (int i = myUnThrownExceptions.size() - 1; i >= 0; i--) {
602         String exceptionFqn = myUnThrownExceptions.get(i);
603         PsiClass classType = facade.findClass(exceptionFqn, GlobalSearchScope.allScope(getRefManager().getProject()));
604         if (InheritanceUtil.isInheritorOrSelf(exceptionClass, classType, true) ||
605             InheritanceUtil.isInheritorOrSelf(classType, exceptionClass, true)) {
606           myUnThrownExceptions.remove(i);
607         }
608       }
609
610       if (myUnThrownExceptions.isEmpty()) myUnThrownExceptions = null;
611     }
612   }
613
614   @Override
615   @Nullable
616   public PsiClass[] getUnThrownExceptions() {
617     if (getRefManager().isOfflineView()) {
618       LOG.debug("Should not traverse graph offline");
619     }
620     if (myUnThrownExceptions == null) return null;
621     JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject());
622     List<PsiClass> result = new ArrayList<PsiClass>(myUnThrownExceptions.size());
623     for (String exception : myUnThrownExceptions) {
624       PsiClass element = facade.findClass(exception, GlobalSearchScope.allScope(myManager.getProject()));
625       if (element != null) result.add(element);
626     }
627     return result.toArray(new PsiClass[result.size()]);
628   }
629
630
631   public void setLibraryOverride(boolean libraryOverride) {
632     setFlag(libraryOverride, IS_LIBRARY_OVERRIDE_MASK);
633   }
634
635   private void setAppMain(boolean appMain) {
636     setFlag(appMain, IS_APPMAIN_MASK);
637   }
638
639   private void setAbstract(boolean anAbstract) {
640     setFlag(anAbstract, IS_ABSTRACT_MASK);
641   }
642
643   public void setBodyEmpty(boolean bodyEmpty) {
644     setFlag(bodyEmpty, IS_BODY_EMPTY_MASK);
645   }
646
647   private void setOnlyCallsSuper(boolean onlyCallsSuper) {
648     setFlag(onlyCallsSuper, IS_ONLY_CALLS_SUPER_MASK);
649   }
650
651
652
653   private void setConstructor(boolean constructor) {
654     setFlag(constructor, IS_CONSTRUCTOR_MASK);
655   }
656
657   @Override
658   public boolean isTestMethod() {
659     return checkFlag(IS_TEST_METHOD_MASK);
660   }
661
662   private void setTestMethod(boolean testMethod){
663     setFlag(testMethod, IS_TEST_METHOD_MASK);
664   }
665
666   @Override
667   public PsiModifierListOwner getElement() {
668     return (PsiModifierListOwner)super.getElement();
669   }
670
671   @Override
672   public boolean isCalledOnSubClass() {
673     return checkFlag(IS_CALLED_ON_SUBCLASS_MASK);
674   }
675
676   public void setCalledOnSubClass(boolean isCalledOnSubClass){
677     setFlag(isCalledOnSubClass, IS_CALLED_ON_SUBCLASS_MASK);
678   }
679
680   private static String extractMethodName(String methodSignature) {
681     final String returnTypeAndName = methodSignature.substring(0, methodSignature.indexOf('('));
682     return returnTypeAndName.substring(returnTypeAndName.indexOf(' ') + 1);
683   }
684 }