diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java index d920f3993df3..a596e30b5565 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -21,6 +21,7 @@ package com.intellij.debugger.engine.evaluation.expression; import com.intellij.codeInsight.daemon.JavaErrorMessages; +import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.SourcePosition; @@ -160,7 +161,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { final PsiType unboxedLType = PsiPrimitiveType.getUnboxedType(lType); if (unboxedLType != null) { - if (rType instanceof PsiPrimitiveType && !PsiPrimitiveType.NULL.equals(rType)) { + if (rType instanceof PsiPrimitiveType && !PsiType.NULL.equals(rType)) { if (!rType.equals(unboxedLType)) { rEvaluator = new TypeCastEvaluator(rEvaluator, unboxedLType.getCanonicalText(), true); } @@ -175,7 +176,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { } final PsiPrimitiveType unboxedRType = PsiPrimitiveType.getUnboxedType(rType); final PsiType _rType = unboxedRType != null? unboxedRType : rType; - if (_rType instanceof PsiPrimitiveType && !PsiPrimitiveType.NULL.equals(_rType)) { + if (_rType instanceof PsiPrimitiveType && !PsiType.NULL.equals(_rType)) { if (!lType.equals(_rType)) { rEvaluator = new TypeCastEvaluator(rEvaluator, lType.getCanonicalText(), true); } @@ -988,9 +989,9 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { @Override public void visitLiteralExpression(PsiLiteralExpression expression) { - final String parsingError = HighlightUtil.getLiteralExpressionParsingError(expression); + final HighlightInfo parsingError = HighlightUtil.checkLiteralExpressionParsingError(expression); if (parsingError != null) { - throwEvaluateException(parsingError); + throwEvaluateException(parsingError.description); return; } @@ -1219,9 +1220,9 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { myResult = new ArrayInitializerEvaluator(evaluators); } + @Nullable private static PsiClass getOuterClass(PsiClass aClass) { - if(aClass == null) return null; - return PsiTreeUtil.getContextOfType(aClass, PsiClass.class, true); + return aClass == null ? null : PsiTreeUtil.getContextOfType(aClass, PsiClass.class, true); } private PsiClass getContainingClass(PsiVariable variable) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 66ee1e61c6e5..618e5e8701ac 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -883,42 +883,30 @@ public class HighlightUtil { return null; } - @Nullable - static HighlightInfo checkLiteralExpressionParsingError(final PsiLiteralExpression expression) { - final String error = getLiteralExpressionParsingError(expression); - if (error != null) { - final HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, error); - QuickFixAction.registerQuickFixActions(info, getLiteralExpressionQuickFixes(expression)); - return info; - } - return null; - } - - private static final Key TOO_BIG_CHAR_LITERAL_KEY = Key.create("too.big.char.literal"); - - @Nullable - public static String getLiteralExpressionParsingError(final PsiLiteralExpression expression) { + public static HighlightInfo checkLiteralExpressionParsingError(final PsiLiteralExpression expression) { final Object value = expression.getValue(); final PsiElement literal = expression.getFirstChild(); assert literal instanceof PsiJavaToken : literal; final IElementType type = ((PsiJavaToken)literal).getTokenType(); String text = PsiLiteralExpressionImpl.NUMERIC_LITERALS.contains(type) ? literal.getText().toLowerCase() : literal.getText(); - final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(expression); if (PsiLiteralExpressionImpl.REAL_LITERALS.contains(type)) { - if (text.startsWith(PsiLiteralExpressionImpl.HEX_PREFIX) && !languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) { - return JavaErrorMessages.message("hex.FP.literals.not.supported"); + if (text.startsWith(PsiLiteralExpressionImpl.HEX_PREFIX)) { + final HighlightInfo info = checkFeature(expression, Feature.HEX_FP_LITERALS); + if (info != null) return info; } } if (PsiLiteralExpressionImpl.INTEGER_LITERALS.contains(type)) { - if (text.startsWith(PsiLiteralExpressionImpl.BIN_PREFIX) && !languageLevel.isAtLeast(LanguageLevel.JDK_1_7)) { - return JavaErrorMessages.message("binary.literals.not.supported"); + if (text.startsWith(PsiLiteralExpressionImpl.BIN_PREFIX)) { + final HighlightInfo info = checkFeature(expression, Feature.BIN_LITERALS); + if (info != null) return info; } } if (PsiLiteralExpressionImpl.NUMERIC_LITERALS.contains(type)) { - if (text.contains("_") && !languageLevel.isAtLeast(LanguageLevel.JDK_1_7)) { - return JavaErrorMessages.message("underscores.in.literals.not.supported"); + if (text.contains("_")) { + final HighlightInfo info = checkFeature(expression, Feature.UNDERSCORES); + if (info != null) return info; } } @@ -929,13 +917,16 @@ public class HighlightUtil { parent instanceof PsiPrefixExpression && ((PsiPrefixExpression)parent).getOperationTokenType() == JavaTokenType.MINUS)) { if (text.equals(PsiLiteralExpressionImpl.HEX_PREFIX)) { - return JavaErrorMessages.message("hexadecimal.numbers.must.contain.at.least.one.hexadecimal.digit"); + final String message = JavaErrorMessages.message("hexadecimal.numbers.must.contain.at.least.one.hexadecimal.digit"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); } if (text.equals(PsiLiteralExpressionImpl.BIN_PREFIX)) { - return JavaErrorMessages.message("binary.numbers.must.contain.at.least.one.hexadecimal.digit"); + final String message = JavaErrorMessages.message("binary.numbers.must.contain.at.least.one.hexadecimal.digit"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); } if (value == null || text.equals(PsiLiteralExpressionImpl._2_IN_31)) { - return JavaErrorMessages.message("integer.number.too.large"); + final String message = JavaErrorMessages.message("integer.number.too.large"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); } } } @@ -946,19 +937,23 @@ public class HighlightUtil { parent instanceof PsiPrefixExpression && ((PsiPrefixExpression)parent).getOperationTokenType() == JavaTokenType.MINUS)) { if (mText.equals(PsiLiteralExpressionImpl.HEX_PREFIX)) { - return JavaErrorMessages.message("hexadecimal.numbers.must.contain.at.least.one.hexadecimal.digit"); + final String message = JavaErrorMessages.message("hexadecimal.numbers.must.contain.at.least.one.hexadecimal.digit"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); } if (mText.equals(PsiLiteralExpressionImpl.BIN_PREFIX)) { - return JavaErrorMessages.message("binary.numbers.must.contain.at.least.one.hexadecimal.digit"); + final String message = JavaErrorMessages.message("binary.numbers.must.contain.at.least.one.hexadecimal.digit"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); } if (value == null || mText.equals(PsiLiteralExpressionImpl._2_IN_63)) { - return JavaErrorMessages.message("long.number.too.large"); + final String message = JavaErrorMessages.message("long.number.too.large"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); } } } else if (type == JavaTokenType.FLOAT_LITERAL || type == JavaTokenType.DOUBLE_LITERAL) { if (value == null) { - return JavaErrorMessages.message("malformed.floating.point.literal"); + final String message = JavaErrorMessages.message("malformed.floating.point.literal"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); } } else if (type == JavaTokenType.TRUE_KEYWORD || type == JavaTokenType.FALSE_KEYWORD || type == JavaTokenType.NULL_KEYWORD) { @@ -967,28 +962,41 @@ public class HighlightUtil { else if (type == JavaTokenType.CHARACTER_LITERAL) { // todo[r.sh] clean this mess up if (value != null) { - if (!StringUtil.endsWithChar(text, '\'')) return JavaErrorMessages.message("unclosed.char.literal"); + if (!StringUtil.endsWithChar(text, '\'')) { + final String message = JavaErrorMessages.message("unclosed.char.literal"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); + } } else { if (!StringUtil.startsWithChar(text, '\'')) return null; if (StringUtil.endsWithChar(text, '\'')) { - if (text.length() == 1) return JavaErrorMessages.message("illegal.line.end.in.character.literal"); + if (text.length() == 1) { + final String message = JavaErrorMessages.message("illegal.line.end.in.character.literal"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); + } text = text.substring(1, text.length() - 1); } else { - return JavaErrorMessages.message("illegal.line.end.in.character.literal"); + final String message = JavaErrorMessages.message("illegal.line.end.in.character.literal"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); } final StringBuilder chars = StringBuilderSpinAllocator.alloc(); final boolean success = PsiLiteralExpressionImpl.parseStringCharacters(text, chars, null); - if (!success) return JavaErrorMessages.message("illegal.escape.character.in.character.literal"); + if (!success) { + final String message = JavaErrorMessages.message("illegal.escape.character.in.character.literal"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); + } final int length = chars.length(); StringBuilderSpinAllocator.dispose(chars); if (length > 1) { - literal.putUserData(TOO_BIG_CHAR_LITERAL_KEY, Boolean.TRUE); - return JavaErrorMessages.message("too.many.characters.in.character.literal"); + final String message = JavaErrorMessages.message("too.many.characters.in.character.literal"); + final HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); + QuickFixAction.registerQuickFixAction(info, new ConvertToStringLiteralAction()); + return info; } else if (length == 0) { - return JavaErrorMessages.message("empty.character.literal"); + final String message = JavaErrorMessages.message("empty.character.literal"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); } } } @@ -1002,27 +1010,46 @@ public class HighlightUtil { if (!StringUtil.startsWithChar(text, '\"')) return null; if (StringUtil.endsWithChar(text, '\"')) { - if (text.length() == 1) return JavaErrorMessages.message("illegal.line.end.in.string.literal"); + if (text.length() == 1) { + final String message = JavaErrorMessages.message("illegal.line.end.in.string.literal"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); + } text = text.substring(1, text.length() - 1); } else { - return JavaErrorMessages.message("illegal.line.end.in.string.literal"); + final String message = JavaErrorMessages.message("illegal.line.end.in.string.literal"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); } StringBuilder chars = new StringBuilder(); boolean success = PsiLiteralExpressionImpl.parseStringCharacters(text, chars, null); - if (!success) return JavaErrorMessages.message("illegal.escape.character.in.string.literal"); + if (!success) { + final String message = JavaErrorMessages.message("illegal.escape.character.in.string.literal"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); + } } } if (value instanceof Float) { final Float number = (Float)value; - if (number.isInfinite()) return JavaErrorMessages.message("floating.point.number.too.large"); - if (number.floatValue() == 0 && !isFPZero(text)) return JavaErrorMessages.message("floating.point.number.too.small"); + if (number.isInfinite()) { + final String message = JavaErrorMessages.message("floating.point.number.too.large"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); + } + if (number.floatValue() == 0 && !isFPZero(text)) { + final String message = JavaErrorMessages.message("floating.point.number.too.small"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); + } } else if (value instanceof Double) { final Double number = (Double)value; - if (number.isInfinite()) return JavaErrorMessages.message("floating.point.number.too.large"); - if (number.doubleValue() == 0 && !isFPZero(text)) return JavaErrorMessages.message("floating.point.number.too.small"); + if (number.isInfinite()) { + final String message = JavaErrorMessages.message("floating.point.number.too.large"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); + } + if (number.doubleValue() == 0 && !isFPZero(text)) { + final String message = JavaErrorMessages.message("floating.point.number.too.small"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, message); + } } return null; @@ -1038,33 +1065,6 @@ public class HighlightUtil { return true; } - private static Collection getLiteralExpressionQuickFixes(final PsiLiteralExpression expression) { - final PsiElement literal = expression.getFirstChild(); - assert literal instanceof PsiJavaToken : literal; - final String text = literal.getText().toLowerCase(); - final IElementType type = ((PsiJavaToken)literal).getTokenType(); - final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(expression); - - if (PsiLiteralExpressionImpl.REAL_LITERALS.contains(type)) { - if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_5) && text.startsWith(PsiLiteralExpressionImpl.HEX_PREFIX)) { - return Collections.singletonList(new IncreaseLanguageLevelFix(LanguageLevel.JDK_1_5)); - } - } - if (PsiLiteralExpressionImpl.NUMERIC_LITERALS.contains(type)) { - if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_7) && (text.startsWith(PsiLiteralExpressionImpl.BIN_PREFIX) || text.contains("_"))) { - return Collections.singletonList(new IncreaseLanguageLevelFix(LanguageLevel.JDK_1_7)); - } - } - if (type == JavaTokenType.CHARACTER_LITERAL) { - if (Boolean.TRUE.equals(literal.getUserData(TOO_BIG_CHAR_LITERAL_KEY))) { - return Collections.singletonList(new ConvertToStringLiteralAction()); - } - } - - return Collections.emptyList(); - } - - @Nullable static HighlightInfo checkMustBeBoolean(@NotNull PsiExpression expr, PsiType type) { PsiElement parent = expr.getParent(); @@ -2525,9 +2525,12 @@ public class HighlightUtil { STATIC_IMPORTS(LanguageLevel.JDK_1_5, "feature.static.imports"), FOR_EACH(LanguageLevel.JDK_1_5, "feature.for.each"), VARARGS(LanguageLevel.JDK_1_5, "feature.varargs"), + HEX_FP_LITERALS(LanguageLevel.JDK_1_5, "feature.hex.fp.literals"), DIAMOND_TYPES(LanguageLevel.JDK_1_7, "feature.diamond.types"), MULTI_CATCH(LanguageLevel.JDK_1_7, "feature.multi.catch"), TRY_WITH_RESOURCES(LanguageLevel.JDK_1_7, "feature.try.with.resources"), + BIN_LITERALS(LanguageLevel.JDK_1_7, "feature.binary.literals"), + UNDERSCORES(LanguageLevel.JDK_1_7, "feature.underscores.in.literals"), EXTENSION_METHODS(LanguageLevel.JDK_1_8, "feature.extension.methods"); private final LanguageLevel level; diff --git a/java/java-psi-impl/src/messages/JavaErrorMessages.properties b/java/java-psi-impl/src/messages/JavaErrorMessages.properties index 8e5226d573fe..51d626aaedbe 100644 --- a/java/java-psi-impl/src/messages/JavaErrorMessages.properties +++ b/java/java-psi-impl/src/messages/JavaErrorMessages.properties @@ -273,9 +273,6 @@ unclosed.char.literal=Unclosed character literal illegal.escape.character.in.string.literal=Illegal escape character in string literal floating.point.number.too.large=Floating point number too large floating.point.number.too.small=Floating point number too small -hex.FP.literals.not.supported=Hexadecimal floating point literals are only supported in JDK 5 or higher -binary.literals.not.supported=Binary literals are only supported in JDK 7 or higher -underscores.in.literals.not.supported=Underscores in literals are only supported in JDK 7 or higher import.statement.identifier.or.asterisk.expected.=Identifier or '*' expected @@ -349,8 +346,11 @@ feature.annotations=Annotations feature.static.imports=Static imports feature.for.each=For-each loops feature.varargs=Variable arity methods +feature.hex.fp.literals=Hexadecimal floating point literals feature.diamond.types=Diamond types feature.multi.catch=Multi-catches feature.try.with.resources=Try-with-resources +feature.binary.literals=Binary literals +feature.underscores.in.literals=Underscores in literals feature.extension.methods=Extension methods insufficient.language.level={0} are not supported at this language level diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/NumericLiterals.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/NumericLiterals.java index d05587836cac..becdda581a2a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/NumericLiterals.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/NumericLiterals.java @@ -1,3 +1,19 @@ +/* + * Copyright 2000-2012 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. + */ + /// assignment compatible types import java.io.*; import java.net.*; @@ -23,9 +39,9 @@ public class a { int i14 = 020000000000; int i15 = 0xf044332211; int octale = 017777777777; // negative - int bi1 = 0b0010; - int bi2 = 0B0010; - int bi3 = 1_2; + int bi1 = 0b0010; + int bi2 = 0B0010; + int bi3 = 1_2; long l1 = -9223372036854775809L; long l2 = 9223372036854775808L; @@ -39,20 +55,20 @@ public class a { long l10 = 0x8000000000000000L; long octalValue = 01777777777777777777600L; long octalValua = 01777777777777777777777L; - long bl1 = 0b0010l; - long bl2 = 0B0010L; - long bl3 = 10_24L; + long bl1 = 0b0010l; + long bl2 = 0B0010L; + long bl3 = 10_24L; float f1= 1e-46f; float f2 = 1e39f; float f3 = 0E1F; - float f4 = 0xabc.defP2f; - float bf1 = 3.141_592f; + float f4 = 0xabc.defP2f; + float bf1 = 3.141_592f; double dd1 = 1e-324; double dd2 = 1e309; double dd3 = 0E1; - double dd4 = 0x1.fffffffffffffP1023; + double dd4 = 0x1.fffffffffffffP1023; double d1 = 1.E; double d2 = 1.e; double d3 = 1.E+; @@ -64,6 +80,6 @@ public class a { double d9 = 1e-d; double d10 = 1e-F; double d11 = 1e-f; - double d12 = 3.141_592_653_589_793d; + double d12 = 3.141_592_653_589_793d; } }