private static PsiSubstitutor obtainFinalSubstitutor(
      PsiClass superClass,
      PsiSubstitutor superSubstitutor,
      PsiSubstitutor derivedSubstitutor,
      boolean inRawContext) {
    if (inRawContext) {
      Set<PsiTypeParameter> typeParams = superSubstitutor.getSubstitutionMap().keySet();
      PsiElementFactory factory = JavaPsiFacade.getElementFactory(superClass.getProject());
      superSubstitutor =
          factory.createRawSubstitutor(
              derivedSubstitutor, typeParams.toArray(new PsiTypeParameter[typeParams.size()]));
    }
    Map<PsiTypeParameter, PsiType> map = null;
    for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(superClass)) {
      PsiType type = superSubstitutor.substitute(typeParameter);
      final PsiType t = derivedSubstitutor.substitute(type);
      if (map == null) {
        map = new THashMap<PsiTypeParameter, PsiType>();
      }
      map.put(typeParameter, t);
    }

    return map == null
        ? PsiSubstitutor.EMPTY
        : JavaPsiFacade.getInstance(superClass.getProject())
            .getElementFactory()
            .createSubstitutor(map);
  }
 private static void addDefaultConstructor(
     JavaChangeInfo changeInfo, PsiClass aClass, final UsageInfo[] usages)
     throws IncorrectOperationException {
   if (!(aClass instanceof PsiAnonymousClass)) {
     PsiElementFactory factory = JavaPsiFacade.getElementFactory(aClass.getProject());
     PsiMethod defaultConstructor =
         factory.createMethodFromText(aClass.getName() + "(){}", aClass);
     defaultConstructor =
         (PsiMethod)
             CodeStyleManager.getInstance(aClass.getProject()).reformat(defaultConstructor);
     defaultConstructor = (PsiMethod) aClass.add(defaultConstructor);
     PsiUtil.setModifierProperty(
         defaultConstructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true);
     addSuperCall(changeInfo, defaultConstructor, null, usages);
   } else {
     final PsiElement parent = aClass.getParent();
     if (parent instanceof PsiNewExpression) {
       final PsiExpressionList argumentList = ((PsiNewExpression) parent).getArgumentList();
       final PsiClass baseClass = changeInfo.getMethod().getContainingClass();
       final PsiSubstitutor substitutor =
           TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY);
       fixActualArgumentsList(argumentList, changeInfo, true, substitutor);
     }
   }
 }
  @NotNull
  private static PsiClass[] getSupersInner(@NotNull PsiClass psiClass) {
    PsiClassType[] extendsListTypes = psiClass.getExtendsListTypes();
    PsiClassType[] implementsListTypes = psiClass.getImplementsListTypes();

    if (psiClass.isInterface()) {
      return resolveClassReferenceList(
          extendsListTypes, psiClass.getManager(), psiClass.getResolveScope(), true);
    }

    if (psiClass instanceof PsiAnonymousClass) {
      PsiAnonymousClass psiAnonymousClass = (PsiAnonymousClass) psiClass;
      PsiClassType baseClassReference = psiAnonymousClass.getBaseClassType();
      PsiClass baseClass = baseClassReference.resolve();
      if (baseClass != null) {
        if (baseClass.isInterface()) {
          PsiClass objectClass =
              JavaPsiFacade.getInstance(psiClass.getProject())
                  .findClass(CommonClassNames.JAVA_LANG_OBJECT, psiClass.getResolveScope());
          return objectClass != null
              ? new PsiClass[] {objectClass, baseClass}
              : new PsiClass[] {baseClass};
        }
        return new PsiClass[] {baseClass};
      }

      PsiClass objectClass =
          JavaPsiFacade.getInstance(psiClass.getProject())
              .findClass(CommonClassNames.JAVA_LANG_OBJECT, psiClass.getResolveScope());
      return objectClass != null ? new PsiClass[] {objectClass} : PsiClass.EMPTY_ARRAY;
    }
    if (psiClass instanceof PsiTypeParameter) {
      if (extendsListTypes.length == 0) {
        final PsiClass objectClass =
            JavaPsiFacade.getInstance(psiClass.getProject())
                .findClass(CommonClassNames.JAVA_LANG_OBJECT, psiClass.getResolveScope());
        return objectClass != null ? new PsiClass[] {objectClass} : PsiClass.EMPTY_ARRAY;
      }
      return resolveClassReferenceList(
          extendsListTypes, psiClass.getManager(), psiClass.getResolveScope(), false);
    }

    PsiClass[] interfaces =
        resolveClassReferenceList(
            implementsListTypes, psiClass.getManager(), psiClass.getResolveScope(), false);

    PsiClass superClass = getSuperClass(psiClass);
    if (superClass == null) return interfaces;
    PsiClass[] types = new PsiClass[interfaces.length + 1];
    types[0] = superClass;
    System.arraycopy(interfaces, 0, types, 1, interfaces.length);

    return types;
  }
 private static void putInMap(
     PsiClass aClass,
     Map<MethodSignature, HierarchicalMethodSignature> result,
     Map<MethodSignature, HierarchicalMethodSignatureImpl> map,
     HierarchicalMethodSignature hierarchicalMethodSignature,
     MethodSignature signature) {
   if (!PsiUtil.isAccessible(
       aClass.getProject(), hierarchicalMethodSignature.getMethod(), aClass, aClass)) return;
   HierarchicalMethodSignatureImpl existing = map.get(signature);
   if (existing == null) {
     HierarchicalMethodSignatureImpl copy = copy(hierarchicalMethodSignature);
     LOG.assertTrue(copy.getMethod().isValid());
     map.put(signature, copy);
   } else if (isReturnTypeIsMoreSpecificThan(hierarchicalMethodSignature, existing)
       && isSuperMethod(aClass, hierarchicalMethodSignature, existing)) {
     HierarchicalMethodSignatureImpl newSuper = copy(hierarchicalMethodSignature);
     mergeSupers(newSuper, existing);
     LOG.assertTrue(newSuper.getMethod().isValid());
     map.put(signature, newSuper);
   } else if (isSuperMethod(aClass, existing, hierarchicalMethodSignature)) {
     mergeSupers(existing, hierarchicalMethodSignature);
   }
   // just drop an invalid method declaration there - to highlight accordingly
   else if (!result.containsKey(signature)) {
     LOG.assertTrue(hierarchicalMethodSignature.getMethod().isValid());
     result.put(signature, hierarchicalMethodSignature);
   }
 }
 public static boolean inheritsITestListener(@NotNull PsiClass psiClass) {
   final Project project = psiClass.getProject();
   final PsiClass aListenerClass =
       JavaPsiFacade.getInstance(project)
           .findClass(ITestNGListener.class.getName(), GlobalSearchScope.allScope(project));
   return aListenerClass != null && psiClass.isInheritor(aListenerClass, true);
 }
 private static PsiType createType(PsiClass cls, PsiSubstitutor currentSubstitutor, int arrayDim) {
   final PsiElementFactory elementFactory =
       JavaPsiFacade.getInstance(cls.getProject()).getElementFactory();
   PsiType newType = elementFactory.createType(cls, currentSubstitutor);
   for (int i = 0; i < arrayDim; i++) {
     newType = newType.createArrayType();
   }
   return newType;
 }
  public GrPullUpHelper(
      PsiClass aClass, PsiClass superClass, GrMemberInfo[] infos, DocCommentPolicy policy) {
    super(aClass.getProject());

    mySourceClass = aClass;
    myTargetSuperClass = (GrTypeDefinition) superClass;
    myMembersToMove = infos;
    myDocCommentPolicy = policy;
  }
 public ExtractClassProcessor(
     PsiClass sourceClass,
     List<PsiField> fields,
     List<PsiMethod> methods,
     List<PsiClass> classes,
     String packageName,
     MoveDestination moveDestination,
     String newClassName,
     String newVisibility,
     boolean generateAccessors,
     List<MemberInfo> enumConstants) {
   super(sourceClass.getProject());
   this.sourceClass = sourceClass;
   this.newPackageName = packageName;
   myMoveDestination = moveDestination;
   myNewVisibility = newVisibility;
   myGenerateAccessors = generateAccessors;
   this.enumConstants = new ArrayList<PsiField>();
   for (MemberInfo constant : enumConstants) {
     if (constant.isChecked()) {
       this.enumConstants.add((PsiField) constant.getMember());
     }
   }
   this.fields = new ArrayList<PsiField>(fields);
   this.methods = new ArrayList<PsiMethod>(methods);
   this.innerClasses = new ArrayList<PsiClass>(classes);
   this.newClassName = newClassName;
   delegateFieldName = calculateDelegateFieldName();
   requiresBackpointer =
       new BackpointerUsageVisitor(fields, innerClasses, methods, sourceClass)
           .backpointerRequired();
   if (requiresBackpointer) {
     ContainerUtil.addAll(typeParams, sourceClass.getTypeParameters());
   } else {
     final Set<PsiTypeParameter> typeParamSet = new HashSet<PsiTypeParameter>();
     final TypeParametersVisitor visitor = new TypeParametersVisitor(typeParamSet);
     for (PsiField field : fields) {
       field.accept(visitor);
     }
     for (PsiMethod method : methods) {
       method.accept(visitor);
       // do not include method's type parameters in class signature
       typeParamSet.removeAll(Arrays.asList(method.getTypeParameters()));
     }
     typeParams.addAll(typeParamSet);
   }
   myClass =
       new WriteCommandAction<PsiClass>(myProject, getCommandName()) {
         @Override
         protected void run(@NotNull Result<PsiClass> result) throws Throwable {
           result.setResult(buildClass());
         }
       }.execute().getResultObject();
   myExtractEnumProcessor = new ExtractEnumProcessor(myProject, this.enumConstants, myClass);
 }
 @NotNull
 public static PsiClassType[] getExtendsListTypes(@NotNull PsiClass psiClass) {
   if (psiClass.isEnum()) {
     PsiClassType enumSuperType =
         getEnumSuperType(
             psiClass, JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory());
     return enumSuperType == null ? PsiClassType.EMPTY_ARRAY : new PsiClassType[] {enumSuperType};
   }
   if (psiClass.isAnnotationType()) {
     return new PsiClassType[] {
       getAnnotationSuperType(
           psiClass, JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory())
     };
   }
   final PsiReferenceList extendsList = psiClass.getExtendsList();
   if (extendsList != null) {
     return extendsList.getReferencedTypes();
   }
   return PsiClassType.EMPTY_ARRAY;
 }
 public PullUpProcessor(
     PsiClass sourceClass,
     PsiClass targetSuperClass,
     MemberInfo[] membersToMove,
     DocCommentPolicy javaDocPolicy) {
   super(sourceClass.getProject());
   mySourceClass = sourceClass;
   myTargetSuperClass = targetSuperClass;
   myMembersToMove = membersToMove;
   myJavaDocPolicy = javaDocPolicy;
 }
 private static void generateDelegate(JavaChangeInfo changeInfo)
     throws IncorrectOperationException {
   final PsiMethod delegate = (PsiMethod) changeInfo.getMethod().copy();
   final PsiClass targetClass = changeInfo.getMethod().getContainingClass();
   LOG.assertTrue(!targetClass.isInterface());
   PsiElementFactory factory = JavaPsiFacade.getElementFactory(targetClass.getProject());
   ChangeSignatureProcessor.makeEmptyBody(factory, delegate);
   final PsiCallExpression callExpression =
       ChangeSignatureProcessor.addDelegatingCallTemplate(delegate, changeInfo.getNewName());
   addDelegateArguments(changeInfo, factory, callExpression);
   targetClass.addBefore(delegate, changeInfo.getMethod());
 }
  @Override
  protected boolean preprocessUsages(@NotNull final Ref<UsageInfo[]> refUsages) {
    final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
    myExtractEnumProcessor.findEnumConstantConflicts(refUsages);
    if (!DestinationFolderComboBox.isAccessible(
        myProject,
        sourceClass.getContainingFile().getVirtualFile(),
        myClass.getContainingFile().getContainingDirectory().getVirtualFile())) {
      conflicts.putValue(
          sourceClass,
          "Extracted class won't be accessible in "
              + RefactoringUIUtil.getDescription(sourceClass, true));
    }
    ApplicationManager.getApplication()
        .runWriteAction(
            new Runnable() {
              public void run() {
                myClass.delete();
              }
            });
    final Project project = sourceClass.getProject();
    final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
    final PsiClass existingClass =
        JavaPsiFacade.getInstance(project).findClass(getQualifiedName(), scope);
    if (existingClass != null) {
      conflicts.putValue(
          existingClass,
          RefactorJBundle.message("cannot.perform.the.refactoring")
              + RefactorJBundle.message("there.already.exists.a.class.with.the.chosen.name"));
    }

    if (!myGenerateAccessors) {
      calculateInitializersConflicts(conflicts);
      final NecessaryAccessorsVisitor visitor = checkNecessaryGettersSetters4ExtractedClass();
      final NecessaryAccessorsVisitor srcVisitor = checkNecessaryGettersSetters4SourceClass();
      final Set<PsiField> fieldsNeedingGetter = new LinkedHashSet<PsiField>();
      fieldsNeedingGetter.addAll(visitor.getFieldsNeedingGetter());
      fieldsNeedingGetter.addAll(srcVisitor.getFieldsNeedingGetter());
      for (PsiField field : fieldsNeedingGetter) {
        conflicts.putValue(field, "Field \'" + field.getName() + "\' needs getter");
      }
      final Set<PsiField> fieldsNeedingSetter = new LinkedHashSet<PsiField>();
      fieldsNeedingSetter.addAll(visitor.getFieldsNeedingSetter());
      fieldsNeedingSetter.addAll(srcVisitor.getFieldsNeedingSetter());
      for (PsiField field : fieldsNeedingSetter) {
        conflicts.putValue(field, "Field \'" + field.getName() + "\' needs setter");
      }
    }
    checkConflicts(refUsages, conflicts);
    return showConflicts(conflicts, refUsages.get());
  }
Beispiel #13
0
 public static boolean nameCanBeImported(@NotNull String fqName, @NotNull PsiElement context) {
   final PsiClass containingClass = PsiTreeUtil.getParentOfType(context, PsiClass.class);
   if (containingClass != null) {
     if (fqName.equals(containingClass.getQualifiedName())) {
       return true;
     }
     final String shortName = ClassUtil.extractClassName(fqName);
     final PsiClass[] innerClasses = containingClass.getAllInnerClasses();
     for (PsiClass innerClass : innerClasses) {
       if (innerClass.hasModifierProperty(PsiModifier.PRIVATE)) {
         continue;
       }
       if (innerClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
         if (!ClassUtils.inSamePackage(innerClass, containingClass)) {
           continue;
         }
       }
       final String className = innerClass.getName();
       if (shortName.equals(className)) {
         return false;
       }
     }
     PsiField field = containingClass.findFieldByName(shortName, false);
     if (field != null) {
       return false;
     }
     field = containingClass.findFieldByName(shortName, true);
     if (field != null
         && PsiUtil.isAccessible(containingClass.getProject(), field, containingClass, null)) {
       return false;
     }
   }
   final PsiJavaFile file = PsiTreeUtil.getParentOfType(context, PsiJavaFile.class);
   if (file == null) {
     return false;
   }
   if (hasExactImportConflict(fqName, file)) {
     return false;
   }
   if (hasOnDemandImportConflict(fqName, file, true)) {
     return false;
   }
   if (containsConflictingReference(file, fqName)) {
     return false;
   }
   if (containsConflictingClass(fqName, file)) {
     return false;
   }
   return !containsConflictingClassName(fqName, file);
 }
 @NotNull
 private static ParameterizedCachedValue<MembersMap, PsiClass> getValues(
     @NotNull PsiClass aClass) {
   ParameterizedCachedValue<MembersMap, PsiClass> value = aClass.getUserData(MAP_IN_CLASS_KEY);
   if (value == null) {
     value =
         CachedValuesManager.getManager(aClass.getProject())
             .createParameterizedCachedValue(ByNameCachedValueProvider.INSTANCE, false);
     // Do not cache for nonphysical elements
     if (aClass.isPhysical()) {
       value = ((UserDataHolderEx) aClass).putUserDataIfAbsent(MAP_IN_CLASS_KEY, value);
     }
   }
   return value;
 }
 @Nullable
 public static PsiMethod findPsiMethod(PsiManager manager, String externalName) {
   final int spaceIdx = externalName.indexOf(' ');
   final String className = externalName.substring(0, spaceIdx);
   final PsiClass psiClass = ClassUtil.findPsiClass(manager, className);
   if (psiClass == null) return null;
   try {
     PsiElementFactory factory =
         JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory();
     String methodSignature = externalName.substring(spaceIdx + 1);
     PsiMethod patternMethod = factory.createMethodFromText(methodSignature, psiClass);
     return psiClass.findMethodBySignature(patternMethod, false);
   } catch (IncorrectOperationException e) {
     // Do nothing. Returning null is acceptable in this case.
     return null;
   }
 }
  private List<PsiClass> calculateInterfacesSupported() {
    final List<PsiClass> out = new ArrayList<PsiClass>();
    final PsiClass[] supers = sourceClass.getSupers();
    for (PsiClass superClass : supers) {
      if (!superClass.isInterface()) {
        continue;
      }
      final PsiMethod[] superclassMethods = superClass.getMethods();
      if (superclassMethods.length == 0) {
        continue;
      }
      boolean allMethodsCovered = true;

      for (PsiMethod method : superclassMethods) {
        boolean isCovered = false;
        for (PsiMethod movedMethod : methods) {
          if (isSuperMethod(method, movedMethod)) {
            isCovered = true;
            break;
          }
        }
        if (!isCovered) {
          allMethodsCovered = false;
          break;
        }
      }
      if (allMethodsCovered) {
        out.add(superClass);
      }
    }
    final Project project = sourceClass.getProject();
    final PsiManager manager = sourceClass.getManager();
    final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
    if (usesDefaultSerialization(sourceClass)) {
      final PsiClass serializable =
          JavaPsiFacade.getInstance(manager.getProject()).findClass("java.io.Serializable", scope);
      out.add(serializable);
    }
    if (usesDefaultClone(sourceClass)) {
      final PsiClass cloneable =
          JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.Cloneable", scope);
      out.add(cloneable);
    }
    return out;
  }
 private static boolean usesDefaultClone(PsiClass aClass) {
   final Project project = aClass.getProject();
   final PsiManager manager = aClass.getManager();
   final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
   final PsiClass cloneable =
       JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.Cloneable", scope);
   if (!InheritanceUtil.isInheritorOrSelf(aClass, cloneable, true)) {
     return false;
   }
   final PsiMethod[] methods = aClass.findMethodsByName("clone", false);
   for (PsiMethod method : methods) {
     final PsiParameterList parameterList = method.getParameterList();
     final PsiParameter[] parameters = parameterList.getParameters();
     if (parameters.length == 0) {
       return false;
     }
   }
   return true;
 }
  public static boolean isSourceLevelAccessible(
      PsiElement context, PsiClass psiClass, final boolean pkgContext) {
    if (!JavaPsiFacade.getInstance(psiClass.getProject())
        .getResolveHelper()
        .isAccessible(psiClass, context, null)) {
      return false;
    }

    if (pkgContext) {
      PsiClass topLevel = PsiUtil.getTopLevelClass(psiClass);
      if (topLevel != null) {
        String fqName = topLevel.getQualifiedName();
        if (fqName != null && StringUtil.isEmpty(StringUtil.getPackageName(fqName))) {
          return false;
        }
      }
    }

    return true;
  }
  private static boolean isSuperMethod(
      PsiClass aClass,
      HierarchicalMethodSignature hierarchicalMethodSignature,
      HierarchicalMethodSignature superSignatureHierarchical) {
    PsiMethod superMethod = superSignatureHierarchical.getMethod();
    PsiClass superClass = superMethod.getContainingClass();
    PsiClass containingClass = hierarchicalMethodSignature.getMethod().getContainingClass();
    if (!superMethod.isConstructor()) {
      if (!aClass.equals(superClass)) {
        if (PsiUtil.isAccessible(aClass.getProject(), superMethod, aClass, aClass)) {
          if (MethodSignatureUtil.isSubsignature(
              superSignatureHierarchical, hierarchicalMethodSignature)) {
            if (superClass != null) {
              if (superClass.isInterface()
                  || CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) {
                if (superMethod.hasModifierProperty(PsiModifier.DEFAULT)
                    || hierarchicalMethodSignature
                        .getMethod()
                        .hasModifierProperty(PsiModifier.DEFAULT)) {
                  return !InheritanceUtil.isInheritorOrSelf(superClass, containingClass, true);
                }
                return true;
              }

              if (containingClass != null) {
                if (containingClass.isInterface()) {
                  return false;
                }

                if (!aClass.isInterface()
                    && !InheritanceUtil.isInheritorOrSelf(superClass, containingClass, true)) {
                  return true;
                }
              }
            }
          }
        }
      }
    }
    return false;
  }
 @Override
 public PsiType visitClassType(PsiClassType classType) {
   final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
   final PsiClass aClass = resolveResult.getElement();
   if (aClass == null) return classType;
   if (aClass instanceof PsiTypeParameter) {
     final PsiTypeParameter typeParameter = (PsiTypeParameter) aClass;
     if (containsInMap(typeParameter)) {
       return substituteTypeParameter(typeParameter);
     } else {
       return classType;
     }
   }
   final Map<PsiTypeParameter, PsiType> hashMap = new HashMap<PsiTypeParameter, PsiType>(2);
   if (!processClass(aClass, resolveResult.getSubstitutor(), hashMap)) {
     return null;
   }
   return JavaPsiFacade.getInstance(aClass.getProject())
       .getElementFactory()
       .createType(aClass, createSubstitutor(hashMap), classType.getLanguageLevel());
 }
  @NotNull
  public static SearchScope getClassUseScope(@NotNull PsiClass aClass) {
    if (aClass instanceof PsiAnonymousClass) {
      return new LocalSearchScope(aClass);
    }
    final GlobalSearchScope maximalUseScope = ResolveScopeManager.getElementUseScope(aClass);
    PsiFile file = aClass.getContainingFile();
    if (PsiImplUtil.isInServerPage(file)) return maximalUseScope;
    final PsiClass containingClass = aClass.getContainingClass();
    if (aClass.hasModifierProperty(PsiModifier.PUBLIC)
        || aClass.hasModifierProperty(PsiModifier.PROTECTED)) {
      return containingClass == null ? maximalUseScope : containingClass.getUseScope();
    } else if (aClass.hasModifierProperty(PsiModifier.PRIVATE)
        || aClass instanceof PsiTypeParameter) {
      PsiClass topClass = PsiUtil.getTopLevelClass(aClass);
      return new LocalSearchScope(topClass == null ? aClass.getContainingFile() : topClass);
    } else {
      PsiPackage aPackage = null;
      if (file instanceof PsiJavaFile) {
        aPackage =
            JavaPsiFacade.getInstance(aClass.getProject())
                .findPackage(((PsiJavaFile) file).getPackageName());
      }

      if (aPackage == null) {
        PsiDirectory dir = file.getContainingDirectory();
        if (dir != null) {
          aPackage = JavaDirectoryService.getInstance().getPackage(dir);
        }
      }

      if (aPackage != null) {
        SearchScope scope = PackageScope.packageScope(aPackage, false);
        scope = scope.intersectWith(maximalUseScope);
        return scope;
      }

      return new LocalSearchScope(file);
    }
  }
  private String calculateDelegateFieldName() {
    final Project project = sourceClass.getProject();
    final CodeStyleSettingsManager settingsManager = CodeStyleSettingsManager.getInstance(project);
    final CodeStyleSettings settings = settingsManager.getCurrentSettings();

    final String baseName =
        settings.FIELD_NAME_PREFIX.length() == 0
            ? StringUtil.decapitalize(newClassName)
            : newClassName;
    String name = settings.FIELD_NAME_PREFIX + baseName + settings.FIELD_NAME_SUFFIX;
    if (!existsFieldWithName(name) && !PsiNameHelper.getInstance(project).isKeyword(name)) {
      return name;
    }
    int counter = 1;
    while (true) {
      name = settings.FIELD_NAME_PREFIX + baseName + counter + settings.FIELD_NAME_SUFFIX;
      if (!existsFieldWithName(name) && !PsiNameHelper.getInstance(project).isKeyword(name)) {
        return name;
      }
      counter++;
    }
  }
 private static boolean usesDefaultSerialization(PsiClass aClass) {
   final Project project = aClass.getProject();
   final PsiManager manager = aClass.getManager();
   final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
   final PsiClass serializable =
       JavaPsiFacade.getInstance(manager.getProject()).findClass("java.io.Serializable", scope);
   if (!InheritanceUtil.isInheritorOrSelf(aClass, serializable, true)) {
     return false;
   }
   final PsiMethod[] methods = aClass.findMethodsByName("writeObject", false);
   for (PsiMethod method : methods) {
     final PsiParameterList parameterList = method.getParameterList();
     final PsiParameter[] parameters = parameterList.getParameters();
     if (parameters.length == 1) {
       final PsiType type = parameters[0].getType();
       final String text = type.getCanonicalText();
       if ("java.io.DataOutputStream".equals(text)) {
         return false;
       }
     }
   }
   return true;
 }
  private void makeArray(PsiVariable variable) throws IncorrectOperationException {
    PsiType type = variable.getType();

    PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory();
    PsiType newType = type.createArrayType();

    PsiDeclarationStatement variableDeclarationStatement;
    PsiExpression initializer = variable.getInitializer();
    if (initializer == null) {
      String expression = "[1]";
      while (type instanceof PsiArrayType) {
        expression += "[1]";
        type = ((PsiArrayType) type).getComponentType();
      }
      PsiExpression init =
          factory.createExpressionFromText("new " + type.getCanonicalText() + expression, variable);
      variableDeclarationStatement =
          factory.createVariableDeclarationStatement(variable.getName(), newType, init);
    } else {
      PsiExpression init =
          factory.createExpressionFromText("{ " + initializer.getText() + " }", variable);
      variableDeclarationStatement =
          factory.createVariableDeclarationStatement(variable.getName(), newType, init);
    }
    PsiVariable newVariable = (PsiVariable) variableDeclarationStatement.getDeclaredElements()[0];
    PsiUtil.setModifierProperty(newVariable, PsiModifier.FINAL, true);
    PsiElement newExpression =
        factory.createExpressionFromText(variable.getName() + "[0]", variable);

    PsiElement outerCodeBlock = PsiUtil.getVariableCodeBlock(variable, null);
    if (outerCodeBlock == null) return;
    List<PsiReferenceExpression> outerReferences = new ArrayList<PsiReferenceExpression>();
    collectReferences(outerCodeBlock, variable, outerReferences);
    replaceReferences(outerReferences, newExpression);
    variable.replace(newVariable);
  }
  static boolean isSideEffectFreeConstructor(PsiNewExpression newExpression) {
    PsiJavaCodeReferenceElement classReference = newExpression.getClassReference();
    PsiClass aClass = classReference == null ? null : (PsiClass) classReference.resolve();
    String qualifiedName = aClass == null ? null : aClass.getQualifiedName();
    if (qualifiedName == null) return false;
    if (ourSideEffectFreeClasses.contains(qualifiedName)) return true;

    PsiFile file = aClass.getContainingFile();
    PsiDirectory directory = file.getContainingDirectory();
    PsiPackage classPackage = JavaDirectoryService.getInstance().getPackage(directory);
    String packageName = classPackage == null ? null : classPackage.getQualifiedName();

    // all Throwable descendants from java.lang are side effects free
    if ("java.lang".equals(packageName) || "java.io".equals(packageName)) {
      PsiClass throwableClass =
          JavaPsiFacade.getInstance(aClass.getProject())
              .findClass("java.lang.Throwable", aClass.getResolveScope());
      if (throwableClass != null
          && InheritanceUtil.isInheritorOrSelf(aClass, throwableClass, true)) {
        return true;
      }
    }
    return false;
  }
  private static boolean processDeclarationsInClassNotCached(
      @NotNull PsiClass aClass,
      @NotNull PsiScopeProcessor processor,
      @NotNull ResolveState state,
      @Nullable Set<PsiClass> visited,
      PsiElement last,
      @NotNull PsiElement place,
      boolean isRaw,
      @NotNull LanguageLevel languageLevel) {
    if (visited == null) visited = new THashSet<PsiClass>();
    if (!visited.add(aClass)) return true;
    processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass);
    final ElementClassHint classHint = processor.getHint(ElementClassHint.KEY);
    final NameHint nameHint = processor.getHint(NameHint.KEY);

    if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.FIELD)) {
      if (nameHint != null) {
        final PsiField fieldByName = aClass.findFieldByName(nameHint.getName(state), false);
        if (fieldByName != null && !processor.execute(fieldByName, state)) return false;
      } else {
        final PsiField[] fields = aClass.getFields();
        for (final PsiField field : fields) {
          if (!processor.execute(field, state)) return false;
        }
      }
    }

    PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory();

    if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.METHOD)) {
      PsiSubstitutor baseSubstitutor = state.get(PsiSubstitutor.KEY);
      final PsiMethod[] methods =
          nameHint != null
              ? aClass.findMethodsByName(nameHint.getName(state), false)
              : aClass.getMethods();
      for (final PsiMethod method : methods) {
        PsiSubstitutor finalSubstitutor = checkRaw(isRaw, factory, method, baseSubstitutor);
        ResolveState methodState =
            finalSubstitutor == baseSubstitutor
                ? state
                : state.put(PsiSubstitutor.KEY, finalSubstitutor);
        if (!processor.execute(method, methodState)) return false;
      }
    }

    if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) {
      if (last != null && last.getParent() == aClass) {
        // Parameters
        final PsiTypeParameterList list = aClass.getTypeParameterList();
        if (list != null
            && !list.processDeclarations(processor, ResolveState.initial(), last, place))
          return false;
      }

      if (!(last instanceof PsiReferenceList) && !(last instanceof PsiModifierList)) {
        // Inners
        if (nameHint != null) {
          final PsiClass inner = aClass.findInnerClassByName(nameHint.getName(state), false);
          if (inner != null) {
            if (!processor.execute(inner, state)) return false;
          }
        } else {
          final PsiClass[] inners = aClass.getInnerClasses();
          for (final PsiClass inner : inners) {
            if (!processor.execute(inner, state)) return false;
          }
        }
      }
    }

    return last instanceof PsiReferenceList
        || processSuperTypes(
            aClass, processor, visited, last, place, state, isRaw, factory, languageLevel);
  }
  private static AllowedValues parseBeanInfo(@NotNull PsiModifierListOwner owner) {
    PsiMethod method = null;
    if (owner instanceof PsiParameter) {
      PsiParameter parameter = (PsiParameter) owner;
      PsiElement scope = parameter.getDeclarationScope();
      if (!(scope instanceof PsiMethod)) return null;
      PsiElement nav = scope.getNavigationElement();
      if (!(nav instanceof PsiMethod)) return null;
      method = (PsiMethod) nav;
      if (method.isConstructor()) {
        // not a property, try the @ConstructorProperties({"prop"})
        PsiAnnotation annotation =
            AnnotationUtil.findAnnotation(method, "java.beans.ConstructorProperties");
        if (annotation == null) return null;
        PsiAnnotationMemberValue value = annotation.findAttributeValue("value");
        if (!(value instanceof PsiArrayInitializerMemberValue)) return null;
        PsiAnnotationMemberValue[] initializers =
            ((PsiArrayInitializerMemberValue) value).getInitializers();
        PsiElement parent = parameter.getParent();
        if (!(parent instanceof PsiParameterList)) return null;
        int index = ((PsiParameterList) parent).getParameterIndex(parameter);
        if (index >= initializers.length) return null;
        PsiAnnotationMemberValue initializer = initializers[index];
        if (!(initializer instanceof PsiLiteralExpression)) return null;
        Object val = ((PsiLiteralExpression) initializer).getValue();
        if (!(val instanceof String)) return null;
        PsiMethod setter =
            PropertyUtil.findPropertySetter(
                method.getContainingClass(), (String) val, false, false);
        if (setter == null) return null;
        // try the @beaninfo of the corresponding setter
        method = (PsiMethod) setter.getNavigationElement();
      }
    } else if (owner instanceof PsiMethod) {
      PsiElement nav = owner.getNavigationElement();
      if (!(nav instanceof PsiMethod)) return null;
      method = (PsiMethod) nav;
    }
    if (method == null) return null;

    PsiClass aClass = method.getContainingClass();
    if (aClass == null) return null;
    if (PropertyUtil.isSimplePropertyGetter(method)) {
      List<PsiMethod> setters =
          PropertyUtil.getSetters(aClass, PropertyUtil.getPropertyNameByGetter(method));
      if (setters.size() != 1) return null;
      method = setters.get(0);
    }
    if (!PropertyUtil.isSimplePropertySetter(method)) return null;
    PsiDocComment doc = method.getDocComment();
    if (doc == null) return null;
    PsiDocTag beaninfo = doc.findTagByName("beaninfo");
    if (beaninfo == null) return null;
    String data =
        StringUtil.join(
            beaninfo.getDataElements(),
            new Function<PsiElement, String>() {
              @Override
              public String fun(PsiElement element) {
                return element.getText();
              }
            },
            "\n");
    int enumIndex = StringUtil.indexOfSubstringEnd(data, "enum:");
    if (enumIndex == -1) return null;
    data = data.substring(enumIndex);
    int colon = data.indexOf(":");
    int last = colon == -1 ? data.length() : data.substring(0, colon).lastIndexOf("\n");
    data = data.substring(0, last);

    List<PsiAnnotationMemberValue> values = new ArrayList<PsiAnnotationMemberValue>();
    for (String line : StringUtil.splitByLines(data)) {
      List<String> words = StringUtil.split(line, " ", true, true);
      if (words.size() != 2) continue;
      String ref = words.get(1);
      PsiExpression constRef =
          JavaPsiFacade.getElementFactory(aClass.getProject())
              .createExpressionFromText(ref, aClass);
      if (!(constRef instanceof PsiReferenceExpression)) continue;
      PsiReferenceExpression expr = (PsiReferenceExpression) constRef;
      values.add(expr);
    }
    if (values.isEmpty()) return null;
    PsiAnnotationMemberValue[] array = values.toArray(new PsiAnnotationMemberValue[values.size()]);
    return new AllowedValues(array, false);
  }
  private static boolean processCachedMembersByName(
      @NotNull PsiClass aClass,
      @NotNull PsiScopeProcessor processor,
      @NotNull ResolveState state,
      @Nullable Set<PsiClass> visited,
      PsiElement last,
      @NotNull PsiElement place,
      boolean isRaw,
      @NotNull PsiSubstitutor substitutor,
      @NotNull MembersMap value,
      String name,
      @NotNull LanguageLevel languageLevel) {
    final ElementClassHint classHint = processor.getHint(ElementClassHint.KEY);

    PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory();

    if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.FIELD)) {
      final PsiField fieldByName = aClass.findFieldByName(name, false);
      if (fieldByName != null) {
        processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass);
        if (!processor.execute(fieldByName, state)) return false;
      } else {
        final Map<String, List<Pair<PsiMember, PsiSubstitutor>>> allFieldsMap =
            value.get(MemberType.FIELD);

        final List<Pair<PsiMember, PsiSubstitutor>> list = allFieldsMap.get(name);
        if (list != null) {
          for (final Pair<PsiMember, PsiSubstitutor> candidate : list) {
            PsiMember candidateField = candidate.getFirst();
            PsiSubstitutor finalSubstitutor =
                obtainFinalSubstitutor(
                    candidateField.getContainingClass(),
                    candidate.getSecond(),
                    aClass,
                    substitutor,
                    factory,
                    languageLevel);

            processor.handleEvent(
                PsiScopeProcessor.Event.SET_DECLARATION_HOLDER,
                candidateField.getContainingClass());
            if (!processor.execute(candidateField, state.put(PsiSubstitutor.KEY, finalSubstitutor)))
              return false;
          }
        }
      }
    }
    if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) {
      if (last != null && last.getParent() == aClass) {
        if (last instanceof PsiClass) {
          if (!processor.execute(last, state)) return false;
        }
        // Parameters
        final PsiTypeParameterList list = aClass.getTypeParameterList();
        if (list != null && !list.processDeclarations(processor, state, last, place)) return false;
      }
      if (!(last instanceof PsiReferenceList)) {
        final PsiClass classByName = aClass.findInnerClassByName(name, false);
        if (classByName != null) {
          processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass);
          if (!processor.execute(classByName, state)) return false;
        } else {
          Map<String, List<Pair<PsiMember, PsiSubstitutor>>> allClassesMap =
              value.get(MemberType.CLASS);

          List<Pair<PsiMember, PsiSubstitutor>> list = allClassesMap.get(name);
          if (list != null) {
            for (final Pair<PsiMember, PsiSubstitutor> candidate : list) {
              PsiMember inner = candidate.getFirst();
              PsiClass containingClass = inner.getContainingClass();
              if (containingClass != null) {
                PsiSubstitutor finalSubstitutor =
                    obtainFinalSubstitutor(
                        containingClass,
                        candidate.getSecond(),
                        aClass,
                        substitutor,
                        factory,
                        languageLevel);
                processor.handleEvent(
                    PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, containingClass);
                if (!processor.execute(inner, state.put(PsiSubstitutor.KEY, finalSubstitutor)))
                  return false;
              }
            }
          }
        }
      }
    }
    if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.METHOD)) {
      if (processor instanceof MethodResolverProcessor) {
        final MethodResolverProcessor methodResolverProcessor = (MethodResolverProcessor) processor;
        if (methodResolverProcessor.isConstructor()) {
          final PsiMethod[] constructors = aClass.getConstructors();
          methodResolverProcessor.handleEvent(
              PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass);
          for (PsiMethod constructor : constructors) {
            if (!methodResolverProcessor.execute(constructor, state)) return false;
          }
          return true;
        }
      }
      Map<String, List<Pair<PsiMember, PsiSubstitutor>>> allMethodsMap =
          value.get(MemberType.METHOD);
      List<Pair<PsiMember, PsiSubstitutor>> list = allMethodsMap.get(name);
      if (list != null) {
        for (final Pair<PsiMember, PsiSubstitutor> candidate : list) {
          ProgressIndicatorProvider.checkCanceled();
          PsiMethod candidateMethod = (PsiMethod) candidate.getFirst();
          if (processor instanceof MethodResolverProcessor) {
            if (candidateMethod.isConstructor()
                != ((MethodResolverProcessor) processor).isConstructor()) continue;
          }
          final PsiClass containingClass = candidateMethod.getContainingClass();
          if (visited != null && visited.contains(candidateMethod.getContainingClass())) {
            continue;
          }

          PsiSubstitutor finalSubstitutor =
              obtainFinalSubstitutor(
                  containingClass,
                  candidate.getSecond(),
                  aClass,
                  substitutor,
                  factory,
                  languageLevel);
          finalSubstitutor = checkRaw(isRaw, factory, candidateMethod, finalSubstitutor);
          processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, containingClass);
          if (!processor.execute(candidateMethod, state.put(PsiSubstitutor.KEY, finalSubstitutor)))
            return false;
        }

        if (visited != null) {
          for (Pair<PsiMember, PsiSubstitutor> aList : list) {
            visited.add(aList.getFirst().getContainingClass());
          }
        }
      }
    }
    return true;
  }
  private PsiClass buildClass() {
    final PsiManager manager = sourceClass.getManager();
    final Project project = sourceClass.getProject();
    final ExtractedClassBuilder extractedClassBuilder = new ExtractedClassBuilder();
    extractedClassBuilder.setProject(myProject);
    extractedClassBuilder.setClassName(newClassName);
    extractedClassBuilder.setPackageName(newPackageName);
    extractedClassBuilder.setOriginalClassName(sourceClass.getQualifiedName());
    extractedClassBuilder.setRequiresBackPointer(requiresBackpointer);
    extractedClassBuilder.setExtractAsEnum(enumConstants);
    for (PsiField field : fields) {
      extractedClassBuilder.addField(field);
    }
    for (PsiMethod method : methods) {
      extractedClassBuilder.addMethod(method);
    }
    for (PsiClass innerClass : innerClasses) {
      extractedClassBuilder.addInnerClass(
          innerClass, innerClassesToMakePublic.contains(innerClass));
    }
    extractedClassBuilder.setTypeArguments(typeParams);
    final List<PsiClass> interfaces = calculateInterfacesSupported();
    extractedClassBuilder.setInterfaces(interfaces);

    if (myGenerateAccessors) {
      final NecessaryAccessorsVisitor visitor = checkNecessaryGettersSetters4ExtractedClass();
      sourceClass.accept(visitor);
      extractedClassBuilder.setFieldsNeedingGetters(visitor.getFieldsNeedingGetter());
      extractedClassBuilder.setFieldsNeedingSetters(visitor.getFieldsNeedingSetter());
    }

    final String classString = extractedClassBuilder.buildBeanClass();
    if (extractInnerClass) {
      final PsiFileFactory factory = PsiFileFactory.getInstance(project);
      final PsiJavaFile newFile =
          (PsiJavaFile)
              factory.createFileFromText(
                  newClassName + ".java", JavaFileType.INSTANCE, classString);
      final PsiClass psiClass = newFile.getClasses()[0];
      if (!psiClass.isEnum()) {
        final PsiModifierList modifierList = psiClass.getModifierList();
        assert modifierList != null;
        modifierList.setModifierProperty(PsiModifier.STATIC, true);
      }
      final PsiElement addedClass = sourceClass.add(psiClass);
      return (PsiClass)
          CodeStyleManager.getInstance(manager)
              .reformat(
                  JavaCodeStyleManager.getInstance(project).shortenClassReferences(addedClass));
    }

    try {
      final PsiFile containingFile = sourceClass.getContainingFile();
      final PsiDirectory directory;
      final PsiDirectory containingDirectory = containingFile.getContainingDirectory();
      if (myMoveDestination != null) {
        directory = myMoveDestination.getTargetDirectory(containingDirectory);
      } else {
        final Module module = ModuleUtil.findModuleForPsiElement(containingFile);
        assert module != null;
        directory =
            PackageUtil.findOrCreateDirectoryForPackage(
                module, newPackageName, containingDirectory, false, true);
      }
      if (directory != null) {
        final PsiFileFactory factory = PsiFileFactory.getInstance(project);
        final PsiFile newFile =
            factory.createFileFromText(newClassName + ".java", JavaFileType.INSTANCE, classString);
        final PsiElement addedFile = directory.add(newFile);
        final CodeStyleManager codeStyleManager =
            CodeStyleManager.getInstance(manager.getProject());
        final PsiElement shortenedFile =
            JavaCodeStyleManager.getInstance(project).shortenClassReferences(addedFile);
        return ((PsiJavaFile) codeStyleManager.reformat(shortenedFile)).getClasses()[0];
      } else {
        return null;
      }
    } catch (IncorrectOperationException e) {
      return null;
    }
  }
  private static Map<MethodSignature, HierarchicalMethodSignature> buildMethodHierarchy(
      PsiClass aClass,
      PsiSubstitutor substitutor,
      final boolean includePrivates,
      final Set<PsiClass> visited,
      boolean isInRawContext) {
    Map<MethodSignature, HierarchicalMethodSignature> result =
        new LinkedHashMap<MethodSignature, HierarchicalMethodSignature>();
    final Map<MethodSignature, List<PsiMethod>> sameParameterErasureMethods =
        new THashMap<MethodSignature, List<PsiMethod>>(
            MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);

    Map<MethodSignature, HierarchicalMethodSignatureImpl> map =
        new THashMap<MethodSignature, HierarchicalMethodSignatureImpl>(
            new TObjectHashingStrategy<MethodSignature>() {
              @Override
              public int computeHashCode(MethodSignature signature) {
                return MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY.computeHashCode(
                    signature);
              }

              @Override
              public boolean equals(MethodSignature o1, MethodSignature o2) {
                if (!MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY.equals(o1, o2))
                  return false;
                List<PsiMethod> list = sameParameterErasureMethods.get(o1);
                boolean toCheckReturnType = list != null && list.size() > 1;
                if (!toCheckReturnType) return true;
                PsiType returnType1 =
                    ((MethodSignatureBackedByPsiMethod) o1).getMethod().getReturnType();
                PsiType returnType2 =
                    ((MethodSignatureBackedByPsiMethod) o2).getMethod().getReturnType();
                if (returnType1 == null && returnType2 == null) return true;
                if (returnType1 == null || returnType2 == null) return false;

                PsiType erasure1 =
                    TypeConversionUtil.erasure(o1.getSubstitutor().substitute(returnType1));
                PsiType erasure2 =
                    TypeConversionUtil.erasure(o2.getSubstitutor().substitute(returnType2));
                return erasure1.equals(erasure2);
              }
            });

    for (PsiMethod method : aClass.getMethods()) {
      if (!method.isValid()) {
        throw new PsiInvalidElementAccessException(
            method, "class.valid=" + aClass.isValid() + "; name=" + method.getName());
      }
      if (!includePrivates && method.hasModifierProperty(PsiModifier.PRIVATE)) continue;
      final MethodSignatureBackedByPsiMethod signature =
          MethodSignatureBackedByPsiMethod.create(method, substitutor, isInRawContext);
      HierarchicalMethodSignatureImpl newH = new HierarchicalMethodSignatureImpl(signature);

      List<PsiMethod> list = sameParameterErasureMethods.get(signature);
      if (list == null) {
        list = new SmartList<PsiMethod>();
        sameParameterErasureMethods.put(signature, list);
      }
      list.add(method);

      LOG.assertTrue(newH.getMethod().isValid());
      result.put(signature, newH);
      map.put(signature, newH);
    }

    for (PsiClassType superType : aClass.getSuperTypes()) {
      PsiClassType.ClassResolveResult superTypeResolveResult = superType.resolveGenerics();
      PsiClass superClass = superTypeResolveResult.getElement();
      if (superClass == null) continue;
      if (!visited.add(superClass)) continue; // cyclic inheritance
      final PsiSubstitutor superSubstitutor = superTypeResolveResult.getSubstitutor();
      PsiSubstitutor finalSubstitutor =
          obtainFinalSubstitutor(superClass, superSubstitutor, substitutor, isInRawContext);

      final boolean isInRawContextSuper =
          (isInRawContext || PsiUtil.isRawSubstitutor(superClass, superSubstitutor))
              && superClass.getTypeParameters().length != 0;
      Map<MethodSignature, HierarchicalMethodSignature> superResult =
          buildMethodHierarchy(superClass, finalSubstitutor, false, visited, isInRawContextSuper);
      visited.remove(superClass);

      List<Pair<MethodSignature, HierarchicalMethodSignature>> flattened =
          new ArrayList<Pair<MethodSignature, HierarchicalMethodSignature>>();
      for (Map.Entry<MethodSignature, HierarchicalMethodSignature> entry : superResult.entrySet()) {
        HierarchicalMethodSignature hms = entry.getValue();
        MethodSignature signature = entry.getKey();
        PsiClass containingClass = hms.getMethod().getContainingClass();
        List<HierarchicalMethodSignature> supers =
            new ArrayList<HierarchicalMethodSignature>(hms.getSuperSignatures());
        for (HierarchicalMethodSignature aSuper : supers) {
          PsiClass superContainingClass = aSuper.getMethod().getContainingClass();
          if (containingClass != null
              && superContainingClass != null
              && !containingClass.isInheritor(superContainingClass, true)) {
            // methods must be inherited from unrelated classes, so flatten hierarchy here
            // class C implements SAM1, SAM2 { void methodimpl() {} }
            // hms.getSuperSignatures().remove(aSuper);
            flattened.add(
                new Pair<MethodSignature, HierarchicalMethodSignature>(signature, aSuper));
          }
        }
        putInMap(aClass, result, map, hms, signature);
      }
      for (Pair<MethodSignature, HierarchicalMethodSignature> pair : flattened) {
        putInMap(aClass, result, map, pair.second, pair.first);
      }
    }

    for (Map.Entry<MethodSignature, HierarchicalMethodSignatureImpl> entry : map.entrySet()) {
      HierarchicalMethodSignatureImpl hierarchicalMethodSignature = entry.getValue();
      MethodSignature methodSignature = entry.getKey();
      if (result.get(methodSignature) == null
          && PsiUtil.isAccessible(
              aClass.getProject(), hierarchicalMethodSignature.getMethod(), aClass, aClass)) {
        LOG.assertTrue(hierarchicalMethodSignature.getMethod().isValid());
        result.put(methodSignature, hierarchicalMethodSignature);
      }
    }

    return result;
  }