001package daikon.split; 002 003import daikon.Ppt; 004import daikon.PptTopLevel; 005import daikon.ValueTuple; 006import daikon.inv.DummyInvariant; 007import java.io.Serializable; 008import org.checkerframework.checker.initialization.qual.UnknownInitialization; 009import org.checkerframework.checker.interning.qual.UsesObjectEquals; 010import org.checkerframework.checker.nullness.qual.Nullable; 011 012/** 013 * A Splitter represents a test that can be used to separate all samples into two parts. For 014 * instance, a Splitter might represent the condition "x > 0". The Splitter is used to divide a 015 * collection of variable values into sub-sets. Invariant detection can then occur for the two 016 * subsets independently. 017 * 018 * <p>This class Splitter is the superclass for all the classes we dynamically compile; there will 019 * be one subclass for each condition that's checked. Other information about the splitting 020 * condition is kept in a SplitterObject object, which keeps reference to the corresponding 021 * Splitter. One instance of each Splitter subclass is then created for each program point at which 022 * the splitting condition is applicable. 023 */ 024 025// Should not be "implements Serializable": the classes are created on 026// demand, so the class doesn't exist when a serialized object is being 027// re-read. 028@UsesObjectEquals 029public abstract class Splitter implements Serializable { 030 static final long serialVersionUID = 20020122L; 031 032 /** 033 * Creates a splitter "factory" that should only be used for creating new copies via {@link 034 * #instantiateSplitter(Ppt)}. (That is, the result of "new Splitter()" should not do any 035 * splitting itself.) There is no need for subclasses to override this (but most will have to, 036 * since they will add their own constructors as well). 037 */ 038 protected Splitter() {} 039 040 /** 041 * Creates a valid splitter than can be used for testing the condition via test(ValueTuple). The 042 * implementation should always set the "instantiated" protected field to true, if that field is 043 * present in the Splitter class. 044 */ 045 public abstract Splitter instantiateSplitter(@UnknownInitialization(Ppt.class) Ppt ppt); 046 047 /** True for an instantiated (non-"factory") splitter. */ 048 protected boolean instantiated = false; 049 050 /** 051 * Returns true for an instantiated (non-"factory") splitter. Clients also need to check valid(). 052 */ 053 public boolean instantiated() { 054 return instantiated; 055 } 056 057 /** 058 * Returns true or false according to whether this was instantiated correctly and test(ValueTuple) 059 * can be called without error. An alternate design would have {@link #instantiateSplitter(Ppt)} 060 * check this, but it's a bit easier on implementers of subclasses of Splitter for the work to be 061 * done (in just one place) by the caller. 062 */ 063 public abstract boolean valid(); 064 065 /** 066 * Returns true or false according to whether the values in the specified ValueTuple satisfy the 067 * condition represented by this Splitter. Requires that valid() returns true. 068 */ 069 public abstract boolean test(ValueTuple vt); 070 071 // This method could be static; but don't bother making it so. 072 /** Returns the condition being tested, as a String. */ 073 public abstract String condition(); 074 075 /** 076 * Set up the static ('factory') DummyInvariant for this kind of splitter. This only modifies 077 * static data, but it can't be static because subclasses must override it. 078 */ 079 public void makeDummyInvariantFactory(DummyInvariant inv) {} 080 081 /** 082 * Make an instance DummyInvariant for this instance of the splitter, if possible on an 083 * appropriate slice from ppt. 084 */ 085 public void instantiateDummy(PptTopLevel ppt) {} 086 087 /** On an instantiated Splitter, give back an appropriate instantiated DummyInvariant. */ 088 public abstract @Nullable DummyInvariant getDummyInvariant(); 089}