All Downloads are FREE. Search and download functionalities are using the official Maven repository.

checker.src.org.checkerframework.checker.formatter.qual.ConversionCategory Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java’s type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.42.0
Show newest version
package org.checkerframework.checker.formatter.qual;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.checkerframework.dataflow.qual.Pure;

/**
 * Elements of this enumeration are used in a {@link Format Format} annotation
 * to indicate the valid types that may be passed as a format parameter.
 * For example:
 *
 * 
*
{@literal @}Format({ConversionCategory.GENERAL, ConversionCategory.INT})
 * String f = "String '%s' has length %d";
 * String.format(f, "Example", 7);
*
* * The annotation indicates that the format string requires any Object as the * first parameter ({@link ConversionCategory#GENERAL}) and an integer as the * second parameter ({@link ConversionCategory#INT}). * * @see Format * @checker_framework.manual #formatter-checker Format String Checker * @author Konstantin Weitz */ public enum ConversionCategory { /** * Use if the parameter can be of any type. Applicable for conversions b, B, * h, H, s, S. */ GENERAL(null /* everything */, "bBhHsS"), /** * Use if the parameter is of a basic types which represent Unicode * characters: char, Character, byte, Byte, short, and Short. This * conversion may also be applied to the types int and Integer when * Character.isValidCodePoint(int) returns true. Applicable for conversions * c, C. */ CHAR(new Class[] { Character.class, Byte.class, Short.class, Integer.class}, "cC"), /** * Use if the parameter is is an integral type: byte, Byte, short, Short, * int and Integer, long, Long, and BigInteger. Applicable for conversions d, * o, x, X. */ INT(new Class[] { Byte.class, Short.class, Integer.class, Long.class, BigInteger.class }, "doxX"), /** * Use if the parameter is is a floating-point type: float, Float, double, * Double, and BigDecimal. Applicable for conversions e, E, f, g, G, a, A. */ FLOAT(new Class[] { Float.class, Double.class, BigDecimal.class }, "eEfgGaA"), /** * Use if the parameter is is a type which is capable of encoding a date or * time: long, Long, Calendar, and Date. Applicable for conversions t, T. */ TIME(new Class[] { Long.class, Calendar.class, Date.class }, "tT"), /** * In a format string, multiple conversions may be applied to * the same parameter. This is seldomly needed, but the following * is an example of such use: * *
     *   format("Test %1$c %1$d", (int)42);
     * 
* * In this example, the first parameter is interpreted as both * a character and an int, therefore the parameter must be * compatible with both conversion, and can therefore neither be * char nor long. This intersection of conversions is called * CHAR_AND_INT. * * One other conversion intersection * is interesting, namely the intersection of INT and TIME, * resulting in INT_AND_TIME. * * All other intersection either lead to an already existing type, * or NULL, in which case it is illegal to pass object's of any * type as parameter. */ CHAR_AND_INT(new Class[] { Byte.class, Short.class, Integer.class}, null), INT_AND_TIME(new Class[] { Long.class }, null), /** * Use if no object of any type can be passed as parameter. * In this case, the only legal value is null. * This is seldomly needed, and indicates an error in most cases. * For example: * *
     *   format("Test %1$f %1$d", null);
     * 
* * Only null can be legally passed, passing a value such as 4 or 4.2 * would lead to an exception. */ NULL(new Class[0], null), /** * Use if a parameter is not used by the formatter. * This is seldomly needed, and indicates an error in most cases. * For example: * *
     *   format("Test %1$s %3$s", "a","unused","b");
     * 
* * Only the first "a" and third "b" parameters are used, * the second "unused" parameter is ignored. */ UNUSED(null /* everything */, null); ConversionCategory(Class[] types, String chars) { this.types = types; this.chars = chars; } public final Class[] types; public final String chars; /** * Use this function to * get the category associated with a conversion character. For example: * *
*
     * ConversionCategory.fromConversionChar('d') == ConversionCategory.INT;
     * 
*
*/ public static ConversionCategory fromConversionChar(char c) { for (ConversionCategory v : new ConversionCategory[] { GENERAL, CHAR, INT, FLOAT, TIME }) { if (v.chars.contains(String.valueOf(c))) { return v; } } throw new IllegalArgumentException(); } private static Set arrayToSet(E[] a) { return new HashSet(Arrays.asList(a)); } public static boolean isSubsetOf(ConversionCategory a, ConversionCategory b) { return intersect(a, b) == a; } /** * Use this function to get the intersection of two categories. * This is seldomly needed. * *
*
     * ConversionCategory.intersect(INT, TIME) == INT_AND_TIME;
     * 
*
*/ public static ConversionCategory intersect(ConversionCategory a, ConversionCategory b) { if (a == UNUSED) { return b; } if (b == UNUSED) { return a; } if (a == GENERAL) { return b; } if (b == GENERAL) { return a; } Set> as = arrayToSet(a.types); Set> bs = arrayToSet(b.types); as.retainAll(bs); // intersection for (ConversionCategory v : new ConversionCategory[] { CHAR, INT, FLOAT, TIME, CHAR_AND_INT, INT_AND_TIME, NULL }) { Set> vs = arrayToSet(v.types); if (vs.equals(as)) { return v; } } // this should never happen throw new RuntimeException(); } /** * Use this function to get the union of two categories. * This is seldomly needed. * *
*
     * ConversionCategory.union(INT, TIME) == GENERAL;
     * 
*
*/ public static ConversionCategory union(ConversionCategory a, ConversionCategory b) { if (a == UNUSED || b == UNUSED) { return UNUSED; } if (a == GENERAL || b == GENERAL) { return GENERAL; } if ((a == CHAR_AND_INT && b == INT_AND_TIME) || (a == INT_AND_TIME && b == CHAR_AND_INT)) { // This is special-cased because the union of a.types and b.types // does not include BigInteger.class, whereas the types for INT does. // Returning INT here to prevent returning GENERAL below. return INT; } Set> as = arrayToSet(a.types); Set> bs = arrayToSet(b.types); as.addAll(bs); // union for (ConversionCategory v : new ConversionCategory[] { NULL, CHAR_AND_INT, INT_AND_TIME, CHAR, INT, FLOAT, TIME }) { Set> vs = arrayToSet(v.types); if (vs.equals(as)) { return v; } } return GENERAL; } private String className(Class cls) { if (cls == Boolean.class) { return "boolean"; } if (cls == Character.class) { return "char"; } if (cls == Byte.class) { return "byte"; } if (cls == Short.class) { return "short"; } if (cls == Integer.class) { return "int"; } if (cls == Long.class) { return "long"; } if (cls == Float.class) { return "float"; } if (cls == Double.class) { return "double"; } return cls.getSimpleName(); } /** * Returns a pretty printed {@link ConversionCategory}. */ @Pure @Override public String toString() { StringBuilder sb = new StringBuilder(this.name()); sb.append(" conversion category (one of: "); boolean first = true; for (Class cls : this.types) { if (!first) { sb.append(", "); } sb.append(className(cls)); first = false; } sb.append(")"); return sb.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy