com.intellij.codeInsight.daemon.impl.quickfix.ModifierFix.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.codeInsight.daemon.impl.quickfix.ModifierFix.java

Source

/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.codeInsight.daemon.impl.quickfix;

import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.undo.UndoUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.*;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.search.PsiElementProcessorAdapter;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.PsiFormatUtilBase;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.VisibilityUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;

public class ModifierFix extends LocalQuickFixAndIntentionActionOnPsiElement {
    private static final Logger LOG = Logger
            .getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.ModifierFix");

    @PsiModifier.ModifierConstant
    private final String myModifier;
    private final boolean myShouldHave;
    private final boolean myShowContainingClass;
    private final String myName;
    private final SmartPsiElementPointer<PsiVariable> myVariable;

    public ModifierFix(PsiModifierList modifierList, @PsiModifier.ModifierConstant @NotNull String modifier,
            boolean shouldHave, boolean showContainingClass) {
        super(modifierList);
        myModifier = modifier;
        myShouldHave = shouldHave;
        myShowContainingClass = showContainingClass;
        myName = format(null, modifierList);
        myVariable = null;
    }

    public ModifierFix(@NotNull PsiModifierListOwner owner, @PsiModifier.ModifierConstant @NotNull String modifier,
            boolean shouldHave, boolean showContainingClass) {
        super(owner.getModifierList());
        myModifier = modifier;
        myShouldHave = shouldHave;
        myShowContainingClass = showContainingClass;
        PsiVariable variable = owner instanceof PsiVariable ? (PsiVariable) owner : null;
        myName = format(variable, owner.getModifierList());

        myVariable = variable == null ? null
                : SmartPointerManager.getInstance(owner.getProject()).createSmartPsiElementPointer(variable);
    }

    @NotNull
    @Override
    public String getText() {
        return myName;
    }

    private String format(PsiVariable variable, PsiModifierList modifierList) {
        String name = null;
        PsiElement parent = variable == null ? modifierList == null ? null : modifierList.getParent() : variable;
        if (parent instanceof PsiClass) {
            name = ((PsiClass) parent).getName();
        } else {
            int options = PsiFormatUtilBase.SHOW_NAME
                    | (myShowContainingClass ? PsiFormatUtilBase.SHOW_CONTAINING_CLASS : 0);
            if (parent instanceof PsiMethod) {
                name = PsiFormatUtil.formatMethod((PsiMethod) parent, PsiSubstitutor.EMPTY, options, 0);
            } else if (parent instanceof PsiVariable) {
                name = PsiFormatUtil.formatVariable((PsiVariable) parent, options, PsiSubstitutor.EMPTY);
            } else if (parent instanceof PsiClassInitializer) {
                PsiClass containingClass = ((PsiClassInitializer) parent).getContainingClass();
                String className = containingClass instanceof PsiAnonymousClass
                        ? QuickFixBundle.message("anonymous.class.presentation",
                                ((PsiAnonymousClass) containingClass).getBaseClassType().getPresentableText())
                        : containingClass != null ? containingClass.getName() : "unknown";
                name = QuickFixBundle.message("class.initializer.presentation", className);
            }
        }

        String modifierText = VisibilityUtil.toPresentableText(myModifier);

        return QuickFixBundle.message(myShouldHave ? "add.modifier.fix" : "remove.modifier.fix", name,
                modifierText);
    }

    @Override
    @NotNull
    public String getFamilyName() {
        return QuickFixBundle.message("fix.modifiers.family");
    }

    @Override
    public boolean isAvailable(@NotNull Project project, @NotNull PsiFile file, @NotNull PsiElement startElement,
            @NotNull PsiElement endElement) {
        final PsiModifierList myModifierList = (PsiModifierList) startElement;
        PsiVariable variable = myVariable == null ? null : myVariable.getElement();
        return myModifierList.isValid() && myModifierList.getManager().isInProject(myModifierList)
                && myModifierList.hasExplicitModifier(myModifier) != myShouldHave
                && (variable == null || variable.isValid());
    }

    private void changeModifierList(PsiModifierList modifierList) {
        try {
            modifierList.setModifierProperty(myModifier, myShouldHave);
        } catch (IncorrectOperationException e) {
            LOG.error(e);
        }
    }

    @Override
    public void invoke(@NotNull Project project, @NotNull PsiFile file,
            @Nullable("is null when called from inspection") Editor editor, @NotNull PsiElement startElement,
            @NotNull PsiElement endElement) {
        final PsiModifierList myModifierList = (PsiModifierList) startElement;
        final PsiVariable variable = myVariable == null ? null : myVariable.getElement();
        if (!FileModificationService.getInstance().preparePsiElementForWrite(myModifierList))
            return;
        final List<PsiModifierList> modifierLists = new ArrayList<PsiModifierList>();
        final PsiFile containingFile = myModifierList.getContainingFile();
        final PsiModifierList modifierList;
        if (variable != null && variable.isValid()) {
            ApplicationManager.getApplication().runWriteAction(new Runnable() {
                @Override
                public void run() {
                    try {
                        variable.normalizeDeclaration();
                    } catch (IncorrectOperationException e) {
                        LOG.error(e);
                    }
                }
            });
            modifierList = variable.getModifierList();
            assert modifierList != null;
        } else {
            modifierList = myModifierList;
        }
        PsiElement owner = modifierList.getParent();
        if (owner instanceof PsiMethod) {
            PsiModifierList copy = (PsiModifierList) myModifierList.copy();
            changeModifierList(copy);
            final int accessLevel = PsiUtil.getAccessLevel(copy);

            OverridingMethodsSearch.search((PsiMethod) owner, owner.getResolveScope(), true)
                    .forEach(new PsiElementProcessorAdapter<PsiMethod>(new PsiElementProcessor<PsiMethod>() {
                        @Override
                        public boolean execute(@NotNull PsiMethod inheritor) {
                            PsiModifierList list = inheritor.getModifierList();
                            if (inheritor.getManager().isInProject(inheritor)
                                    && PsiUtil.getAccessLevel(list) < accessLevel) {
                                modifierLists.add(list);
                            }
                            return true;
                        }
                    }));
        }

        if (!FileModificationService.getInstance().prepareFileForWrite(containingFile))
            return;

        if (!modifierLists.isEmpty()) {
            if (Messages.showYesNoDialog(project,
                    QuickFixBundle.message("change.inheritors.visibility.warning.text"),
                    QuickFixBundle.message("change.inheritors.visibility.warning.title"),
                    Messages.getQuestionIcon()) == DialogWrapper.OK_EXIT_CODE) {
                ApplicationManager.getApplication().runWriteAction(new Runnable() {
                    @Override
                    public void run() {
                        if (!FileModificationService.getInstance().preparePsiElementsForWrite(modifierLists)) {
                            return;
                        }

                        for (final PsiModifierList modifierList : modifierLists) {
                            changeModifierList(modifierList);
                        }
                    }
                });
            }
        }

        ApplicationManager.getApplication().runWriteAction(new Runnable() {
            @Override
            public void run() {
                changeModifierList(modifierList);
                UndoUtil.markPsiFileForUndo(containingFile);
            }
        });
    }

    @Override
    public boolean startInWriteAction() {
        return false;
    }

}