/** Create ViewHolder for adapters with injections */
  protected void generateAdapter() {
    // view holder class
    String holderClassName = Utils.getViewHolderClassName();
    StringBuilder holderBuilder = new StringBuilder();

    // generator of view holder class
    StringBuilder generator = new StringBuilder();
    generator.append("public " + holderClassName + "(android.view.View rootView) {\n");

    // rootView
    String rootViewName = "rootView";
    holderBuilder.append("public " + "android.view.View " + rootViewName + ";\n");
    generator.append("this." + rootViewName + " = " + rootViewName + ";\n");

    for (Element element : mElements) {
      if (!element.used) {
        continue;
      }

      // field
      holderBuilder.append("public " + element.name + " " + element.getFieldName() + ";\n");

      // findViewById in generator
      generator.append(
          "this."
              + element.getFieldName()
              + " = ("
              + element.name
              + ") "
              + rootViewName
              + ".findViewById("
              + element.getFullID()
              + ");\n");
    }
    generator.append("}\n");

    holderBuilder.append(generator.toString());

    PsiClass viewHolder = mFactory.createClassFromText(holderBuilder.toString(), mClass);
    viewHolder.setName(holderClassName);
    mClass.add(viewHolder);
    mClass.addBefore(
        mFactory.createKeyword("public", mClass),
        mClass.findInnerClassByName(holderClassName, true));
    mClass.addBefore(
        mFactory.createKeyword("static", mClass),
        mClass.findInnerClassByName(holderClassName, true));
  }
  @Override
  protected PsiMethod findOrCreateSetUpMethod(PsiClass clazz) throws IncorrectOperationException {
    LOG.assertTrue(clazz.getLanguage() == GroovyFileType.GROOVY_LANGUAGE);
    final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(clazz.getProject());

    final PsiMethod patternMethod = createSetUpPatternMethod(factory);

    final PsiClass baseClass = clazz.getSuperClass();
    if (baseClass != null) {
      final PsiMethod baseMethod = baseClass.findMethodBySignature(patternMethod, false);
      if (baseMethod != null && baseMethod.hasModifierProperty(PsiModifier.PUBLIC)) {
        PsiUtil.setModifierProperty(patternMethod, PsiModifier.PROTECTED, false);
        PsiUtil.setModifierProperty(patternMethod, PsiModifier.PUBLIC, true);
      }
    }

    PsiMethod inClass = clazz.findMethodBySignature(patternMethod, false);
    if (inClass == null) {
      PsiMethod testMethod = JUnitUtil.findFirstTestMethod(clazz);
      if (testMethod != null) {
        return (PsiMethod) clazz.addBefore(patternMethod, testMethod);
      }
      return (PsiMethod) clazz.add(patternMethod);
    } else if (inClass.getBody() == null) {
      return (PsiMethod) inClass.replace(patternMethod);
    }
    return inClass;
  }
 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());
 }
  protected void doFix(Project project, ProblemDescriptor descriptor, boolean external)
      throws IncorrectOperationException {
    PsiElement element = myPointer.getElement();
    if (!(element instanceof PsiClass)) return;
    PsiClass clazz = (PsiClass) element;

    PsiMethod ctor =
        JavaPsiFacade.getInstance(clazz.getProject()).getElementFactory().createConstructor();
    PsiUtil.setModifierProperty(ctor, PsiModifier.PUBLIC, true);

    PsiMethod[] constructors = clazz.getConstructors();
    if (constructors.length > 0) {
      ctor = (PsiMethod) clazz.addBefore(ctor, constructors[0]);
    } else {
      // shouldn't get here - it's legal if there's no ctor present at all
      ctor = (PsiMethod) clazz.add(ctor);
    }

    if (myOnTheFly) ctor.navigate(true);
  }
  private void doMoveField(PsiSubstitutor substitutor, MemberInfo info) {
    PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject);
    PsiField field = (PsiField) info.getMember();

    if (field instanceof HaxeVarDeclarationPart) {
      field = (HaxeVarDeclaration) field.getParent();
    }

    field.normalizeDeclaration();
    RefactoringUtil.replaceMovedMemberTypeParameters(
        field, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
    fixReferencesToStatic(field);
    if (myIsTargetInterface) {
      PsiUtil.setModifierProperty(field, PsiModifier.PUBLIC, true);
    }
    final PsiMember movedElement =
        (PsiMember)
            myTargetSuperClass.addBefore(
                convertFieldToLanguage(field, myTargetSuperClass.getLanguage()),
                myTargetSuperClass.getRBrace());
    myMembersAfterMove.add(movedElement);
    field.delete();
  }
  private void doMoveMethod(PsiSubstitutor substitutor, MemberInfo info) {
    PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject);
    PsiMethod method = (PsiMethod) info.getMember();
    PsiMethod sibling = method;
    PsiMethod anchor = null;
    while (sibling != null) {
      sibling = PsiTreeUtil.getNextSiblingOfType(sibling, PsiMethod.class);
      if (sibling != null) {
        anchor =
            MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived(
                method.getContainingClass(),
                myTargetSuperClass,
                sibling.getSignature(PsiSubstitutor.EMPTY),
                false);
        if (anchor != null) {
          break;
        }
      }
    }
    PsiMethod methodCopy = (PsiMethod) method.copy();
    Language language = myTargetSuperClass.getLanguage();
    final PsiMethod superClassMethod = myTargetSuperClass.findMethodBySignature(methodCopy, false);
    if (superClassMethod != null && superClassMethod.findDeepestSuperMethods().length == 0
        || method.findSuperMethods(myTargetSuperClass).length == 0) {
      deleteOverrideAnnotationIfFound(methodCopy);
    }
    boolean isOriginalMethodAbstract =
        method.hasModifierProperty(PsiModifier.ABSTRACT)
            || method.hasModifierProperty(PsiModifier.DEFAULT);
    boolean isOriginalMethodPrototype =
        method instanceof HaxeFunctionPrototypeDeclarationWithAttributes;
    if (myIsTargetInterface || info.isToAbstract()) {
      ChangeContextUtil.clearContextInfo(method);

      if (!info.isToAbstract()
          && !method.hasModifierProperty(PsiModifier.ABSTRACT)
          && PsiUtil.isLanguageLevel8OrHigher(myTargetSuperClass)) {
        // pull as default
        RefactoringUtil.makeMethodDefault(methodCopy);
        isOriginalMethodAbstract = true;
      } else {
        RefactoringUtil.makeMethodAbstract(myTargetSuperClass, methodCopy);
      }

      RefactoringUtil.replaceMovedMemberTypeParameters(
          methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);

      myJavaDocPolicy.processCopiedJavaDoc(
          methodCopy.getDocComment(), method.getDocComment(), isOriginalMethodAbstract);

      final PsiMember movedElement;
      if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
        movedElement =
            (PsiMember) superClassMethod.replace(convertMethodToLanguage(methodCopy, language));
      } else {
        methodCopy =
            HaxeElementGenerator.createFunctionPrototypeDeclarationWithAttributes(
                myProject, methodCopy.getText().trim() + ";");

        movedElement =
            anchor != null
                ? (PsiMember) myTargetSuperClass.addBefore(methodCopy, anchor)
                : (PsiMember)
                    myTargetSuperClass.addBefore(methodCopy, myTargetSuperClass.getRBrace());

        reformat(movedElement);
      }
      CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(method.getProject());
      if (styleSettings.INSERT_OVERRIDE_ANNOTATION) {
        if (PsiUtil.isLanguageLevel5OrHigher(mySourceClass) && !myIsTargetInterface
            || PsiUtil.isLanguageLevel6OrHigher(mySourceClass)) {
          new AddAnnotationFix(Override.class.getName(), method)
              .invoke(method.getProject(), null, mySourceClass.getContainingFile());
        }
      }
      if (!PsiUtil.isLanguageLevel6OrHigher(mySourceClass) && myIsTargetInterface) {
        if (isOriginalMethodAbstract) {
          for (PsiMethod oMethod : OverridingMethodsSearch.search(method)) {
            deleteOverrideAnnotationIfFound(oMethod);
          }
        }
        deleteOverrideAnnotationIfFound(method);
      }
      myMembersAfterMove.add(movedElement);
      // if (isOriginalMethodAbstract) {
      method.delete();
      // }
    } else {
      if (isOriginalMethodAbstract) {
        PsiUtil.setModifierProperty(myTargetSuperClass, PsiModifier.ABSTRACT, true);
      }
      RefactoringUtil.replaceMovedMemberTypeParameters(
          methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
      fixReferencesToStatic(methodCopy);

      if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
        superClassMethod.replace(convertMethodToLanguage(methodCopy, language));
      } else {
        final PsiMember movedElement =
            anchor != null
                ? (PsiMember)
                    myTargetSuperClass.addBefore(
                        convertMethodToLanguage(methodCopy, language), anchor)
                : (PsiMember)
                    myTargetSuperClass.addBefore(
                        convertMethodToLanguage(methodCopy, language),
                        myTargetSuperClass.getRBrace());
        reformat(movedElement);
        myMembersAfterMove.add(movedElement);
      }
      method.delete();
    }
  }
  public void replace(final ReplacementInfo info, ReplaceOptions options) {
    PsiElement elementToReplace = info.getMatch(0);
    PsiElement elementParent = elementToReplace.getParent();
    String replacementToMake = info.getReplacement();
    Project project = myContext.getProject();
    PsiElement el = findRealSubstitutionElement(elementToReplace);
    boolean listContext = isListContext(el);

    if (el instanceof PsiAnnotation && !StringUtil.startsWithChar(replacementToMake, '@')) {
      replacementToMake = "@" + replacementToMake;
    }

    PsiElement[] statements =
        ReplacerUtil.createTreeForReplacement(
            replacementToMake,
            el instanceof PsiMember && !isSymbolReplacement(el)
                ? PatternTreeContext.Class
                : PatternTreeContext.Block,
            myContext);

    if (listContext) {
      if (statements.length > 1) {
        elementParent.addRangeBefore(
            statements[0], statements[statements.length - 1], elementToReplace);
      } else if (statements.length == 1) {
        PsiElement replacement = getMatchExpr(statements[0], elementToReplace);

        handleModifierList(el, replacement);
        replacement = handleSymbolReplacement(replacement, el);

        if (replacement instanceof PsiTryStatement) {
          final List<PsiCatchSection> unmatchedCatchSections =
              el.getUserData(JavaMatchingVisitor.UNMATCHED_CATCH_SECTION_CONTENT_VAR_KEY);
          final PsiCatchSection[] catches = ((PsiTryStatement) replacement).getCatchSections();

          if (unmatchedCatchSections != null) {
            for (int i = unmatchedCatchSections.size() - 1; i >= 0; --i) {
              final PsiParameter parameter = unmatchedCatchSections.get(i).getParameter();
              final PsiElementFactory elementFactory =
                  JavaPsiFacade.getInstance(project).getElementFactory();
              final PsiCatchSection catchSection =
                  elementFactory.createCatchSection(parameter.getType(), parameter.getName(), null);

              catchSection.getCatchBlock().replace(unmatchedCatchSections.get(i).getCatchBlock());
              replacement.addAfter(catchSection, catches[catches.length - 1]);
              replacement.addBefore(createWhiteSpace(replacement), replacement.getLastChild());
            }
          }
        }

        try {
          final PsiElement inserted = elementParent.addBefore(replacement, elementToReplace);

          if (replacement instanceof PsiComment
              && (elementParent instanceof PsiIfStatement
                  || elementParent instanceof PsiLoopStatement)) {
            elementParent.addAfter(createSemicolon(replacement), inserted);
          }
        } catch (IncorrectOperationException e) {
          elementToReplace.replace(replacement);
        }
      }
    } else if (statements.length > 0) {
      PsiElement replacement =
          ReplacerUtil.copySpacesAndCommentsBefore(
              elementToReplace, statements, replacementToMake, elementParent);

      replacement = getMatchExpr(replacement, elementToReplace);

      if (replacement instanceof PsiStatement
          && !(replacement.getLastChild() instanceof PsiJavaToken)
          && !(replacement.getLastChild() instanceof PsiComment)) {
        // assert w/o ;
        final PsiElement prevLastChildInParent = replacement.getLastChild().getPrevSibling();

        if (prevLastChildInParent != null) {
          elementParent.addRangeBefore(replacement.getFirstChild(), prevLastChildInParent, el);
        } else {
          elementParent.addBefore(replacement.getFirstChild(), el);
        }

        el.getNode().getTreeParent().removeChild(el.getNode());
      } else {
        // preserve comments
        handleModifierList(el, replacement);

        if (replacement instanceof PsiClass) {
          // modifier list
          final PsiStatement[] searchStatements = getCodeBlock().getStatements();
          if (searchStatements.length > 0
              && searchStatements[0] instanceof PsiDeclarationStatement
              && ((PsiDeclarationStatement) searchStatements[0]).getDeclaredElements()[0]
                  instanceof PsiClass) {
            final PsiClass replaceClazz = (PsiClass) replacement;
            final PsiClass queryClazz =
                (PsiClass) ((PsiDeclarationStatement) searchStatements[0]).getDeclaredElements()[0];
            final PsiClass clazz = (PsiClass) el;

            if (replaceClazz.getExtendsList().getTextLength() == 0
                && queryClazz.getExtendsList().getTextLength() == 0
                && clazz.getExtendsList().getTextLength() != 0) {
              replaceClazz.addBefore(
                  clazz.getExtendsList().getPrevSibling(),
                  replaceClazz.getExtendsList()); // whitespace
              replaceClazz
                  .getExtendsList()
                  .addRange(
                      clazz.getExtendsList().getFirstChild(),
                      clazz.getExtendsList().getLastChild());
            }

            if (replaceClazz.getImplementsList().getTextLength() == 0
                && queryClazz.getImplementsList().getTextLength() == 0
                && clazz.getImplementsList().getTextLength() != 0) {
              replaceClazz.addBefore(
                  clazz.getImplementsList().getPrevSibling(),
                  replaceClazz.getImplementsList()); // whitespace
              replaceClazz
                  .getImplementsList()
                  .addRange(
                      clazz.getImplementsList().getFirstChild(),
                      clazz.getImplementsList().getLastChild());
            }

            if (replaceClazz.getTypeParameterList().getTextLength() == 0
                && queryClazz.getTypeParameterList().getTextLength() == 0
                && clazz.getTypeParameterList().getTextLength() != 0) {
              // skip < and >
              replaceClazz.getTypeParameterList().replace(clazz.getTypeParameterList());
            }
          }
        }

        replacement = handleSymbolReplacement(replacement, el);

        el.replace(replacement);
      }
    } else {
      final PsiElement nextSibling = el.getNextSibling();
      el.delete();
      if (nextSibling instanceof PsiWhiteSpace && nextSibling.isValid()) {
        nextSibling.delete();
      }
    }

    if (listContext) {
      final int matchSize = info.getMatchesCount();

      for (int i = 0; i < matchSize; ++i) {
        PsiElement matchElement = info.getMatch(i);
        PsiElement element = findRealSubstitutionElement(matchElement);

        if (element == null) continue;
        PsiElement firstToDelete = element;
        PsiElement lastToDelete = element;
        PsiElement prevSibling = element.getPrevSibling();
        PsiElement nextSibling = element.getNextSibling();

        if (prevSibling instanceof PsiWhiteSpace) {
          firstToDelete = prevSibling;
          prevSibling = prevSibling != null ? prevSibling.getPrevSibling() : null;
        } else if (prevSibling == null && nextSibling instanceof PsiWhiteSpace) {
          lastToDelete = nextSibling;
        }

        if (nextSibling instanceof XmlText && i + 1 < matchSize) {
          final PsiElement next = info.getMatch(i + 1);
          if (next != null && next == nextSibling.getNextSibling()) {
            lastToDelete = nextSibling;
          }
        }

        if (element instanceof PsiExpression) {
          final PsiElement parent = element.getParent().getParent();
          if ((parent instanceof PsiCall || parent instanceof PsiAnonymousClass)
              && prevSibling instanceof PsiJavaToken
              && ((PsiJavaToken) prevSibling).getTokenType() == JavaTokenType.COMMA) {
            firstToDelete = prevSibling;
          }
        } else if (element instanceof PsiParameter
            && prevSibling instanceof PsiJavaToken
            && ((PsiJavaToken) prevSibling).getTokenType() == JavaTokenType.COMMA) {
          firstToDelete = prevSibling;
        }

        element.getParent().deleteChildRange(firstToDelete, lastToDelete);
      }
    }
  }
  public static void createFieldAndAddAssignment(
      final @NotNull Project project,
      final @NotNull PsiClass targetClass,
      final @NotNull PsiMethod method,
      final @NotNull PsiParameter parameter,
      final @NotNull PsiType fieldType,
      final @NotNull String fieldName,
      final boolean isStatic,
      final boolean isFinal)
      throws IncorrectOperationException {
    PsiManager psiManager = PsiManager.getInstance(project);
    PsiElementFactory factory =
        JavaPsiFacade.getInstance(psiManager.getProject()).getElementFactory();

    PsiField field = factory.createField(fieldName, fieldType);
    PsiModifierList modifierList = field.getModifierList();

    if (modifierList == null) return;
    modifierList.setModifierProperty(PsiModifier.STATIC, isStatic);
    modifierList.setModifierProperty(PsiModifier.FINAL, isFinal);

    NullableNotNullManager.getInstance(project).copyNullableOrNotNullAnnotation(parameter, field);

    PsiCodeBlock methodBody = method.getBody();
    if (methodBody == null) return;
    PsiStatement[] statements = methodBody.getStatements();

    Ref<Pair<PsiField, Boolean>> anchorRef = new Ref<Pair<PsiField, Boolean>>();
    int i = findFieldAssignmentAnchor(statements, anchorRef, targetClass, parameter);
    Pair<PsiField, Boolean> fieldAnchor = anchorRef.get();

    String stmtText = fieldName + " = " + parameter.getName() + ";";
    if (fieldName.equals(parameter.getName())) {
      @NonNls
      String prefix =
          isStatic ? targetClass.getName() == null ? "" : targetClass.getName() + "." : "this.";
      stmtText = prefix + stmtText;
    }

    PsiStatement assignmentStmt = factory.createStatementFromText(stmtText, methodBody);
    assignmentStmt = (PsiStatement) CodeStyleManager.getInstance(project).reformat(assignmentStmt);

    if (i == statements.length) {
      methodBody.add(assignmentStmt);
    } else {
      methodBody.addAfter(assignmentStmt, i > 0 ? statements[i - 1] : null);
    }

    if (fieldAnchor != null) {
      PsiVariable psiVariable = fieldAnchor.getFirst();
      psiVariable.normalizeDeclaration();
    }

    if (targetClass.findFieldByName(fieldName, false) == null) {
      if (fieldAnchor != null) {
        Boolean insertBefore = fieldAnchor.getSecond();
        PsiField inField = fieldAnchor.getFirst();
        if (insertBefore.booleanValue()) {
          targetClass.addBefore(field, inField);
        } else {
          targetClass.addAfter(field, inField);
        }
      } else {
        targetClass.add(field);
      }
    }
  }