f0a34ce3d9539eca1f1eb19b9cd6f97796895f09
[idea/community.git] / java / java-analysis-impl / src / com / intellij / codeInsight / daemon / impl / quickfix / WrapLongWithMathToIntExactFix.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.codeInsight.daemon.impl.quickfix;
17
18 import com.intellij.codeInsight.FileModificationService;
19 import com.intellij.codeInsight.daemon.QuickFixBundle;
20 import com.intellij.codeInsight.intention.HighPriorityAction;
21 import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
22 import com.intellij.openapi.editor.Editor;
23 import com.intellij.openapi.project.Project;
24 import com.intellij.psi.*;
25 import com.intellij.psi.util.PsiUtil;
26 import com.intellij.util.IncorrectOperationException;
27 import org.jetbrains.annotations.Nls;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
30
31 /**
32  * @author Dmitry Batkovich
33  */
34 public class WrapLongWithMathToIntExactFix extends LocalQuickFixAndIntentionActionOnPsiElement implements HighPriorityAction {
35   public final static MyMethodArgumentFixerFactory REGISTAR = new MyMethodArgumentFixerFactory();
36
37   private final PsiType myType;
38
39   public WrapLongWithMathToIntExactFix(final PsiType type, final @NotNull PsiExpression expression) {
40     super(expression);
41     myType = type;
42   }
43
44   @NotNull
45   @Override
46   public String getText() {
47     return getFamilyName();
48   }
49
50   @Override
51   public void invoke(@NotNull Project project,
52                      @NotNull PsiFile file,
53                      @Nullable("is null when called from inspection") Editor editor,
54                      @NotNull PsiElement startElement,
55                      @NotNull PsiElement endElement) {
56     if (!FileModificationService.getInstance().prepareFileForWrite(file)) return;
57     startElement.replace(getModifiedExpression(startElement));
58   }
59
60   @Override
61   public boolean isAvailable(@NotNull Project project,
62                              @NotNull PsiFile file,
63                              @NotNull PsiElement startElement,
64                              @NotNull PsiElement endElement) {
65     return startElement.isValid() &&
66            startElement.getManager().isInProject(startElement) &&
67            PsiUtil.isLanguageLevel8OrHigher(startElement) &&
68            areSameTypes(myType, PsiType.INT) &&
69            areSameTypes(((PsiExpression) startElement).getType(), PsiType.LONG);
70   }
71
72   private static boolean areSameTypes(@Nullable PsiType type, @NotNull PsiPrimitiveType expected) {
73     return !(type == null ||
74              !type.isValid() ||
75              (!type.equals(expected) && !expected.getBoxedTypeName().equals(type.getCanonicalText(false))));
76   }
77
78   @Nls
79   @NotNull
80   @Override
81   public String getFamilyName() {
82     return QuickFixBundle.message("wrap.long.with.math.to.int.text");
83   }
84
85   private static PsiElement getModifiedExpression(PsiElement expression) {
86     return JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText("java.lang.Math.toIntExact(" + expression.getText() + ")", expression);
87   }
88
89   private static class MyMethodArgumentFix extends MethodArgumentFix implements HighPriorityAction {
90
91     protected MyMethodArgumentFix(@NotNull PsiExpressionList list,
92                                   int i,
93                                   @NotNull PsiType toType,
94                                   @NotNull ArgumentFixerActionFactory fixerActionFactory) {
95       super(list, i, toType, fixerActionFactory);
96     }
97
98     @Nls
99     @NotNull
100     @Override
101     public String getText() {
102       return myArgList.getExpressions().length == 1
103              ? QuickFixBundle.message("wrap.long.with.math.to.int.parameter.single.text")
104              : QuickFixBundle.message("wrap.long.with.math.to.int.parameter.multiple.text", myIndex + 1);
105     }
106
107     @Override
108     public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
109       return PsiUtil.isLanguageLevel8OrHigher(file) && super.isAvailable(project, editor, file);
110     }
111   }
112
113   public static class MyMethodArgumentFixerFactory extends ArgumentFixerActionFactory {
114     @Nullable
115     @Override
116     protected PsiExpression getModifiedArgument(final PsiExpression expression, final PsiType toType) throws IncorrectOperationException {
117       return areSameTypes(toType, PsiType.INT) ? (PsiExpression)getModifiedExpression(expression) : null;
118     }
119
120     @Override
121     public boolean areTypesConvertible(@NotNull final PsiType exprType, @NotNull final PsiType parameterType, @NotNull final PsiElement context) {
122       return parameterType.isConvertibleFrom(exprType) || (areSameTypes(parameterType, PsiType.INT) && areSameTypes(exprType, PsiType.LONG));
123     }
124
125     @Override
126     public MethodArgumentFix createFix(final PsiExpressionList list, final int i, final PsiType toType) {
127       return new MyMethodArgumentFix(list, i, toType, this);
128     }
129   }
130 }