2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com
.intellij
.codeInsight
.daemon
.impl
.quickfix
;
18 import com
.intellij
.codeInsight
.CodeInsightUtilBase
;
19 import com
.intellij
.codeInsight
.daemon
.QuickFixBundle
;
20 import com
.intellij
.codeInsight
.daemon
.impl
.HighlightInfo
;
21 import com
.intellij
.codeInsight
.daemon
.impl
.HighlightInfoType
;
22 import com
.intellij
.codeInsight
.intention
.IntentionAction
;
23 import com
.intellij
.openapi
.editor
.Editor
;
24 import com
.intellij
.openapi
.project
.Project
;
25 import com
.intellij
.openapi
.util
.Comparing
;
26 import com
.intellij
.psi
.*;
27 import com
.intellij
.psi
.infos
.CandidateInfo
;
28 import com
.intellij
.psi
.infos
.MethodCandidateInfo
;
29 import com
.intellij
.util
.IncorrectOperationException
;
30 import org
.jetbrains
.annotations
.NotNull
;
32 import java
.util
.HashSet
;
33 import java
.util
.List
;
36 public class ChangeStringLiteralToCharInMethodCallFix
implements IntentionAction
{
37 private final PsiLiteralExpression myLiteral
;
38 private final PsiCall myCall
;
40 public ChangeStringLiteralToCharInMethodCallFix(final PsiLiteralExpression literal
, final PsiCall methodCall
) {
46 public String
getText() {
47 final String convertedValue
= convertedValue();
48 final boolean isString
= isString(myLiteral
.getType());
49 return QuickFixBundle
.message("fix.single.character.string.to.char.literal.text", myLiteral
.getText(),
50 quote(convertedValue
, ! isString
), isString ? PsiType
.CHAR
.getCanonicalText() : "String");
54 public String
getFamilyName() {
55 return QuickFixBundle
.message("fix.single.character.string.to.char.literal.family");
58 public boolean isAvailable(@NotNull final Project project
, final Editor editor
, final PsiFile file
) {
59 return myCall
.isValid() && myLiteral
.isValid() && myCall
.getManager().isInProject(myCall
);
62 public void invoke(@NotNull final Project project
, final Editor editor
, final PsiFile file
) throws IncorrectOperationException
{
63 if (!CodeInsightUtilBase
.prepareFileForWrite(file
)) return;
65 final Object value
= myLiteral
.getValue();
66 if ((value
!= null) && (value
.toString().length() == 1)) {
67 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(project
).getElementFactory();
69 final PsiExpression newExpression
= factory
.createExpressionFromText(quote(convertedValue(), ! isString(myLiteral
.getType())),
70 myLiteral
.getParent());
71 myLiteral
.replace(newExpression
);
75 public boolean startInWriteAction() {
79 private String
quote(final String value
, final boolean doubleQuotes
) {
80 final char quote
= doubleQuotes ?
'"' : '\'';
81 return quote
+ value
+ quote
;
84 private String
convertedValue() {
85 String value
= String
.valueOf(myLiteral
.getValue());
86 return ("\"".equals(value
) || "'".equals(value
)) ?
"\\" + value
: value
;
89 public static void createHighLighting(@NotNull final PsiMethod
[] candidates
, @NotNull final PsiConstructorCall call
,
90 @NotNull final List
<HighlightInfo
> out
) {
91 final Set
<PsiLiteralExpression
> literals
= new HashSet
<PsiLiteralExpression
>();
92 if (call
.getArgumentList() == null) {
95 boolean exactMatch
= false;
96 for (PsiMethod method
: candidates
) {
97 exactMatch
|= findMatchingExpressions(call
.getArgumentList().getExpressions(), method
, literals
);
100 processLiterals(literals
, call
, out
);
104 public static void createHighLighting(@NotNull final CandidateInfo
[] candidates
, @NotNull final PsiMethodCallExpression methodCall
,
105 @NotNull final List
<HighlightInfo
> out
) {
106 final Set
<PsiLiteralExpression
> literals
= new HashSet
<PsiLiteralExpression
>();
107 boolean exactMatch
= false;
108 for (CandidateInfo candidate
: candidates
) {
109 if (candidate
instanceof MethodCandidateInfo
) {
110 final PsiMethod method
= ((MethodCandidateInfo
) candidate
).getElement();
111 exactMatch
|= findMatchingExpressions(methodCall
.getArgumentList().getExpressions(), method
, literals
);
115 processLiterals(literals
, methodCall
, out
);
119 private static void processLiterals(@NotNull final Set
<PsiLiteralExpression
> literals
, @NotNull final PsiCall call
,
120 @NotNull final List
<HighlightInfo
> out
) {
121 for (PsiLiteralExpression literal
: literals
) {
122 final HighlightInfo info
= HighlightInfo
.createHighlightInfo(HighlightInfoType
.ERROR
, literal
, null);
123 final ChangeStringLiteralToCharInMethodCallFix fix
= new ChangeStringLiteralToCharInMethodCallFix(literal
, call
);
124 QuickFixAction
.registerQuickFixAction(info
, fix
);
130 * @return <code>true</code> if exact TYPEs match
132 private static boolean findMatchingExpressions(final PsiExpression
[] arguments
, final PsiMethod existingMethod
,
133 final Set
<PsiLiteralExpression
> result
) {
134 final PsiParameterList parameterList
= existingMethod
.getParameterList();
135 final PsiParameter
[] parameters
= parameterList
.getParameters();
137 if (arguments
.length
!= parameters
.length
) {
141 boolean typeMatch
= true;
142 for (int i
= 0; (i
< parameters
.length
) && (i
< arguments
.length
); i
++) {
143 final PsiParameter parameter
= parameters
[i
];
144 final PsiType parameterType
= parameter
.getType();
145 final PsiType argumentType
= arguments
[i
].getType();
147 typeMatch
&= Comparing
.equal(parameterType
, argumentType
);
149 if ((arguments
[i
] instanceof PsiLiteralExpression
) &&
150 (! result
.contains(arguments
[i
])) &&
151 (charToString(parameterType
, argumentType
) || charToString(argumentType
, parameterType
))) {
153 final String value
= String
.valueOf(((PsiLiteralExpression
) arguments
[i
]).getValue());
154 if ((value
!= null) && (value
.length() == 1)) {
155 result
.add((PsiLiteralExpression
) arguments
[i
]);
162 private static boolean charToString(final PsiType firstType
, final PsiType secondType
) {
163 return Comparing
.equal(PsiType
.CHAR
, firstType
) && isString(secondType
);
166 private static boolean isString(final PsiType type
) {
167 return (type
!= null) && "java.lang.String".equals((type
.getCanonicalText()));