@Nullable
  private static PsiMethod existingClassIsCompatible(PsiClass aClass, List<ParameterChunk> params) {
    if (params.size() == 1) {
      final ParameterChunk parameterChunk = params.get(0);
      final PsiType paramType = parameterChunk.parameter.type;
      if (TypeConversionUtil.isPrimitiveWrapper(aClass.getQualifiedName())) {
        parameterChunk.setField(aClass.findFieldByName("value", false));
        parameterChunk.setGetter(paramType.getCanonicalText() + "Value");
        for (PsiMethod constructor : aClass.getConstructors()) {
          if (constructorIsCompatible(constructor, params)) return constructor;
        }
      }
    }
    final PsiMethod[] constructors = aClass.getConstructors();
    PsiMethod compatibleConstructor = null;
    for (PsiMethod constructor : constructors) {
      if (constructorIsCompatible(constructor, params)) {
        compatibleConstructor = constructor;
        break;
      }
    }
    if (compatibleConstructor == null) {
      return null;
    }
    final PsiParameterList parameterList = compatibleConstructor.getParameterList();
    final PsiParameter[] constructorParams = parameterList.getParameters();
    for (int i = 0; i < constructorParams.length; i++) {
      final PsiParameter param = constructorParams[i];
      final ParameterChunk parameterChunk = params.get(i);

      final PsiField field = findFieldAssigned(param, compatibleConstructor);
      if (field == null) {
        return null;
      }

      parameterChunk.setField(field);

      final PsiMethod getterForField = PropertyUtil.findGetterForField(field);
      if (getterForField != null) {
        parameterChunk.setGetter(getterForField.getName());
      }

      final PsiMethod setterForField = PropertyUtil.findSetterForField(field);
      if (setterForField != null) {
        parameterChunk.setSetter(setterForField.getName());
      }
    }
    return compatibleConstructor;
  }
 @Override
 @NotNull
 public String getText() {
   if (getFieldsToFix().size() > 1 && myClass.getConstructors().length <= 1)
     return "Add constructor parameters";
   return QuickFixBundle.message("add.constructor.parameter.name");
 }
 private static HashSet<PsiMethod> collectDefaultConstructorsToPropagate(PsiMethod method) {
   final HashSet<PsiMethod> methodsToPropagate = new HashSet<PsiMethod>();
   for (PsiClass inheritor : ClassInheritorsSearch.search(method.getContainingClass())) {
     methodsToPropagate.add(inheritor.getConstructors()[0]);
   }
   return methodsToPropagate;
 }
Exemple #4
0
  private void checkCompoundIds(Class<?> javaClass) throws IOException {
    String javaClassName = javaClass.getCanonicalName();
    PsiClass psiClass =
        myJavaPsiFacade.findClass(
            javaClassName, GlobalSearchScope.moduleWithLibrariesScope(myModule));
    assertNotNull(psiClass);

    for (java.lang.reflect.Method javaMethod : javaClass.getDeclaredMethods()) {
      Method method =
          new Method(
              Type.getType(javaClass).getInternalName(),
              javaMethod.getName(),
              Type.getMethodDescriptor(javaMethod));
      boolean noKey = javaMethod.getAnnotation(ExpectNoPsiKey.class) != null;
      PsiMethod psiMethod = psiClass.findMethodsByName(javaMethod.getName(), false)[0];
      checkCompoundId(method, psiMethod, noKey);
    }

    for (Constructor<?> constructor : javaClass.getDeclaredConstructors()) {
      Method method =
          new Method(
              Type.getType(javaClass).getInternalName(),
              "<init>",
              Type.getConstructorDescriptor(constructor));
      boolean noKey = constructor.getAnnotation(ExpectNoPsiKey.class) != null;
      PsiMethod[] constructors = psiClass.getConstructors();
      PsiMethod psiMethod = constructors[0];
      checkCompoundId(method, psiMethod, noKey);
    }
  }
 boolean hasPrivateConstructor(PsiClass aClass) {
   final PsiMethod[] constructors = aClass.getConstructors();
   for (final PsiMethod constructor : constructors) {
     if (constructor.hasModifierProperty(PsiModifier.PRIVATE)) {
       return true;
     }
   }
   return false;
 }
  private static PsiStatement addInitializationToConstructors(
      PsiLocalVariable local,
      PsiField field,
      PsiMethod enclosingConstructor,
      PsiElementFactory factory)
      throws IncorrectOperationException {
    PsiClass aClass = field.getContainingClass();
    PsiMethod[] constructors = aClass.getConstructors();
    PsiStatement assignment = createAssignment(local, field.getName(), factory);
    boolean added = false;
    for (PsiMethod constructor : constructors) {
      if (constructor == enclosingConstructor) continue;
      PsiCodeBlock body = constructor.getBody();
      if (body == null) continue;
      PsiStatement[] statements = body.getStatements();
      if (statements.length > 0) {
        PsiStatement first = statements[0];
        if (first instanceof PsiExpressionStatement) {
          PsiExpression expression = ((PsiExpressionStatement) first).getExpression();
          if (expression instanceof PsiMethodCallExpression) {
            @NonNls
            String text = ((PsiMethodCallExpression) expression).getMethodExpression().getText();
            if ("this".equals(text)) {
              continue;
            }
            if ("super".equals(text)
                && enclosingConstructor == null
                && PsiTreeUtil.isAncestor(constructor, local, false)) {
              local.delete();
              return (PsiStatement) body.addAfter(assignment, first);
            }
          }
        }
        if (enclosingConstructor == null && PsiTreeUtil.isAncestor(constructor, local, false)) {
          local.delete();
          return (PsiStatement) body.addBefore(assignment, first);
        }
      }

      assignment = (PsiStatement) body.add(assignment);
      added = true;
    }
    if (!added && enclosingConstructor == null) {
      if (aClass instanceof PsiAnonymousClass) {
        final PsiClassInitializer classInitializer =
            (PsiClassInitializer) aClass.addAfter(factory.createClassInitializer(), field);
        assignment = (PsiStatement) classInitializer.getBody().add(assignment);
      } else {
        PsiMethod constructor = (PsiMethod) aClass.add(factory.createConstructor());
        assignment = (PsiStatement) constructor.getBody().add(assignment);
      }
    }

    if (enclosingConstructor == null) local.delete();
    return assignment;
  }
 static boolean hasNullArgConstructor(PsiClass aClass) {
   final PsiMethod[] constructors = aClass.getConstructors();
   for (final PsiMethod constructor : constructors) {
     final PsiParameterList params = constructor.getParameterList();
     if (params.getParametersCount() == 0) {
       return true;
     }
   }
   return false;
 }
 @Override
 public void visitThrowStatement(PsiThrowStatement statement) {
   super.visitThrowStatement(statement);
   final PsiCatchSection catchSection =
       PsiTreeUtil.getParentOfType(statement, PsiCatchSection.class, true, PsiClass.class);
   if (catchSection == null) {
     return;
   }
   final PsiParameter parameter = catchSection.getParameter();
   if (parameter == null) {
     return;
   }
   @NonNls final String parameterName = parameter.getName();
   if (PsiUtil.isIgnoredName(parameterName)) {
     return;
   }
   final PsiExpression exception = statement.getException();
   if (exception == null) {
     return;
   }
   if (ignoreCantWrap) {
     final PsiType thrownType = exception.getType();
     if (thrownType instanceof PsiClassType) {
       final PsiClassType classType = (PsiClassType) thrownType;
       final PsiClass exceptionClass = classType.resolve();
       if (exceptionClass != null) {
         final PsiMethod[] constructors = exceptionClass.getConstructors();
         final PsiClassType throwableType =
             TypeUtils.getType(CommonClassNames.JAVA_LANG_THROWABLE, statement);
         boolean canWrap = false;
         outer:
         for (PsiMethod constructor : constructors) {
           final PsiParameterList parameterList = constructor.getParameterList();
           final PsiParameter[] parameters = parameterList.getParameters();
           for (PsiParameter constructorParameter : parameters) {
             final PsiType type = constructorParameter.getType();
             if (throwableType.equals(type)) {
               canWrap = true;
               break outer;
             }
           }
         }
         if (!canWrap) {
           return;
         }
       }
     }
   }
   final ReferenceFinder visitor = new ReferenceFinder(parameter);
   exception.accept(visitor);
   if (visitor.usesParameter()) {
     return;
   }
   registerStatementError(statement);
 }
  @Test
  public void shouldNotVerifyThatFieldIsSetInConstructorIfConstructorHasNoParameters() {
    // given
    given(psiClass.getConstructors()).willReturn(constructors);

    // when
    boolean result = psiFieldVerifier.isSetInConstructor(psiField, psiClass);

    // then
    assertThat(result, is(false));
  }
  @Test
  public void shouldNotVerifyThatFieldIsSetInConstructorIfConstructorDoesNotExist() {
    // given
    given(psiClass.getConstructors()).willReturn(new PsiMethod[0]);

    // when
    boolean result = psiFieldVerifier.isSetInConstructor(psiField, psiClass);

    // then
    assertThat(result, is(false));
  }
 private void calculateInitializersConflicts(MultiMap<PsiElement, String> conflicts) {
   final PsiClassInitializer[] initializers = sourceClass.getInitializers();
   for (PsiClassInitializer initializer : initializers) {
     if (initializerDependsOnMoved(initializer)) {
       conflicts.putValue(initializer, "Class initializer requires moved members");
     }
   }
   for (PsiMethod constructor : sourceClass.getConstructors()) {
     if (initializerDependsOnMoved(constructor.getBody())) {
       conflicts.putValue(constructor, "Constructor requires moved members");
     }
   }
 }
Exemple #12
0
 public static boolean isConstructorPrimary(@NotNull PsiMethod constructor) {
   if (constructor.getParent() instanceof PsiClass) {
     PsiClass parent = (PsiClass) constructor.getParent();
     if (parent.getConstructors().length == 1) {
       return true;
     } else {
       PsiMethod c =
           getPrimaryConstructorForThisCase(parent); // TODO: move up to classToClass() method
       if (c != null && c.hashCode() == constructor.hashCode()) {
         return true;
       }
     }
   }
   return false;
 }
  @Override
  public void moveFieldInitializations(LinkedHashSet<PsiField> movedFields) {
    PsiMethod[] constructors = myTargetSuperClass.getConstructors();

    if (constructors.length == 0) {
      constructors = new PsiMethod[] {null};
    }

    HashMap<PsiMethod, HashSet<PsiMethod>> constructorsToSubConstructors =
        buildConstructorsToSubConstructorsMap(constructors);
    for (PsiMethod constructor : constructors) {
      HashSet<PsiMethod> subConstructors = constructorsToSubConstructors.get(constructor);
      tryToMoveInitializers(constructor, subConstructors, movedFields);
    }
  }
 static List<? extends LookupElement> wrap(
     @NotNull LookupElement classItem,
     @NotNull PsiClass psiClass,
     @NotNull PsiElement position,
     @NotNull Supplier<PsiClassType> type) {
   if (Registry.is("java.completion.show.constructors") && isConstructorCallPlace(position)) {
     List<PsiMethod> constructors =
         ContainerUtil.filter(
             psiClass.getConstructors(), c -> shouldSuggestConstructor(psiClass, position, c));
     if (!constructors.isEmpty()) {
       return ContainerUtil.map(
           constructors, c -> new JavaConstructorCallElement(classItem, c, type));
     }
   }
   return Collections.singletonList(classItem);
 }
  public static boolean hasAccessibleConstructor(PsiType type) {
    if (type instanceof PsiArrayType) return true;

    final PsiClass psiClass = PsiUtil.resolveClassInType(type);
    if (psiClass == null || psiClass.isEnum() || psiClass.isAnnotationType()) return false;

    if (!(psiClass instanceof PsiCompiledElement)) return true;

    final PsiMethod[] methods = psiClass.getConstructors();
    if (methods.length == 0) return true;

    for (final PsiMethod method : methods) {
      if (!method.hasModifierProperty(PsiModifier.PRIVATE)) return true;
    }
    return false;
  }
 protected void performRefactoring(@NotNull UsageInfo[] usageInfos) {
   final PsiClass psiClass = buildClass();
   if (psiClass != null) {
     fixJavadocForConstructor(psiClass);
     super.performRefactoring(usageInfos);
     if (!myUseExistingClass) {
       for (PsiReference reference : ReferencesSearch.search(method)) {
         final PsiElement place = reference.getElement();
         VisibilityUtil.escalateVisibility(psiClass, place);
         for (PsiMethod constructor : psiClass.getConstructors()) {
           VisibilityUtil.escalateVisibility(constructor, place);
         }
       }
     }
   }
 }
  public static boolean isFieldInitializedAfterObjectConstruction(@NotNull PsiField field) {
    if (field.hasInitializer()) return true;
    final boolean isFieldStatic = field.hasModifierProperty(PsiModifier.STATIC);
    final PsiClass aClass = field.getContainingClass();
    if (aClass != null) {
      // field might be assigned in the other field initializers
      if (isFieldInitializedInOtherFieldInitializer(aClass, field, isFieldStatic)) return true;
    }
    final PsiClassInitializer[] initializers;
    if (aClass != null) {
      initializers = aClass.getInitializers();
    } else {
      return false;
    }
    for (PsiClassInitializer initializer : initializers) {
      if (initializer.hasModifierProperty(PsiModifier.STATIC) == isFieldStatic
          && variableDefinitelyAssignedIn(field, initializer.getBody())) {
        return true;
      }
    }
    if (isFieldStatic) {
      return false;
    } else {
      // instance field should be initialized at the end of the each constructor
      final PsiMethod[] constructors = aClass.getConstructors();

      if (constructors.length == 0) return false;
      nextConstructor:
      for (PsiMethod constructor : constructors) {
        PsiCodeBlock ctrBody = constructor.getBody();
        if (ctrBody == null) return false;
        final List<PsiMethod> redirectedConstructors =
            JavaHighlightUtil.getChainedConstructors(constructor);
        for (int j = 0; redirectedConstructors != null && j < redirectedConstructors.size(); j++) {
          PsiMethod redirectedConstructor = redirectedConstructors.get(j);
          final PsiCodeBlock body = redirectedConstructor.getBody();
          if (body != null && variableDefinitelyAssignedIn(field, body)) continue nextConstructor;
        }
        if (!ctrBody.isValid() || variableDefinitelyAssignedIn(field, ctrBody)) {
          continue;
        }
        return false;
      }
      return true;
    }
  }
  public static boolean isDefaultInstantiable(PsiClass psiClass) {
    final PsiMethod[] constructors = psiClass.getConstructors();

    if (constructors.length == 0) {
      return true;
    }

    for (PsiMethod psiMethod : constructors) {
      final PsiParameterList parameterList = psiMethod.getParameterList();
      if (psiMethod.getModifierList().hasModifierProperty("public")
          && parameterList.getParameters().length == 0) {
        return true;
      }
    }

    return false;
  }
  private void fixJavadocForConstructor(PsiClass psiClass) {
    final PsiDocComment docComment = method.getDocComment();
    if (docComment != null) {
      final List<PsiDocTag> mergedTags = new ArrayList<PsiDocTag>();
      final PsiDocTag[] paramTags = docComment.findTagsByName("param");
      for (PsiDocTag paramTag : paramTags) {
        final PsiElement[] dataElements = paramTag.getDataElements();
        if (dataElements.length > 0) {
          if (dataElements[0] instanceof PsiDocParamRef) {
            final PsiReference reference = dataElements[0].getReference();
            if (reference != null) {
              final PsiElement resolve = reference.resolve();
              if (resolve instanceof PsiParameter) {
                final int parameterIndex =
                    method.getParameterList().getParameterIndex((PsiParameter) resolve);
                if (ArrayUtil.find(paramsToMerge, parameterIndex) < 0) continue;
              }
            }
          }
          mergedTags.add((PsiDocTag) paramTag.copy());
        }
      }

      PsiMethod compatibleParamObjectConstructor = null;
      if (myExistingClassCompatibleConstructor != null
          && myExistingClassCompatibleConstructor.getDocComment() == null) {
        compatibleParamObjectConstructor = myExistingClassCompatibleConstructor;
      } else if (!myUseExistingClass) {
        compatibleParamObjectConstructor = psiClass.getConstructors()[0];
      }

      if (compatibleParamObjectConstructor != null) {
        PsiDocComment psiDocComment =
            JavaPsiFacade.getElementFactory(myProject).createDocCommentFromText("/**\n*/");
        psiDocComment =
            (PsiDocComment)
                compatibleParamObjectConstructor.addBefore(
                    psiDocComment, compatibleParamObjectConstructor.getFirstChild());

        for (PsiDocTag tag : mergedTags) {
          psiDocComment.add(tag);
        }
      }
    }
  }
 @Override
 public void doFix(Project project, ProblemDescriptor descriptor)
     throws IncorrectOperationException {
   final PsiElement classNameIdentifier = descriptor.getPsiElement();
   final PsiClass aClass = (PsiClass) classNameIdentifier.getParent();
   if (aClass == null) {
     return;
   }
   final PsiMethod[] constructurs = aClass.getConstructors();
   for (final PsiMethod constructor : constructurs) {
     final PsiParameterList parameterList = constructor.getParameterList();
     if (parameterList.getParametersCount() == 0) {
       final PsiModifierList modifiers = constructor.getModifierList();
       modifiers.setModifierProperty(PsiModifier.PUBLIC, false);
       modifiers.setModifierProperty(PsiModifier.PROTECTED, false);
       modifiers.setModifierProperty(PsiModifier.PRIVATE, true);
     }
   }
 }
  private static boolean superConstructorHasParameters(PsiMethod method) {
    final PsiClass psiClass = method.getContainingClass();
    if (psiClass == null) {
      return false;
    }

    final PsiClass superClass = psiClass.getSuperClass();
    if (superClass != null) {
      for (final PsiMethod psiMethod : superClass.getConstructors()) {
        final PsiResolveHelper resolveHelper =
            JavaPsiFacade.getInstance(method.getProject()).getResolveHelper();
        if (resolveHelper.isAccessible(psiMethod, method, null)
            && psiMethod.getParameterList().getParameters().length > 0) {
          return true;
        }
      }
    }
    return false;
  }
 @Override
 public void visitField(@NotNull PsiField field) {
   if (field.hasModifierProperty(PsiModifier.STATIC)) {
     return;
   }
   if (field.getInitializer() != null) {
     return;
   }
   final PsiAnnotation annotation = AnnotationUtil.findAnnotation(field, annotationNames);
   if (annotation != null) {
     return;
   }
   if (m_ignorePrimitives) {
     final PsiType fieldType = field.getType();
     if (ClassUtils.isPrimitive(fieldType)) {
       return;
     }
   }
   final PsiClass aClass = field.getContainingClass();
   if (aClass == null) {
     return;
   }
   for (ImplicitUsageProvider provider :
       Extensions.getExtensions(ImplicitUsageProvider.EP_NAME)) {
     if (provider.isImplicitWrite(field)) {
       return;
     }
   }
   final UninitializedReadCollector uninitializedReadsCollector =
       new UninitializedReadCollector();
   if (!isInitializedInInitializer(field, uninitializedReadsCollector)) {
     final PsiMethod[] constructors = aClass.getConstructors();
     for (final PsiMethod constructor : constructors) {
       final PsiCodeBlock body = constructor.getBody();
       uninitializedReadsCollector.blockAssignsVariable(body, field);
     }
   }
   final PsiExpression[] badReads = uninitializedReadsCollector.getUninitializedReads();
   for (PsiExpression expression : badReads) {
     registerError(expression);
   }
 }
  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 static boolean canCallMethodsInConstructors(PsiClass aClass, boolean virtual) {
    for (PsiMethod constructor : aClass.getConstructors()) {
      if (!constructor.getLanguage().isKindOf(JavaLanguage.INSTANCE)) return true;

      PsiCodeBlock body = constructor.getBody();
      if (body == null) continue;

      for (PsiMethodCallExpression call :
          SyntaxTraverser.psiTraverser().withRoot(body).filter(PsiMethodCallExpression.class)) {
        PsiReferenceExpression methodExpression = call.getMethodExpression();
        if (methodExpression instanceof PsiThisExpression
            || methodExpression instanceof PsiSuperExpression) continue;
        if (!virtual) return true;

        PsiMethod target = call.resolveMethod();
        if (target != null && PsiUtil.canBeOverriden(target)) return true;
      }
    }

    return false;
  }
  private static String computeConstantSuperCtorCallParameter(
      PsiClass languagePsiClass, int index) {
    if (languagePsiClass instanceof PsiAnonymousClass) {
      return getStringConstantExpression(
          ((PsiAnonymousClass) languagePsiClass).getArgumentList(), index);
    }

    PsiMethod defaultConstructor = null;
    for (PsiMethod constructor : languagePsiClass.getConstructors()) {
      if (constructor.getParameterList().getParametersCount() == 0) {
        defaultConstructor = constructor;
        break;
      }
    }
    if (defaultConstructor == null) {
      return null;
    }

    final PsiCodeBlock body = defaultConstructor.getBody();
    if (body == null) {
      return null;
    }
    final PsiStatement[] statements = body.getStatements();
    if (statements.length < 1) {
      return null;
    }

    // super() must be first
    PsiStatement statement = statements[0];
    if (!(statement instanceof PsiExpressionStatement)) {
      return null;
    }
    PsiExpression expression = ((PsiExpressionStatement) statement).getExpression();
    if (!(expression instanceof PsiMethodCallExpression)) {
      return null;
    }
    PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) expression;
    PsiExpressionList expressionList = methodCallExpression.getArgumentList();
    return getStringConstantExpression(expressionList, index);
  }
  private static boolean isClassHasConstructorWithMap(PsiClass aClass) {
    PsiMethod[] constructors = aClass.getConstructors();

    if (constructors.length == 0) return true;

    for (PsiMethod constructor : constructors) {
      PsiParameterList parameterList = constructor.getParameterList();

      PsiParameter[] parameters = parameterList.getParameters();

      if (parameters.length == 0) return true;

      final PsiParameter first = parameters[0];
      if (InheritanceUtil.isInheritor(first.getType(), CommonClassNames.JAVA_UTIL_MAP)) return true;
      if (first instanceof GrParameter && ((GrParameter) first).getTypeGroovy() == null)
        return true;

      // if constructor has only optional parameters it can be used as default constructor with map
      // args
      if (!PsiUtil.isConstructorHasRequiredParameters(constructor)) return true;
    }
    return false;
  }
  @Override
  @Nullable
  protected ClassMember[] chooseOriginalMembers(PsiClass aClass, Project project) {
    if (aClass instanceof PsiAnonymousClass) {
      Messages.showMessageDialog(
          project,
          CodeInsightBundle.message("error.attempt.to.generate.constructor.for.anonymous.class"),
          CommonBundle.getErrorTitle(),
          Messages.getErrorIcon());
      return null;
    }

    myCopyJavadoc = false;
    PsiMethod[] baseConstructors = null;
    PsiClass baseClass = aClass.getSuperClass();
    if (baseClass != null) {
      ArrayList<PsiMethod> array = new ArrayList<PsiMethod>();
      for (PsiMethod method : baseClass.getConstructors()) {
        if (JavaPsiFacade.getInstance(method.getProject())
            .getResolveHelper()
            .isAccessible(method, aClass, null)) {
          array.add(method);
        }
      }
      if (!array.isEmpty()) {
        if (array.size() == 1) {
          baseConstructors = new PsiMethod[] {array.get(0)};
        } else {
          final PsiSubstitutor substitutor =
              TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY);
          PsiMethodMember[] constructors =
              ContainerUtil.map2Array(
                  array,
                  PsiMethodMember.class,
                  new Function<PsiMethod, PsiMethodMember>() {
                    @Override
                    public PsiMethodMember fun(final PsiMethod s) {
                      return new PsiMethodMember(s, substitutor);
                    }
                  });
          MemberChooser<PsiMethodMember> chooser =
              new MemberChooser<PsiMethodMember>(constructors, false, true, project);
          chooser.setTitle(
              CodeInsightBundle.message("generate.constructor.super.constructor.chooser.title"));
          chooser.show();
          List<PsiMethodMember> elements = chooser.getSelectedElements();
          if (elements == null || elements.isEmpty()) return null;
          baseConstructors = new PsiMethod[elements.size()];
          for (int i = 0; i < elements.size(); i++) {
            final ClassMember member = elements.get(i);
            baseConstructors[i] = ((PsiMethodMember) member).getElement();
          }
          myCopyJavadoc = chooser.isCopyJavadoc();
        }
      }
    }

    ClassMember[] allMembers = getAllOriginalMembers(aClass);
    ClassMember[] members;
    if (allMembers.length == 0) {
      members = ClassMember.EMPTY_ARRAY;
    } else {
      members = chooseMembers(allMembers, true, false, project, null);
      if (members == null) return null;
    }
    if (baseConstructors != null) {
      ArrayList<ClassMember> array = new ArrayList<ClassMember>();
      for (PsiMethod baseConstructor : baseConstructors) {
        array.add(new PsiMethodMember(baseConstructor));
      }
      ContainerUtil.addAll(array, members);
      members = array.toArray(new ClassMember[array.size()]);
    }

    return members;
  }
  protected void findUsages(@NotNull final List<FixableUsageInfo> usages) {
    final JavaPsiFacade facade = JavaPsiFacade.getInstance(myProject);
    final PsiElementFactory elementFactory = facade.getElementFactory();
    final PsiResolveHelper resolveHelper = facade.getResolveHelper();

    ReferencesSearch.search(mySuperClass)
        .forEach(
            new Processor<PsiReference>() {
              public boolean process(final PsiReference reference) {
                final PsiElement element = reference.getElement();
                if (element instanceof PsiJavaCodeReferenceElement) {
                  final PsiImportStaticStatement staticImportStatement =
                      PsiTreeUtil.getParentOfType(element, PsiImportStaticStatement.class);
                  if (staticImportStatement != null) {
                    usages.add(
                        new ReplaceStaticImportUsageInfo(staticImportStatement, myTargetClasses));
                  } else {
                    final PsiImportStatement importStatement =
                        PsiTreeUtil.getParentOfType(element, PsiImportStatement.class);
                    if (importStatement != null) {
                      usages.add(new RemoveImportUsageInfo(importStatement));
                    } else {
                      final PsiElement parent = element.getParent();
                      if (parent instanceof PsiReferenceList) {
                        final PsiElement pparent = parent.getParent();
                        if (pparent instanceof PsiClass) {
                          final PsiClass inheritor = (PsiClass) pparent;
                          if (parent.equals(inheritor.getExtendsList())
                              || parent.equals(inheritor.getImplementsList())) {
                            usages.add(
                                new ReplaceExtendsListUsageInfo(
                                    (PsiJavaCodeReferenceElement) element,
                                    mySuperClass,
                                    inheritor));
                          }
                        }
                      } else {
                        final PsiClass targetClass = myTargetClasses[0];
                        final PsiClassType targetClassType =
                            elementFactory.createType(
                                targetClass,
                                TypeConversionUtil.getSuperClassSubstitutor(
                                    mySuperClass, targetClass, PsiSubstitutor.EMPTY));

                        if (parent instanceof PsiTypeElement) {
                          final PsiType superClassType = ((PsiTypeElement) parent).getType();
                          PsiSubstitutor subst =
                              getSuperClassSubstitutor(
                                  superClassType, targetClassType, resolveHelper, targetClass);
                          usages.add(
                              new ReplaceWithSubtypeUsageInfo(
                                  ((PsiTypeElement) parent),
                                  elementFactory.createType(targetClass, subst),
                                  myTargetClasses));
                        } else if (parent instanceof PsiNewExpression) {
                          final PsiClassType newType =
                              elementFactory.createType(
                                  targetClass,
                                  getSuperClassSubstitutor(
                                      ((PsiNewExpression) parent).getType(),
                                      targetClassType,
                                      resolveHelper,
                                      targetClass));
                          usages.add(
                              new ReplaceConstructorUsageInfo(
                                  ((PsiNewExpression) parent), newType, myTargetClasses));
                        } else if (parent instanceof PsiJavaCodeReferenceElement) {
                          usages.add(
                              new ReplaceReferenceUsageInfo(
                                  ((PsiJavaCodeReferenceElement) parent).getQualifier(),
                                  myTargetClasses));
                        }
                      }
                    }
                  }
                }
                return true;
              }
            });
    for (PsiClass targetClass : myTargetClasses) {
      for (MemberInfo memberInfo : myMemberInfos) {
        final PsiMember member = memberInfo.getMember();
        for (PsiReference reference : ReferencesSearch.search(member, member.getUseScope(), true)) {
          final PsiElement element = reference.getElement();
          if (element instanceof PsiReferenceExpression
              && ((PsiReferenceExpression) element).getQualifierExpression()
                  instanceof PsiSuperExpression
              && PsiTreeUtil.isAncestor(targetClass, element, false)) {
            usages.add(new RemoveQualifierUsageInfo((PsiReferenceExpression) element));
          }
        }
      }

      final PsiMethod[] superConstructors = mySuperClass.getConstructors();
      for (PsiMethod constructor : targetClass.getConstructors()) {
        final PsiCodeBlock constrBody = constructor.getBody();
        LOG.assertTrue(constrBody != null);
        final PsiStatement[] statements = constrBody.getStatements();
        if (statements.length > 0) {
          final PsiStatement firstConstrStatement = statements[0];
          if (firstConstrStatement instanceof PsiExpressionStatement) {
            final PsiExpression expression =
                ((PsiExpressionStatement) firstConstrStatement).getExpression();
            if (expression instanceof PsiMethodCallExpression) {
              final PsiReferenceExpression methodExpression =
                  ((PsiMethodCallExpression) expression).getMethodExpression();
              if (methodExpression.getText().equals(PsiKeyword.SUPER)) {
                final PsiMethod superConstructor =
                    ((PsiMethodCallExpression) expression).resolveMethod();
                if (superConstructor != null && superConstructor.getBody() != null) {
                  usages.add(new InlineSuperCallUsageInfo((PsiMethodCallExpression) expression));
                  continue;
                }
              }
            }
          }
        }

        // insert implicit call to super
        for (PsiMethod superConstructor : superConstructors) {
          if (superConstructor.getParameterList().getParametersCount() == 0) {
            final PsiExpression expression =
                JavaPsiFacade.getElementFactory(myProject)
                    .createExpressionFromText("super()", constructor);
            usages.add(
                new InlineSuperCallUsageInfo((PsiMethodCallExpression) expression, constrBody));
          }
        }
      }

      if (targetClass.getConstructors().length == 0) {
        // copy default constructor
        for (PsiMethod superConstructor : superConstructors) {
          if (superConstructor.getParameterList().getParametersCount() == 0) {
            usages.add(new CopyDefaultConstructorUsageInfo(targetClass, superConstructor));
            break;
          }
        }
      }
    }
  }
  @Nullable
  public static HighlightInfo checkVariableInitializedBeforeUsage(
      @NotNull PsiReferenceExpression expression,
      @NotNull PsiVariable variable,
      @NotNull Map<PsiElement, Collection<PsiReferenceExpression>> uninitializedVarProblems,
      @NotNull PsiFile containingFile) {
    if (variable instanceof ImplicitVariable) return null;
    if (!PsiUtil.isAccessedForReading(expression)) return null;
    int startOffset = expression.getTextRange().getStartOffset();
    final PsiElement topBlock;
    if (variable.hasInitializer()) {
      topBlock = PsiUtil.getVariableCodeBlock(variable, variable);
      if (topBlock == null) return null;
    } else {
      PsiElement scope =
          variable instanceof PsiField
              ? ((PsiField) variable).getContainingClass()
              : variable.getParent() != null ? variable.getParent().getParent() : null;
      if (scope instanceof PsiCodeBlock && scope.getParent() instanceof PsiSwitchStatement) {
        scope = PsiTreeUtil.getParentOfType(scope, PsiCodeBlock.class);
      }

      topBlock =
          FileTypeUtils.isInServerPageFile(scope) && scope instanceof PsiFile
              ? scope
              : PsiUtil.getTopLevelEnclosingCodeBlock(expression, scope);
      if (variable instanceof PsiField) {
        // non final field already initialized with default value
        if (!variable.hasModifierProperty(PsiModifier.FINAL)) return null;
        // final field may be initialized in ctor or class initializer only
        // if we're inside non-ctr method, skip it
        if (PsiUtil.findEnclosingConstructorOrInitializer(expression) == null
            && HighlightUtil.findEnclosingFieldInitializer(expression) == null) {
          return null;
        }
        if (topBlock == null) return null;
        final PsiElement parent = topBlock.getParent();
        // access to final fields from inner classes always allowed
        if (inInnerClass(expression, ((PsiField) variable).getContainingClass(), containingFile))
          return null;
        final PsiCodeBlock block;
        final PsiClass aClass;
        if (parent instanceof PsiMethod) {
          PsiMethod constructor = (PsiMethod) parent;
          if (!containingFile
              .getManager()
              .areElementsEquivalent(
                  constructor.getContainingClass(), ((PsiField) variable).getContainingClass()))
            return null;
          // static variables already initialized in class initializers
          if (variable.hasModifierProperty(PsiModifier.STATIC)) return null;
          // as a last chance, field may be initialized in this() call
          final List<PsiMethod> redirectedConstructors =
              JavaHighlightUtil.getChainedConstructors(constructor);
          for (int j = 0;
              redirectedConstructors != null && j < redirectedConstructors.size();
              j++) {
            PsiMethod redirectedConstructor = redirectedConstructors.get(j);
            // variable must be initialized before its usage
            // ???
            // if (startOffset < redirectedConstructor.getTextRange().getStartOffset()) continue;
            PsiCodeBlock body = redirectedConstructor.getBody();
            if (body != null && variableDefinitelyAssignedIn(variable, body)) {
              return null;
            }
          }
          block = constructor.getBody();
          aClass = constructor.getContainingClass();
        } else if (parent instanceof PsiClassInitializer) {
          final PsiClassInitializer classInitializer = (PsiClassInitializer) parent;
          if (!containingFile
              .getManager()
              .areElementsEquivalent(
                  classInitializer.getContainingClass(),
                  ((PsiField) variable).getContainingClass())) return null;
          block = classInitializer.getBody();
          aClass = classInitializer.getContainingClass();
        } else {
          // field reference outside code block
          // check variable initialized before its usage
          final PsiField field = (PsiField) variable;

          aClass = field.getContainingClass();
          if (aClass == null
              || isFieldInitializedInOtherFieldInitializer(
                  aClass, field, field.hasModifierProperty(PsiModifier.STATIC))) {
            return null;
          }
          final PsiField anotherField =
              PsiTreeUtil.getTopmostParentOfType(expression, PsiField.class);
          int offset = startOffset;
          if (anotherField != null
              && anotherField.getContainingClass() == aClass
              && !field.hasModifierProperty(PsiModifier.STATIC)) {
            offset = 0;
          }
          block = null;
          // initializers will be checked later
          final PsiMethod[] constructors = aClass.getConstructors();
          for (PsiMethod constructor : constructors) {
            // variable must be initialized before its usage
            if (offset < constructor.getTextRange().getStartOffset()) continue;
            PsiCodeBlock body = constructor.getBody();
            if (body != null && variableDefinitelyAssignedIn(variable, body)) {
              return null;
            }
            // as a last chance, field may be initialized in this() call
            final List<PsiMethod> redirectedConstructors =
                JavaHighlightUtil.getChainedConstructors(constructor);
            for (int j = 0;
                redirectedConstructors != null && j < redirectedConstructors.size();
                j++) {
              PsiMethod redirectedConstructor = redirectedConstructors.get(j);
              // variable must be initialized before its usage
              if (offset < redirectedConstructor.getTextRange().getStartOffset()) continue;
              PsiCodeBlock redirectedBody = redirectedConstructor.getBody();
              if (redirectedBody != null
                  && variableDefinitelyAssignedIn(variable, redirectedBody)) {
                return null;
              }
            }
          }
        }

        if (aClass != null) {
          // field may be initialized in class initializer
          final PsiClassInitializer[] initializers = aClass.getInitializers();
          for (PsiClassInitializer initializer : initializers) {
            PsiCodeBlock body = initializer.getBody();
            if (body == block) break;
            // variable referenced in initializer must be initialized in initializer preceding
            // assignment
            // variable referenced in field initializer or in class initializer
            boolean shouldCheckInitializerOrder =
                block == null || block.getParent() instanceof PsiClassInitializer;
            if (shouldCheckInitializerOrder
                && startOffset < initializer.getTextRange().getStartOffset()) continue;
            if (initializer.hasModifierProperty(PsiModifier.STATIC)
                == variable.hasModifierProperty(PsiModifier.STATIC)) {
              if (variableDefinitelyAssignedIn(variable, body)) return null;
            }
          }
        }
      }
    }
    if (topBlock == null) return null;
    Collection<PsiReferenceExpression> codeBlockProblems = uninitializedVarProblems.get(topBlock);
    if (codeBlockProblems == null) {
      try {
        final ControlFlow controlFlow = getControlFlow(topBlock);
        codeBlockProblems = ControlFlowUtil.getReadBeforeWriteLocals(controlFlow);
      } catch (AnalysisCanceledException | IndexNotReadyException e) {
        codeBlockProblems = Collections.emptyList();
      }
      uninitializedVarProblems.put(topBlock, codeBlockProblems);
    }
    if (codeBlockProblems.contains(expression)) {
      final String name = expression.getElement().getText();
      String description = JavaErrorMessages.message("variable.not.initialized", name);
      HighlightInfo highlightInfo =
          HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
              .range(expression)
              .descriptionAndTooltip(description)
              .create();
      QuickFixAction.registerQuickFixAction(
          highlightInfo, QUICK_FIX_FACTORY.createAddVariableInitializerFix(variable));
      if (variable instanceof PsiField) {
        QuickFixAction.registerQuickFixAction(
            highlightInfo,
            QUICK_FIX_FACTORY.createModifierListFix(variable, PsiModifier.FINAL, false, false));
      }
      return highlightInfo;
    }

    return null;
  }
  @Override
  public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file)
      throws IncorrectOperationException {
    if (!FileModificationService.getInstance().prepareFileForWrite(file)) return;

    PsiMethod[] constructors = myClass.getConstructors();
    if (constructors.length == 0) {
      final AddDefaultConstructorFix defaultConstructorFix = new AddDefaultConstructorFix(myClass);
      ApplicationManager.getApplication()
          .runWriteAction(
              new Runnable() {
                @Override
                public void run() {
                  defaultConstructorFix.invoke(project, editor, file);
                }
              });
      constructors = myClass.getConstructors();
    }
    Arrays.sort(
        constructors,
        new Comparator<PsiMethod>() {
          @Override
          public int compare(PsiMethod c1, PsiMethod c2) {
            final PsiMethod cc1 = RefactoringUtil.getChainedConstructor(c1);
            final PsiMethod cc2 = RefactoringUtil.getChainedConstructor(c2);
            if (cc1 == c2) return 1;
            if (cc2 == c1) return -1;
            if (cc1 == null) {
              return cc2 == null ? 0 : compare(c1, cc2);
            } else {
              return cc2 == null ? compare(cc1, c2) : compare(cc1, cc2);
            }
          }
        });
    final ArrayList<PsiMethod> constrs =
        filterConstructorsIfFieldAlreadyAssigned(constructors, getField());
    if (constrs.size() > 1) {
      final PsiMethodMember[] members = new PsiMethodMember[constrs.size()];
      int i = 0;
      for (PsiMethod constructor : constrs) {
        members[i++] = new PsiMethodMember(constructor);
      }
      final List<PsiMethodMember> elements;
      if (ApplicationManager.getApplication().isUnitTestMode()) {
        elements = Arrays.asList(members);
      } else {
        final MemberChooser<PsiMethodMember> chooser =
            new MemberChooser<PsiMethodMember>(members, false, true, project);
        chooser.setTitle("Choose constructors to add parameter to");
        chooser.show();
        elements = chooser.getSelectedElements();
        if (elements == null) return;
      }

      for (PsiMethodMember member : elements) {
        if (!addParameterToConstructor(
            project, file, editor, member.getElement(), new PsiField[] {getField()})) break;
      }

    } else if (!constrs.isEmpty()) {
      final Collection<SmartPsiElementPointer<PsiField>> fieldsToFix = getFieldsToFix();
      try {
        final PsiMethod constructor = constrs.get(0);
        final LinkedHashSet<PsiField> fields = new LinkedHashSet<PsiField>();
        getFieldsToFix().add(myField);
        for (SmartPsiElementPointer<PsiField> elementPointer : fieldsToFix) {
          final PsiField field = elementPointer.getElement();
          if (field != null
              && isAvailable(field)
              && filterConstructorsIfFieldAlreadyAssigned(new PsiMethod[] {constructor}, field)
                  .contains(constructor)) {
            fields.add(field);
          }
        }
        if (constrs.size() == constructors.length
            && fields.size() > 1
            && !ApplicationManager.getApplication().isUnitTestMode()) {
          PsiFieldMember[] members = new PsiFieldMember[fields.size()];
          int i = 0;
          for (PsiField field : fields) {
            members[i++] = new PsiFieldMember(field);
          }
          MemberChooser<PsiElementClassMember> chooser =
              new MemberChooser<PsiElementClassMember>(members, false, true, project);
          chooser.setTitle("Choose Fields to Generate Constructor Parameters for");
          chooser.show();
          if (chooser.getExitCode() != DialogWrapper.OK_EXIT_CODE) return;
          final List<PsiElementClassMember> selectedElements = chooser.getSelectedElements();
          if (selectedElements == null) return;
          fields.clear();
          for (PsiElementClassMember member : selectedElements) {
            fields.add((PsiField) member.getElement());
          }
        }

        addParameterToConstructor(
            project,
            file,
            editor,
            constructor,
            constrs.size() == constructors.length
                ? fields.toArray(new PsiField[fields.size()])
                : new PsiField[] {getField()});
      } finally {
        fieldsToFix.clear();
      }
    }
  }