public static ISymbolIdWithType[] Collect(TermManager termManager, Term term, SafeDictionary <Field, FieldValueHolder> fieldValues, SafeList <Field> fields, SafeList <TypeEx> allFieldTypes) { using (var collector = new VariablesCollector(termManager, fieldValues, fields, allFieldTypes)) { collector.VisitTerm(default(TVoid), term); return(collector.variables.ToArray()); } }
/// <summary> /// simplifies the term based on the contents of the term. all /// </summary> /// <param name="host"></param> /// <param name="termManager"></param> /// <param name="condition"></param> /// <param name="binOp"></param> private static Term SimplifyTerm(IPexExplorationComponent host, TermManager termManager, Term condition) { Term left, right; BinaryOperator binOp; if (!termManager.TryGetBinary(condition, out binOp, out left, out right)) { return(condition); } if (!IsInteger(termManager, left) || !IsInteger(termManager, right)) { return(condition); } //Check whether the term is of the form x > 20, where one side is a constant. then no simplification needs to be done if (termManager.IsValue(left)) { //one side is constant. so just return over here return(condition); } if (termManager.IsValue(right)) { //one side is constant. so just return over here return(condition); } //none of the sides are concrete. both sides are symbolic. //find out which side can be more controlled based on the variables //contained on that side SafeList <Field> allFieldsInLeftCondition = new SafeList <Field>(); SafeList <TypeEx> allFieldTypes = new SafeList <TypeEx>(); SafeDictionary <Field, FieldValueHolder> leftfields = new SafeDictionary <Field, FieldValueHolder>(); VariablesCollector.Collect(termManager, left, leftfields, allFieldsInLeftCondition, allFieldTypes); //TODO: How to get the concrete value of the other side, could be either left //or right. and make a term out of the concrete value int lvalue; if (termManager.TryGetI4Constant(left, out lvalue)) { } int rvalue; if (termManager.TryGetI4Constant(right, out rvalue)) { } return(condition); }
/// <summary> /// Solves a term and computes the actual and expected values of fields. There are various possibilites of the term. The actual /// fiels in a condition, returned by this function should be only from one side. /// /// a. One side of the term is concrete and not symbolic. It is easy to handle this case as one side is concrete /// b. Both the sides are symbolic. Pex assigns different values to both the sides, since both are symbolic, but this is not possible /// in the context of ours. So, we treat one side as a concrete and other side as symbolic. We use heuristics in deciding which /// side is concrete and which side is symbolic. /// </summary> /// <param name="host"></param> /// <param name="condition"></param> /// <param name="binOp"></param> /// <param name="actualFieldValues"></param> /// <param name="expectedFieldValues"></param> /// <param name="allFieldsInCondition"></param> /// <returns></returns> public static bool SolveTerm(IPexExplorationComponent host, Term condition, BinaryOperator binOp, out SafeDictionary <Field, FieldValueHolder> actualFieldValues, out SafeDictionary <Field, FieldValueHolder> expectedFieldValues, out SafeList <Field> allFieldsInCondition, out SafeList <TypeEx> allFieldTypes) { var termManager = host.ExplorationServices.TermManager; var solverFactory = host.ExplorationServices.SolverFactory; var solverStatistics = solverFactory.CreateStatistics(); actualFieldValues = new SafeDictionary <Field, FieldValueHolder>(); expectedFieldValues = new SafeDictionary <Field, FieldValueHolder>(); allFieldTypes = new SafeList <TypeEx>(); //Simplifies term based on the contents within the term. gathering a simplied form of condition condition = SimplifyTerm(host, termManager, condition); allFieldsInCondition = new SafeList <Field>(); var variables = VariablesCollector.Collect(termManager, condition, actualFieldValues, allFieldsInCondition, allFieldTypes); using (var solver = solverFactory.CreateSolver(solverStatistics)) { var writer = new SafeStringWriter(); foreach (var symbolIdWithType in variables) { writer.WriteLine("variable: {0}", symbolIdWithType.Description); solver.AddDomainVariable(0, symbolIdWithType); } writer.WriteLine("condition: {0}", prettyPrintTerm(host, condition, SystemTypes.Bool)); solver.Assert("is satisfiable check", condition); IModel model; var result = solver.TryGetModel(null, out model); writer.WriteLine("TryGetModel => {0}", result); if (result == TryGetModelResult.Success) { foreach (var symbolIdWithType in variables) { writer.Write("{0} => ", symbolIdWithType.Description); var variable = termManager.Symbol(symbolIdWithType); var value = model.GetValue(variable); writer.WriteLine(prettyPrintTerm(host, value, symbolIdWithType.Type)); TypeEx type; if (symbolIdWithType.Layout.Kind == LayoutKind.Ref && termManager.TryGetObjectType(value, out type) && type != SystemTypes.Null) { foreach (var field in type.InstanceFields) { var fieldVariable = termManager.SelectInstanceFieldInInitialState(variable, field); var fieldValue = model.GetValue(fieldVariable); writer.Write("{0}.{1} => ", symbolIdWithType.Description, field.ShortName); writer.WriteLine(prettyPrintTerm(host, fieldValue, field.Type)); TypeEx fieldValueType; if (termManager.TryGetObjectType(fieldValue, out fieldValueType)) // is this an object, and if so, what’s its type? { // do the same thing are before for the nested fields foreach (var nestedField in field.Type.InstanceFields) { var nestedFieldVariable = termManager.SelectInstanceFieldInInitialState(fieldValue, nestedField); var nestedFieldValue = model.GetValue(nestedFieldVariable); writer.Write("{0}.{1}.{2} => ", symbolIdWithType.Description, field.ShortName, nestedField.ShortName); writer.WriteLine(prettyPrintTerm(host, nestedFieldValue, nestedField.Type)); } } //stores the field value into expected field values StoreFieldValue(termManager, field, fieldValue, expectedFieldValues, actualFieldValues, allFieldsInCondition, host, condition, binOp); } } } } if (model != null) { model.Dispose(); } host.Log.Dump("Satisfiable Checker", "TermSolver", writer.ToString()); } return(true); }