001package daikon; 002 003import java.util.logging.Logger; 004import org.checkerframework.checker.lock.qual.GuardSatisfied; 005import org.checkerframework.dataflow.qual.Pure; 006 007// Internally, we use the names "array[]", "array[]-element", and 008// "array[]-indexn". These may be different depending on the programming 009// language; for instance, C uses "*array" in place of "array[]-element". 010 011/** 012 * Represents the comparability of variables, including methods to determine if two 013 * VarComparabilities are comparable. VarComparability types have two formats: implicit and none. 014 * 015 * <p>A VarComparabilityImplicit is an arbitrary string, and comparisons succeed exactly if the two 016 * VarComparabilitys are identical. 017 * 018 * <p>VarComparabilityNone means no comparability information was provided. 019 */ 020public abstract class VarComparability { 021 022 /** Debug tracer. */ 023 public static final Logger debug = Logger.getLogger("daikon.VarComparability"); 024 025 public static final int NONE = 0; 026 public static final int IMPLICIT = 1; 027 028 /** 029 * Create a VarComparability representing the given arguments with respect to a variable. 030 * 031 * @param format the type of comparability, either NONE or IMPLICIT 032 * @param rep a regular expression indicating how to match. The form is "(a)[b][c]..." where each 033 * variable is string (or number) that is a UID for a basic type. a is the type of the 034 * element, b is the type of the first index, c the type of the second, etc. Index variables 035 * only apply if this is an array. 036 * @param vartype the declared type of the variable 037 */ 038 public static VarComparability parse(int format, String rep, ProglangType vartype) { 039 if (format == NONE) { 040 return VarComparabilityNone.parse(rep, vartype); 041 } else if (format == IMPLICIT) { 042 return VarComparabilityImplicit.parse(rep, vartype); 043 } else { 044 throw new IllegalArgumentException( 045 "bad format argument " + format + " should have been in {0, 1, 2}"); 046 } 047 } 048 049 /** 050 * Create a VarComparability based on comparabilities of indices. 051 * 052 * @return a new comparability that is an array with the same dimensionality and indices as given, 053 * but with a different element type 054 * @param elemTypeName the new type of the elements of return value 055 * @param old the varcomparability that this is derived from; has the same indices as this 056 */ 057 public static VarComparability makeComparabilitySameIndices( 058 String elemTypeName, VarComparability old) { 059 if (old instanceof VarComparabilityNone) { 060 return VarComparabilityNone.it; 061 } else { 062 throw new Error("makeComparabilitySameIndices not implemented for implicit comparables"); 063 } 064 } 065 066 public static VarComparability makeAlias(VarInfo vi) { 067 return vi.comparability.makeAlias(); 068 } 069 070 public abstract VarComparability makeAlias(); 071 072 public abstract VarComparability elementType(@GuardSatisfied VarComparability this); 073 074 public abstract VarComparability indexType(@GuardSatisfied VarComparability this, int dim); 075 076 /** Return the comparability for the length of this string* */ 077 public abstract VarComparability string_length_type(); 078 079 /** Returns true if this is comparable to everything else. */ 080 public abstract boolean alwaysComparable(@GuardSatisfied VarComparability this); 081 082 /** Returns whether two variables are comparable. */ 083 @Pure 084 public static boolean comparable(VarInfo v1, VarInfo v2) { 085 return comparable(v1.comparability, v2.comparability); 086 } 087 088 /** Returns whether two comparabilities are comparable. */ 089 @SuppressWarnings("all:purity") // Override the purity checker 090 @Pure 091 public static boolean comparable( 092 @GuardSatisfied VarComparability type1, @GuardSatisfied VarComparability type2) { 093 094 if (type1 != null && type2 != null && type1.getClass() != type2.getClass()) { 095 throw new Error( 096 String.format( 097 "Trying to compare VarComparabilities of different types: %s (%s) and %s (%s)", 098 type1.toString(), type1.getClass(), type2.toString(), type2.getClass())); 099 } 100 101 if (type1 instanceof VarComparabilityNone || type1 == null || type2 == null) { 102 return VarComparabilityNone.comparable( 103 (VarComparabilityNone) type1, (VarComparabilityNone) type2); 104 } else if (type1 instanceof VarComparabilityImplicit) { 105 return VarComparabilityImplicit.comparable( 106 (VarComparabilityImplicit) type1, (VarComparabilityImplicit) type2); 107 } else { 108 throw new Error("Unrecognized subtype of VarComparability: " + type1); 109 } 110 } 111 112 /** 113 * In general, if two items are comparable, they can be placed in the same equality set. This is 114 * not always true for some comparabilities (because they are not always transitive). They can 115 * override this method to provide the correct results. 116 */ 117 public boolean equality_set_ok( 118 @GuardSatisfied VarComparability this, @GuardSatisfied VarComparability other) { 119 return comparable(this, other); 120 } 121}