From f0ee218178eb73603cfc82f472d76aac7de75f14 Mon Sep 17 00:00:00 2001 From: Denis Zhdanov Date: Thu, 3 Mar 2011 18:47:54 +0300 Subject: [PATCH] IDEA-66185 Malformed format string inspection: Instruct the inspection that int -> char conversion is correct The inspection is taught to not report int -> char conversion --- .../src/com/siyeh/ig/bugs/FormatDecode.java | 33 +++++++++++++++++-- .../MalformedFormatString.java | 1 + 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/FormatDecode.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/FormatDecode.java index ec750545ffe5..bfbcdb8550f2 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/FormatDecode.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/FormatDecode.java @@ -17,8 +17,12 @@ package com.siyeh.ig.bugs; import com.intellij.psi.CommonClassNames; import com.intellij.psi.PsiType; +import com.intellij.util.containers.ContainerUtil; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -44,6 +48,27 @@ class FormatDecode{ private static final Validator FLOAT_VALIDATOR = new FloatValidator(); + /** + * Holds information about validator replacement rules, i.e. allows to answer if validator of particular type may be + * safely replaced by validator of another particular type. + *

+ * For example, validator of type {@link AllValidator#type() 'all'} may be safely replaced by validator of any other + * type, e.g. {@link DateValidator#type() Date/Time} or {@link CharValidator#type() 'char validator'} may be replaced + * by {@link IntValidator#type() 'int validator'} because {@link Formatter java formatter} knows how to + * {@link Formatter.FormatSpecifier#printCharacter(Object) print character from integer} etc. + *

+ * Generally, current collection holds set of mappings where the key is type of validator that may be safely replaced + * by validator of type that is contained at 'values' collection. + */ + private static final Map> REPLACEABLE_VALIDATOR_TYPES = new HashMap>(); + static { + REPLACEABLE_VALIDATOR_TYPES.put( + ALL_VALIDATOR.type(), + ContainerUtil.set(DATE_VALIDATOR.type(), CHAR_VALIDATOR.type(), INT_VALIDATOR.type(), FLOAT_VALIDATOR.type()) + ); + REPLACEABLE_VALIDATOR_TYPES.put(CHAR_VALIDATOR.type(), ContainerUtil.set(INT_VALIDATOR.type())); + } + public static Validator[] decode(String formatString, int argumentCount){ final ArrayList parameters = new ArrayList(); @@ -108,11 +133,13 @@ class FormatDecode{ int argumentCount){ if(pos < parameters.size()){ final Validator old = parameters.get(pos); + Set replaceableTypes = REPLACEABLE_VALIDATOR_TYPES.get(old.type()); + if (replaceableTypes != null && replaceableTypes.contains(val.type())) { + parameters.set(pos, val); + } // it's OK to overwrite ALL with something more specific // it's OK to ignore overwrite of something else with ALL or itself - if (old == ALL_VALIDATOR) { - parameters.set(pos, val); - } else if (val != ALL_VALIDATOR && val != old) { + else if (val != ALL_VALIDATOR && val != old) { throw new DuplicateFormatFlagsException( "requires both " + old.type() + " and " + val.type()); } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/malformed_format_string/MalformedFormatString.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/malformed_format_string/MalformedFormatString.java index d8b0e830f731..4835464100b7 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/malformed_format_string/MalformedFormatString.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/malformed_format_string/MalformedFormatString.java @@ -21,6 +21,7 @@ public class MalformedFormatString { String warn = String.format("%s %s", 1); // this is invalid according to the inspector (correct) String invalid = String.format("%s %s" + local, 1); // this is valid according to the inspector (INCORRECT!) String interesting = String.format("%s %s" + "hmm", 1); // this is invalid according to the inspector (correct) + String intAsChar = String.format("symbol '%1$c' (numeric value %1$d)", 60); // integer->char conversion is ok (correct) } public void outOfMemory() {