2 * Copyright 2003-2009 Dave Griffith, Bas Leijdekkers
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
.siyeh
.ig
.numeric
;
18 import com
.intellij
.codeInspection
.ProblemDescriptor
;
19 import com
.intellij
.openapi
.project
.Project
;
20 import com
.intellij
.psi
.PsiExpression
;
21 import com
.intellij
.psi
.PsiLiteralExpression
;
22 import com
.intellij
.psi
.PsiType
;
23 import com
.intellij
.util
.IncorrectOperationException
;
24 import com
.siyeh
.InspectionGadgetsBundle
;
25 import com
.siyeh
.ig
.BaseInspection
;
26 import com
.siyeh
.ig
.BaseInspectionVisitor
;
27 import com
.siyeh
.ig
.InspectionGadgetsFix
;
28 import org
.jetbrains
.annotations
.NotNull
;
29 import org
.jetbrains
.annotations
.Nullable
;
31 public class ConfusingFloatingPointLiteralInspection
32 extends BaseInspection
{
36 public String
getDisplayName() {
37 return InspectionGadgetsBundle
.message(
38 "confusing.floating.point.literal.display.name");
43 protected String
buildErrorString(Object
... infos
) {
44 return InspectionGadgetsBundle
.message(
45 "confusing.floating.point.literal.problem.descriptor");
49 public InspectionGadgetsFix
buildFix(Object
... infos
) {
50 return new ConfusingFloatingPointLiteralFix();
53 private static class ConfusingFloatingPointLiteralFix
54 extends InspectionGadgetsFix
{
57 public String
getName() {
58 return InspectionGadgetsBundle
.message(
59 "confusing.floating.point.literal.change.quickfix");
63 public void doFix(Project project
, ProblemDescriptor descriptor
)
64 throws IncorrectOperationException
{
65 final PsiExpression literalExpression
=
66 (PsiExpression
)descriptor
.getPsiElement();
67 final String text
= literalExpression
.getText();
68 final String newText
= getCanonicalForm(text
);
69 replaceExpression(literalExpression
, newText
);
72 private static String
getCanonicalForm(String text
) {
73 final boolean isHexadecimal
=
74 text
.startsWith("0x") || text
.startsWith("0X");
75 int breakPoint
= text
.indexOf((int)'e');
77 breakPoint
= text
.indexOf((int)'E');
80 breakPoint
= text
.indexOf((int)'f');
83 breakPoint
= text
.indexOf((int)'F');
86 breakPoint
= text
.indexOf((int)'p');
89 breakPoint
= text
.indexOf((int)'P');
92 breakPoint
= text
.indexOf((int)'d');
95 breakPoint
= text
.indexOf((int)'D');
103 suffix
= text
.substring(breakPoint
);
104 prefix
= text
.substring(0, breakPoint
);
106 final int indexPoint
= prefix
.indexOf((int)'.');
107 if (indexPoint
< 0) {
108 return prefix
+ ".0" + suffix
;
109 } else if (isHexadecimal
&& indexPoint
== 2) {
110 return prefix
.substring(0, 2) + '0' + prefix
.substring(2) + suffix
;
111 } else if (indexPoint
== 0) {
112 return '0' + prefix
+ suffix
;
114 return prefix
+ '0' + suffix
;
121 public BaseInspectionVisitor
buildVisitor() {
122 return new ConfusingFloatingPointLiteralVisitor();
125 private static class ConfusingFloatingPointLiteralVisitor
126 extends BaseInspectionVisitor
{
128 @Override public void visitLiteralExpression(
129 @NotNull PsiLiteralExpression literal
) {
130 super.visitLiteralExpression(literal
);
131 final PsiType type
= literal
.getType();
135 if (!(type
.equals(PsiType
.FLOAT
) || type
.equals(PsiType
.DOUBLE
))) {
138 final String text
= literal
.getText();
142 if (!isConfusing(text
)) {
145 registerError(literal
);
149 private static boolean isConfusing(@Nullable CharSequence text
) {
153 final int length
= text
.length();
157 boolean hexadecimal
= true;
158 final char firstChar
= text
.charAt(0);
159 if (firstChar
!= '0') {
161 } else if (firstChar
< '0' && firstChar
> '9'){
164 final char secondChar
= text
.charAt(1);
166 if (secondChar
!= 'x' && secondChar
!= 'X') {
170 int index
= hexadecimal ?
2 : 1;
171 char nextChar
= text
.charAt(index
);
172 if (hexadecimal
&& (nextChar
< '0' || nextChar
> '9')) {
175 while (nextChar
>= '0' && nextChar
<='9') {
177 if (index
>= length
) {
180 nextChar
= text
.charAt(index
);
182 if (nextChar
!= '.') {
186 if (index
>= length
) {
189 nextChar
= text
.charAt(index
);
190 if (nextChar
< '0' || nextChar
> '9') {
193 while (nextChar
>= '0' && nextChar
<= '9') {
195 if (index
>= length
) {
198 nextChar
= text
.charAt(index
);
201 if (nextChar
!= 'p' && nextChar
!= 'P') {
205 if (nextChar
!= 'e' && nextChar
!= 'E') {
206 if (nextChar
=='f' || nextChar
== 'F' ||
207 nextChar
== 'd' || nextChar
== 'D') {
208 if (index
== length
- 1) {
216 if (index
>= length
) {
219 nextChar
= text
.charAt(index
);
220 if (nextChar
== '-') {
222 if (index
>= length
) {
225 nextChar
= text
.charAt(index
);
227 while (nextChar
>= '0' && nextChar
<= '9') {
229 if (index
>= length
) {
232 nextChar
= text
.charAt(index
);
234 // ignore trailing f, F, d or D