@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); } }
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; }
@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); }