@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 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");
     }
   }
 }
  @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);
    }
  }
Beispiel #4
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;
 }
  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;
  }
  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;
  }
  @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();
      }
    }
  }
  protected void performRefactoring(@NotNull UsageInfo[] usageInfos) {
    final PsiClass psiClass = buildClass();
    if (psiClass == null) return;
    if (delegationRequired) {
      buildDelegate();
    }
    myExtractEnumProcessor.performEnumConstantTypeMigration(usageInfos);
    final Set<PsiMember> members = new HashSet<PsiMember>();
    for (PsiMethod method : methods) {
      final PsiMethod member = psiClass.findMethodBySignature(method, false);
      if (member != null) {
        members.add(member);
      }
    }
    for (PsiField field : fields) {
      final PsiField member = psiClass.findFieldByName(field.getName(), false);
      if (member != null) {
        members.add(member);
        final PsiExpression initializer = member.getInitializer();
        if (initializer != null) {
          final boolean[] moveInitializerToConstructor = new boolean[1];
          initializer.accept(
              new JavaRecursiveElementWalkingVisitor() {
                @Override
                public void visitReferenceExpression(PsiReferenceExpression expression) {
                  super.visitReferenceExpression(expression);
                  final PsiElement resolved = expression.resolve();
                  if (resolved instanceof PsiField && !members.contains(resolved)) {
                    moveInitializerToConstructor[0] = true;
                  }
                }
              });

          if (moveInitializerToConstructor[0]) {
            final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject);
            PsiMethod[] constructors = psiClass.getConstructors();
            if (constructors.length == 0) {
              final PsiMethod constructor =
                  (PsiMethod) elementFactory.createConstructor().setName(psiClass.getName());
              constructors = new PsiMethod[] {(PsiMethod) psiClass.add(constructor)};
            }
            for (PsiMethod constructor : constructors) {
              MoveInstanceMembersUtil.moveInitializerToConstructor(
                  elementFactory, constructor, member);
            }
          }
        }
      }
    }

    if (myGenerateAccessors) {
      final NecessaryAccessorsVisitor visitor = checkNecessaryGettersSetters4SourceClass();
      for (PsiField field : visitor.getFieldsNeedingGetter()) {
        sourceClass.add(GenerateMembersUtil.generateGetterPrototype(field));
      }

      for (PsiField field : visitor.getFieldsNeedingSetter()) {
        sourceClass.add(GenerateMembersUtil.generateSetterPrototype(field));
      }
    }
    super.performRefactoring(usageInfos);
    if (myNewVisibility == null) return;
    for (PsiMember member : members) {
      VisibilityUtil.fixVisibility(UsageViewUtil.toElements(usageInfos), member, myNewVisibility);
    }
  }
  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;
  }
Beispiel #10
0
  @NotNull
  public Class classToClass(@NotNull PsiClass psiClass) {
    Set<String> modifiers = modifiersListToModifiersSet(psiClass.getModifierList());
    List<Field> fields = fieldsToFieldList(psiClass.getFields(), psiClass);
    List<Element> typeParameters = elementsToElementList(psiClass.getTypeParameters());
    List<Type> implementsTypes = typesToNotNullableTypeList(psiClass.getImplementsListTypes());
    List<Type> extendsTypes = typesToNotNullableTypeList(psiClass.getExtendsListTypes());
    IdentifierImpl name = new IdentifierImpl(psiClass.getName());
    List<Expression> baseClassParams = new LinkedList<Expression>();

    List<Member> members = getMembers(psiClass);

    // we try to find super() call and generate class declaration like that: class A(name: String, i
    // : Int) : Base(name)
    SuperVisitor visitor = new SuperVisitor();
    psiClass.accept(visitor);
    Collection<PsiExpressionList> resolvedSuperCallParameters =
        visitor.getResolvedSuperCallParameters();
    if (resolvedSuperCallParameters.size() == 1) {
      baseClassParams.addAll(
          expressionsToExpressionList(
              resolvedSuperCallParameters.toArray(new PsiExpressionList[1])[0].getExpressions()));
    }

    // we create primary constructor from all non final fields and fields without initializers
    if (!psiClass.isEnum()
        && !psiClass.isInterface()
        && psiClass.getConstructors().length > 1
        && getPrimaryConstructorForThisCase(psiClass) == null) {
      List<Field> finalOrWithEmptyInitializer = getFinalOrWithEmptyInitializer(fields);
      Map<String, String> initializers = new HashMap<String, String>();

      for (Member m : members) {
        // and modify secondaries
        if (m.getKind() == INode.Kind.CONSTRUCTOR) {
          Function f = (Function) m;
          if (!((Constructor) f).isPrimary()) {
            for (Field fo : finalOrWithEmptyInitializer) {
              String init = getDefaultInitializer(fo);
              initializers.put(fo.getIdentifier().toKotlin(), init);
            }

            List<Statement> newStatements = new LinkedList<Statement>();

            for (Statement s : f.getBlock().getStatements()) {
              boolean isRemoved = false;

              if (s.getKind() == INode.Kind.ASSIGNMENT_EXPRESSION) {
                AssignmentExpression assignmentExpression = (AssignmentExpression) s;
                if (assignmentExpression.getLeft().getKind() == INode.Kind.CALL_CHAIN) {
                  for (Field fo : finalOrWithEmptyInitializer) {
                    String id = fo.getIdentifier().toKotlin();
                    if (((CallChainExpression) assignmentExpression.getLeft())
                        .getIdentifier()
                        .toKotlin()
                        .endsWith("." + id)) {
                      initializers.put(id, assignmentExpression.getRight().toKotlin());
                      isRemoved = true;
                    }
                  }
                }
              }
              if (!isRemoved) {
                newStatements.add(s);
              }
            }

            newStatements.add(
                0,
                new DummyStringExpression(
                    "val __ = "
                        + createPrimaryConstructorInvocation(
                            name.toKotlin(), finalOrWithEmptyInitializer, initializers)));

            f.setBlock(new Block(newStatements));
          }
        }
      }

      members.add(
          new Constructor(
              Identifier.EMPTY_IDENTIFIER,
              Collections.<String>emptySet(),
              new ClassType(name),
              Collections.<Element>emptyList(),
              new ParameterList(createParametersFromFields(finalOrWithEmptyInitializer)),
              new Block(createInitStatementsFromFields(finalOrWithEmptyInitializer)),
              true));
    }

    if (psiClass.isInterface()) {
      return new Trait(
          this,
          name,
          modifiers,
          typeParameters,
          extendsTypes,
          Collections.<Expression>emptyList(),
          implementsTypes,
          members);
    }
    if (psiClass.isEnum()) {
      return new Enum(
          this,
          name,
          modifiers,
          typeParameters,
          Collections.<Type>emptyList(),
          Collections.<Expression>emptyList(),
          implementsTypes,
          members);
    }
    return new Class(
        this,
        name,
        modifiers,
        typeParameters,
        extendsTypes,
        baseClassParams,
        implementsTypes,
        members);
  }