@Override
  public void renameElement(
      PsiElement element,
      String newName,
      UsageInfo[] usages,
      @Nullable RefactoringElementListener listener)
      throws IncorrectOperationException {
    // see RenameUtil#doRenameGenericNamedElement
    boolean hasBindables = false;
    for (UsageInfo usage : usages) {
      if (!(usage.getReference() instanceof BindablePsiReference)) {
        RenameUtil.rename(usage, newName);
      } else {
        hasBindables = true;
      }
    }

    ErlangPsiImplUtil.renameQAtom((ErlangQAtom) element, newName);

    if (hasBindables) {
      for (UsageInfo usage : usages) {
        final PsiReference ref = usage.getReference();
        if (ref instanceof BindablePsiReference) {
          try {
            ref.bindToElement(element);
          } catch (IncorrectOperationException e) { // fall back to old scheme
            ref.handleElementRename(newName);
          }
        }
      }
    }
    if (listener != null) {
      listener.elementRenamed(element);
    }
  }
  public static void doRenameGenericNamedElement(
      @NotNull PsiElement namedElement,
      String newName,
      UsageInfo[] usages,
      @Nullable RefactoringElementListener listener)
      throws IncorrectOperationException {
    PsiWritableMetaData writableMetaData = null;
    if (namedElement instanceof PsiMetaOwner) {
      final PsiMetaData metaData = ((PsiMetaOwner) namedElement).getMetaData();
      if (metaData instanceof PsiWritableMetaData) {
        writableMetaData = (PsiWritableMetaData) metaData;
      }
    }
    if (writableMetaData == null && !(namedElement instanceof PsiNamedElement)) {
      LOG.error("Unknown element type:" + namedElement);
    }

    boolean hasBindables = false;
    for (UsageInfo usage : usages) {
      if (!(usage.getReference() instanceof BindablePsiReference)) {
        rename(usage, newName);
      } else {
        hasBindables = true;
      }
    }

    if (writableMetaData != null) {
      writableMetaData.setName(newName);
    } else {
      PsiElement namedElementAfterRename = ((PsiNamedElement) namedElement).setName(newName);
      if (namedElementAfterRename != null) namedElement = namedElementAfterRename;
    }

    if (hasBindables) {
      for (UsageInfo usage : usages) {
        final PsiReference ref = usage.getReference();
        if (ref instanceof BindablePsiReference) {
          try {
            ref.bindToElement(namedElement);
          } catch (IncorrectOperationException e) { // fall back to old scheme
            ref.handleElementRename(newName);
          }
        }
      }
    }
    if (listener != null) {
      listener.elementRenamed(namedElement);
    }
  }
  @Override
  public void renameElement(
      final PsiElement psiElement,
      final String newName,
      final UsageInfo[] usages,
      final RefactoringElementListener listener)
      throws IncorrectOperationException {

    final GrField field = (GrField) psiElement;
    final PsiMethod getter = GroovyPropertyUtils.findGetterForField(field);
    final PsiMethod setter = GroovyPropertyUtils.findSetterForField(field);
    final String newGetterName =
        (getter != null && getter.getName().startsWith("is") ? "is" : "get")
            + StringUtil.capitalize(newName);
    final String newSetterName = "set" + StringUtil.capitalize(newName);

    final PsiManager manager = field.getManager();

    List<PsiReference> getterRefs = new ArrayList<PsiReference>();
    List<PsiReference> setterRefs = new ArrayList<PsiReference>();
    List<PsiReference> fieldRefs = new ArrayList<PsiReference>();

    for (UsageInfo usage : usages) {
      final PsiElement element = usage.getElement();
      if (element == null) continue;

      PsiReference ref = element.findReferenceAt(usage.startOffset);
      if (ref == null) continue;

      PsiElement resolved = ref.resolve();
      if (manager.areElementsEquivalent(resolved, getter)) {
        if (isPropertyAccess(element)) {
          fieldRefs.add(ref);
        } else {
          getterRefs.add(ref);
        }
      } else if (manager.areElementsEquivalent(resolved, setter)) {
        if (isPropertyAccess(element)) {
          fieldRefs.add(ref);
        } else {
          setterRefs.add(ref);
        }
      } else if (manager.areElementsEquivalent(resolved, field)) {
        fieldRefs.add(ref);
      } else {
        ref.handleElementRename(newName);
      }
    }

    field.setName(newName);

    final PsiMethod newGetter = GroovyPropertyUtils.findGetterForField(field);
    doRename(newGetterName, manager, getterRefs, newGetter);

    final PsiMethod newSetter = GroovyPropertyUtils.findSetterForField(field);
    doRename(newSetterName, manager, setterRefs, newSetter);

    doRename(newName, manager, fieldRefs, field);

    listener.elementRenamed(field);
  }
  @Override
  public void renameElement(
      final PsiElement psiElement,
      String newName,
      final UsageInfo[] usages,
      @Nullable RefactoringElementListener listener)
      throws IncorrectOperationException {
    final GrField field = (GrField) psiElement;
    String fieldName = field.getName();

    NameProvider nameProvider = new NameProvider(field, newName);

    MultiMap<PsiNamedElement, UsageInfo> propertyUsages = MultiMap.createLinked();
    MultiMap<PsiNamedElement, UsageInfo> simpleUsages = MultiMap.createLinked();

    List<PsiReference> unknownUsages = new ArrayList<>();

    for (UsageInfo usage : usages) {
      final PsiReference ref = usage.getReference();
      if (ref instanceof GrReferenceExpression) {
        final GroovyResolveResult resolveResult = ((GrReferenceExpression) ref).advancedResolve();
        final PsiElement element = resolveResult.getElement();
        if (resolveResult.isInvokedOnProperty()) {
          propertyUsages.putValue((PsiNamedElement) element, usage);
        } else {
          simpleUsages.putValue((PsiNamedElement) element, usage);
        }
      } else if (ref != null) {
        unknownUsages.add(ref);
      }
    }

    for (PsiReference ref : unknownUsages) {
      handleElementRename(newName, ref, fieldName);
    }

    field.setName(newName);

    nameProvider.putNewElements(field);

    PsiManager manager = field.getManager();
    for (PsiNamedElement element : simpleUsages.keySet()) {
      for (UsageInfo info : simpleUsages.get(element)) {
        final String name = nameProvider.getNewName(element);
        rename(
            nameProvider.getNewElement(element),
            info,
            name == null ? newName : name,
            name != null,
            manager);
      }
    }
    for (PsiNamedElement element : propertyUsages.keySet()) {
      for (UsageInfo info : propertyUsages.get(element)) {
        rename(element, info, newName, true, manager);
      }
    }
    if (listener != null) {
      listener.elementRenamed(field);
    }
  }
  public void renameElement(
      final PsiElement psiElement,
      final String newName,
      final UsageInfo[] usages,
      @Nullable RefactoringElementListener listener)
      throws IncorrectOperationException {
    PsiVariable variable = (PsiVariable) psiElement;
    List<MemberHidesOuterMemberUsageInfo> outerHides = new ArrayList<>();
    List<MemberHidesStaticImportUsageInfo> staticImportHides = new ArrayList<>();

    List<PsiElement> occurrencesToCheckForConflict = new ArrayList<>();
    // rename all references
    for (UsageInfo usage : usages) {
      final PsiElement element = usage.getElement();
      if (element == null) continue;

      if (usage instanceof MemberHidesStaticImportUsageInfo) {
        staticImportHides.add((MemberHidesStaticImportUsageInfo) usage);
      } else if (usage instanceof LocalHidesFieldUsageInfo) {
        PsiJavaCodeReferenceElement collidingRef = (PsiJavaCodeReferenceElement) element;
        PsiElement resolved = collidingRef.resolve();

        if (resolved instanceof PsiField) {
          qualifyMember((PsiField) resolved, collidingRef, newName);
        } else {
          // do nothing
        }
      } else if (usage instanceof MemberHidesOuterMemberUsageInfo) {
        PsiJavaCodeReferenceElement collidingRef = (PsiJavaCodeReferenceElement) element;
        PsiField resolved = (PsiField) collidingRef.resolve();
        outerHides.add(new MemberHidesOuterMemberUsageInfo(element, resolved));
      } else {
        final PsiReference ref;
        if (usage instanceof MoveRenameUsageInfo) {
          ref = usage.getReference();
        } else {
          ref = element.getReference();
        }
        if (ref != null) {
          PsiElement newElem = ref.handleElementRename(newName);
          if (variable instanceof PsiField) {
            occurrencesToCheckForConflict.add(newElem);
          }
        }
      }
    }
    // do actual rename
    variable.setName(newName);
    if (listener != null) {
      listener.elementRenamed(variable);
    }

    if (variable instanceof PsiField) {
      for (PsiElement occurrence : occurrencesToCheckForConflict) {
        fixPossibleNameCollisionsForFieldRenaming((PsiField) variable, newName, occurrence);
      }
    }

    qualifyOuterMemberReferences(outerHides);
    qualifyStaticImportReferences(staticImportHides);
  }