/// <summary> /// Retrieves the defined field /// </summary> /// <param name="method"></param> /// <param name="definedField"></param> /// <returns></returns> public static bool TryGetFieldOfSetter(Method method, out Field definedField) { SafeDebug.Assert(method.ShortName.StartsWith("set_"), ""); definedField = null; MethodBodyEx body; if (!method.TryGetBody(out body) || !body.HasInstructions) { return(false); } int offset = 0; Instruction instruction; OpCode prevOpcode = OpCodes.Nop; while (body.TryGetInstruction(offset, out instruction)) { SafeDebug.AssumeNotNull(instruction, "instruction"); OpCode opCode = instruction.OpCode; if (opCode == OpCodes.Stfld || opCode == OpCodes.Stsfld) { definedField = instruction.Field; return(true); } offset = instruction.NextOffset; } return(false); }
bool IPexAssumptionExceptionValidator.IsAssumption(Exception ex) { SafeDebug.AssumeNotNull(ex, "ex"); // 1) must be a requires exception string trace; Type exceptionType = ex.GetType(); if (exceptionType == typeof(Cobra.Lang.RequireException) && ExceptionHelper.TryGetBestStackTrace(ex, out trace)) { StackTraceEx tx = host.Services.SymbolManager.ParseStackTrace(trace, true); bool globalsFound = false; for (int i = tx.Frames.Count - 1; i >= 0; i--) { StackFrameEx frame = tx.Frames[i]; if (frame.MethodName.StartsWith("require_")) { if (globalsFound) // already found? that's not good { return(false); } globalsFound = true; } } return(globalsFound); } return(false); }
public bool IsAssertMethod(MethodDefinition method, out int usefulParameters) { SafeDebug.AssumeNotNull(method, "method"); TypeDefinition type; if (method.TryGetDeclaringType(out type)) { if (type.SerializableName == MSTestv2TestFrameworkMetadata.AssertTypeDefinition) { switch (method.ShortName) { case "IsFalse": case "IsTrue": case "IsNull": case "IsNotNull": case "IsInstanceOfType": case "IsNotInstanceOfType": usefulParameters = 1; return(true); case "AreEqual": case "AreNotEqual": case "AreSame": case "AreNotSame": usefulParameters = 2; return(true); } } } usefulParameters = -1; return(false); }
/// <summary> /// Given a uncovered code location and the associated terms, this /// method infers factory method for that code location. /// /// Assumes that the uncovered branch is mainly due to an object creating issue /// </summary> /// <returns></returns> public bool TryInferFactoryMethod(UncoveredCodeLocationStore ucls, out SafeSet <Method> suggestedMethods) { SafeDebug.AssumeNotNull(ucls, "ucls"); if (ucls.AllFields.Count == 0) { this.host.Log.LogError(WikiTopics.MissingWikiTopic, "factoryguesser", "No information about involving fields in the uncovered branch"); suggestedMethods = null; return(false); } //Check whether the feature is currently supported FieldModificationType fmt = this.GetRequiredFieldModificationType(ucls); if (!(fmt == FieldModificationType.NON_NULL_SET || fmt == FieldModificationType.NULL_SET || fmt == FieldModificationType.INCREMENT || fmt == FieldModificationType.DECREMENT || fmt == FieldModificationType.FALSE_SET || fmt == FieldModificationType.TRUE_SET)) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "factoryguesser", "Format " + fmt.ToString() + " is not supported for suggesting factory methods"); suggestedMethods = null; return(false); } //Step 1: Get the exact type whose factory method is required for covering this branch. //Decided based on where there is a subsequent field which can be directly handled rather than the top field. //This step is moved to the place where the uncovered location is initially stored //Step 2: Decide which methods of this type should be invoked. Use a bottomup approach //for inferrinfg the exact method if (!this.GetTargetMethod(ucls, ucls.TargetField, out suggestedMethods)) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "factoryguesser", "Failed to retrieve the target method of field " + ucls.TargetField.FullName + " in type " + ucls.ExplorableType.FullName); suggestedMethods = null; return(false); } var sb = new StringBuilder(); foreach (var m in suggestedMethods) { sb.AppendLine(MethodOrFieldAnalyzer.GetMethodSignature(m)); } ucls.SuggestedMethodsforFactory = sb.ToString(); //Create a factory suggestion store. This is expected by the rest of the code. FactorySuggestionStore fss; if (!this.pmd.FactorySuggestionsDictionary.TryGetValue(ucls.ExplorableType.ToString(), out fss)) { fss = new FactorySuggestionStore(); fss.DeclaringType = ucls.ExplorableType.ToString(); this.pmd.FactorySuggestionsDictionary[ucls.ExplorableType.ToString()] = fss; } return(true); }
/// <inheritdoc/> public override void EmitInconclusive(MethodBodyBuilder body, string message) { SafeDebug.AssumeNotNull(body, "body"); body.Push(message); body.CallStatic(XunitTestFrameworkMetadata.Method_PexAssertInconclusive.Value); body.Statement(); }
/// <summary> /// Tries the get categories. /// </summary> /// <param name="element"> /// The element. /// </param> /// <param name="names"> /// The names. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> protected override bool TryGetCategories(ICustomAttributeProviderEx element, out IEnumerable <string> names) { SafeDebug.AssumeNotNull(element, "element"); // TODO names = null; return(false); }
public override bool TryMarkExpectedException(VisibilityContext visibility, MethodDefinitionBuilder method, Exception exception) { SafeDebug.AssumeNotNull(visibility, "visibility"); SafeDebug.AssumeNotNull(method, "method"); SafeDebug.AssumeNotNull(exception, "exception"); return(false); }
/// <inheritdoc/> public override void MarkTestMethod(PexExplorationBase exploration, IPexGeneratedTest test, MethodDefinitionBuilder method) { SafeDebug.AssumeNotNull(test, "test"); SafeDebug.AssumeNotNull(method, "method"); method.CustomAttributes.Add(new CustomAttributeBuilder(XunitTestFrameworkMetadata.Ctor_FactAttribute)); }
protected override object BeforeExploration <TAbstractValue>(IPexExplorationComponent <TAbstractValue> host) { SafeDebug.AssumeNotNull(host, "host"); host.ExplorationServices.ExceptionManager.AddAssumptionExceptionValidator( new Validator <TAbstractValue>(host) ); return(null); }
/// <inheritdoc/> public override bool IsFixture(TypeDefinition target) { SafeDebug.AssumeNotNull(target, "target"); return(!target.IsInterface && !target.IsEnumType && !target.IsAbstract && target.DeclaredVisibility == Visibility.Public && target.IsExported && target.GenericTypeParametersCount == 0); }
/// <inheritdoc/> public override bool TryMarkOwner(MethodDefinitionBuilder method, string owner) { SafeDebug.AssumeNotNull(method, "method"); SafeDebug.AssumeNotNull(owner, "owner"); method.CustomAttributes.Add(new CustomAttributeBuilder(XunitTestFrameworkMetadata.Ctor_TraitAttribute, MetadataExpression.String("Owner"), MetadataExpression.String(owner))); return(true); }
/// <summary> /// Analyzes the given assembly statically and gathers all declared entities /// such as member variables and local variables /// </summary> /// <param name="assembly"></param> public static void CollectAllDeclEntitiesInAssembly(AssemblyEx assembly) { SafeDebug.AssumeNotNull(assembly, "assembly"); logger.Debug("Beginning of static analysis"); if (ade == null) { ade = DUCoverStore.GetInstance(); } foreach (TypeDefinition td in assembly.TypeDefinitions) { CollectAllDeclEntitiesInTypeDef(td); } }
public OrderedMethodEffects(IPexComponent host, Method method) { SafeDebug.AssumeNotNull(method, "method"); this.Method = method; TypeEx declaringType; if (!method.TryGetDeclaringType(out declaringType)) { //TODO: error } MethodOrFieldAnalyzer.TryComputeMethodEffects(host, declaringType, method, null, out this.Effects); }
public MethodEffects(IFiniteSet <Field> writtenInstanceFields, IFiniteSet <Field> directSetFields, IFiniteSet <Method> directCalledMethods, IFiniteSet <Field> returnFields, SafeDictionary <Field, FieldModificationType> modificationTypeDic, int callDepth) { SafeDebug.AssumeNotNull(writtenInstanceFields, "writtenInstanceFields"); SafeDebug.Assume(callDepth >= 0, "callDepth>=0"); this.WrittenInstanceFields = writtenInstanceFields; this.DirectSetterFields = directSetFields; this.DirectCalledMethods = directCalledMethods; this.ReturnFields = returnFields; this.ModificationTypeDictionary = modificationTypeDic; this.CallDepth = callDepth; }
/// <inheritdoc/> public override void MarkIgnored(MethodDefinitionBuilder method, string message) { SafeDebug.AssumeNotNull(method, "method"); var fact = method.CustomAttributes .Cast <CustomAttributeBuilder>() .FirstOrDefault(a => a.Constructor.SerializableName == XunitTestFrameworkMetadata.Ctor_FactAttribute); if (fact != null) { fact.AddNamedArgument(XunitTestFrameworkMetadata.Property_Skip, MetadataExpression.String(message)); return; } SafeDebug.FailUnreachable(); }
public bool IsAssertMethod(MethodDefinition method, out int usefulParameters) { SafeDebug.AssumeNotNull(method, "method"); TypeDefinition type; if (method.TryGetDeclaringType(out type) && type.SerializableName == XunitTestFrameworkMetadata.Type_Assert.Definition) { if (parameterCount.TryGetValue(method.ShortName, out usefulParameters)) { return(true); } } usefulParameters = -1; return(false); }
internal SafeSet <Method> FilterCallingMethodsBasedOnField(Method tmw, Field field, SafeSet <Method> callingMethods) { SafeSet <Method> filteredMethods = new SafeSet <Method>(); foreach (var callingm in callingMethods) { //Filter the calling method based on the field MethodBodyEx body; if (!callingm.TryGetBody(out body) || !body.HasInstructions) { continue; } int offset = 0; Instruction instruction; bool bContinueWithNextMethod = false; Field lastAccessedField = null; while (body.TryGetInstruction(offset, out instruction) && !bContinueWithNextMethod) { SafeDebug.AssumeNotNull(instruction, "instruction"); OpCode opCode = instruction.OpCode; if (opCode == OpCodes.Ldfld || opCode == OpCodes.Ldflda) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineField, "opCode.OperandType == OperandType.InlineField"); lastAccessedField = instruction.Field; } else if (opCode == OpCodes.Call || opCode == OpCodes.Callvirt) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineMethod, "opCode.OperandType == OperandType.InlineMethod"); Method methodinner = instruction.Method; if (methodinner == tmw && field == lastAccessedField) { filteredMethods.Add(callingm); bContinueWithNextMethod = true; } lastAccessedField = null; } offset = instruction.NextOffset; } } return(filteredMethods); }
/// <summary> /// Accepts a field and returns the persistent string form "assemblyname#typename#fieldname" of the field. /// </summary> /// <param name="method"></param> /// <returns></returns> public static string GetPersistentStringFormOfField(Field f) { var assemblyname = f.Definition.Module.Assembly.Location; string typename; TypeDefinition typedef = null; if (!f.Definition.TryGetDeclaringType(out typedef)) { SafeDebug.AssumeNotNull(typedef, "Type definition is empty"); typename = PexMeConstants.PexMeDummyTypeName; } else { typename = typedef.FullName; } return(assemblyname + PexMeConstants.PexMePersistenceFormSeparator + typename + PexMeConstants.PexMePersistenceFormSeparator + f.FullName); }
/// <summary> /// Accepts a method and returns the persistent string form "assemblyname#typename#methodsignature" of the method. /// </summary> /// <param name="method"></param> /// <returns></returns> public static string GetPersistentStringFormOfMethod(Method m) { var assemblyname = m.Definition.Module.Assembly.Location; string typename; TypeDefinition typedef = null; if (!m.Definition.TryGetDeclaringType(out typedef)) { SafeDebug.AssumeNotNull(typedef, "Type definition is empty"); typename = PexMeConstants.PexMeDummyTypeName; } else { typename = typedef.FullName; } var signature = MethodOrFieldAnalyzer.GetMethodSignature(m); return(assemblyname + PexMeConstants.PexMePersistenceFormSeparator + typename + PexMeConstants.PexMePersistenceFormSeparator + signature); }
/// <inheritdoc/> public override bool IsTestIgnored(TestFrameworkTestSelection testSelection, MethodDefinition method, out string ignoreMessage) { SafeDebug.AssumeNotNull(testSelection, "testSelection"); SafeDebug.AssumeNotNull(method, "method"); var fact = method.DeclaredAttributes .FirstOrDefault(a => a.Constructor.SerializableName == XunitTestFrameworkMetadata.Ctor_FactAttribute); if (fact != null) { var skip = fact.NamedArguments.FirstOrDefault(na => na.Name == "Skip"); if (skip != null) { ignoreMessage = ((MetadataExpression.StringExpression)skip.Value).Value; return(true); } } ignoreMessage = null; return(false); }
/// <summary> /// Populates all vertices /// </summary> /// <param name="method"></param> private void PopulateVertices(Method method) { MethodBodyEx body; if (!method.TryGetBody(out body) || !body.HasInstructions) { return; } int offset = 0; Instruction instruction; while (body.TryGetInstruction(offset, out instruction)) { SafeDebug.AssumeNotNull(instruction, "instruction"); OpCode opCode = instruction.OpCode; InstructionVertex iv = this.AddVertex(instruction); this.vertices[offset] = iv; offset = instruction.NextOffset; } }
/// <summary> /// Returns a method call for a PUT. This should be of certain characteristics, /// It should contain only one method call as generated by us /// </summary> /// <param name="putmethod"></param> /// <returns></returns> public static bool TryRetrieveMethodCall(Method putmethod, out Method assocmethod) { SafeDebug.AssumeNotNull(putmethod, "putmethod"); assocmethod = null; MethodBodyEx mbodyex; bool bresult = putmethod.TryGetBody(out mbodyex); SafeDebug.Assert(bresult, "Failed to get the body"); int offset = 0; Instruction instruction; List <Method> allCalledMethods = new List <Method>(); while (mbodyex.TryGetInstruction(offset, out instruction)) { SafeDebug.AssumeNotNull(instruction, "instruction"); OpCode opCode = instruction.OpCode; if (opCode == OpCodes.Call || opCode == OpCodes.Callvirt) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineMethod, "opCode.OperandType == OperandType.InlineMethod"); allCalledMethods.Add(instruction.Method); } offset = instruction.NextOffset; } if (allCalledMethods.Count != 1) { return(false); } assocmethod = allCalledMethods[0]; return(true); }
public static TypeEx AddFieldToMethodEffects(IPexComponent host, TypeEx declaringType, SafeSet <string> res, SafeSet <string> directSetFields, SafeDictionary <string, FieldModificationType> modificationTypeDic, OpCode prevOpcode, Field field, TypeEx fieldType) { SafeDebug.AssumeNotNull(field, "field"); SafeDebug.Assume(!field.IsStatic, "!field.IsStatic"); TypeEx fieldDeclaringType; //The following check ensures that the field belongs to this class //or its base classes if (field.TryGetDeclaringType(out fieldDeclaringType) && declaringType.IsAssignableTo(fieldDeclaringType)) { res.Add(field.ShortName); FieldModificationType fmt = FieldModificationType.UNKNOWN; if (fieldType == SystemTypes.Int32 || fieldType == SystemTypes.Int64 || fieldType == SystemTypes.Int16) { if (prevOpcode == OpCodes.Add) { fmt = FieldModificationType.INCREMENT; } else if (prevOpcode == OpCodes.Sub) { fmt = FieldModificationType.DECREMENT; } else if (prevOpcode == OpCodes.Call || prevOpcode == OpCodes.Calli || prevOpcode == OpCodes.Callvirt) { fmt = FieldModificationType.METHOD_CALL; } else { host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype", "Encountered unknown modification type for integer type " + prevOpcode); } } else { if (field.Type.IsReferenceType) { if (prevOpcode == OpCodes.Ldnull) { fmt = FieldModificationType.NULL_SET; } else if (prevOpcode == OpCodes.Newarr || prevOpcode == OpCodes.Newobj) { fmt = FieldModificationType.NON_NULL_SET; } else if (LdArgOpCodes.Contains(prevOpcode)) { fmt = FieldModificationType.NON_NULL_SET; } else { fmt = FieldModificationType.METHOD_CALL; //A method call is invoked on this field, which updates this field } } else if (fieldType == SystemTypes.Bool) { if (prevOpcode == OpCodes.Ldc_I4_0) { fmt = FieldModificationType.FALSE_SET; } else if (prevOpcode == OpCodes.Ldc_I4_1) { fmt = FieldModificationType.TRUE_SET; } else { host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype", "Encountered unknown modification type for boolean type " + prevOpcode); } } } //Store the value of fmt. Sometimes, the same field //can be modified in different ways within the method, for example //setting a boolean field to both true or false. In that case, the modification //type is left as unknown FieldModificationType prevFMT; if (modificationTypeDic.TryGetValue(field.ShortName, out prevFMT)) { //There is some entry for this field if (prevFMT != FieldModificationType.UNKNOWN && prevFMT != fmt) { modificationTypeDic[field.ShortName] = FieldModificationType.UNKNOWN; } } else { modificationTypeDic[field.ShortName] = fmt; } //A heuristic based approach for aliasing analysis for checking whether the field is directly //assigned any parameters if (LdArgOpCodes.Contains(prevOpcode)) { directSetFields.Add(field.ShortName); } } return(fieldDeclaringType); }
/// <summary> /// Computes method effects statically. All written fields of a method. /// Can be imprecise and conservative /// </summary> /// <param name="declaringType"></param> /// <param name="method"></param> /// <param name="effects"></param> /// <returns></returns> public static bool TryComputeMethodEffects(IPexComponent host, TypeEx declaringType, Method method, SafeSet <Method> visitedMethods, out MethodEffects effects) { SafeDebug.AssumeNotNull(declaringType, "declaringType"); SafeDebug.AssumeNotNull(method, "method"); try { if (visitedMethods == null) { visitedMethods = new SafeSet <Method>(); } if (visitedMethods.Contains(method)) { effects = null; return(false); } visitedMethods.Add(method); //Check whether this has been computed before var psd = host.GetService <IPexMeStaticDatabase>() as PexMeStaticDatabase; if (psd.MethodEffectsDic.TryGetValue(method.GlobalIndex, out effects)) { return(true); } var res = new SafeSet <string>(); var directSetFields = new SafeSet <string>(); var directCalledMethods = new SafeSet <Method>(); var returnFields = new SafeSet <Field>(); var modificationTypeDic = new SafeDictionary <string, FieldModificationType>(); var parameters = method.Parameters; MethodBodyEx body; if (!method.TryGetBody(out body) || !body.HasInstructions) { effects = null; return(false); } int callDepth = 0; int offset = 0; Instruction instruction; OpCode prevOpcode = OpCodes.Nop; //Stack for load instructions Field lastAccessedArrayField = null; Field lastAccessedField = null; while (body.TryGetInstruction(offset, out instruction)) { SafeDebug.AssumeNotNull(instruction, "instruction"); OpCode opCode = instruction.OpCode; if (LdcOpCodes.Contains(opCode)) { //topIsConstant = true; } else if (ConvOpCodes.Contains(opCode)) { // do not change topIsConstant } else { if (opCode == OpCodes.Stfld) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineField, "opCode.OperandType == OperandType.InlineField"); Field field = instruction.Field; AddFieldToMethodEffects(host, declaringType, res, directSetFields, modificationTypeDic, prevOpcode, field, field.Type); } else if (opCode == OpCodes.Ldfld || opCode == OpCodes.Ldflda) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineField, "opCode.OperandType == OperandType.InlineField"); Field accessedField = instruction.Field; if (accessedField.Type.Spec == TypeSpec.SzArray) { lastAccessedArrayField = accessedField; } else { lastAccessedField = accessedField; } } else if (StElemOpCodes.Contains(opCode)) { if (lastAccessedArrayField != null) { //Indicates that there is n array type modified AddFieldToMethodEffects(host, declaringType, res, directSetFields, modificationTypeDic, prevOpcode, lastAccessedArrayField, lastAccessedArrayField.Type); lastAccessedArrayField = null; } } else if (opCode == OpCodes.Call || opCode == OpCodes.Callvirt) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineMethod, "opCode.OperandType == OperandType.InlineMethod"); Method methodinner = instruction.Method; SafeDebug.AssumeNotNull(method, "method"); directCalledMethods.Add(methodinner); TypeEx methodDeclaringType; //are these function calls are within the parent types if (methodinner.TryGetDeclaringType(out methodDeclaringType) && declaringType.IsAssignableTo(methodDeclaringType)) { MethodEffects methodEffects; if (TryComputeMethodEffects(host, methodDeclaringType, methodinner, visitedMethods, out methodEffects)) { res.AddRange(methodEffects.WrittenInstanceFields); foreach (var key in methodEffects.ModificationTypeDictionary.Keys) { modificationTypeDic[key] = methodEffects.ModificationTypeDictionary[key]; } directSetFields.AddRange(methodEffects.DirectSetterFields); if (methodEffects.CallDepth > callDepth) { callDepth = methodEffects.CallDepth; } } } else { //introducing heuristics for inter-procedural static analysis if (lastAccessedField != null && lastAccessedField.Type.IsReferenceType && !(methodinner.ShortName.StartsWith("Get") || methodinner.ShortName.StartsWith("get") || methodinner.ShortName.StartsWith("Set") || methodinner.ShortName.StartsWith("set"))) { AddFieldToMethodEffects(host, declaringType, res, directSetFields, modificationTypeDic, prevOpcode, lastAccessedField, lastAccessedField.Type); } } } else if (opCode == OpCodes.Ret) { if (instruction.Field != null) { returnFields.Add(instruction.Field); } } //topIsConstant = false; } prevOpcode = opCode; offset = instruction.NextOffset; } effects = new MethodEffects((IFiniteSet <string>)res, directSetFields, directCalledMethods, returnFields, modificationTypeDic, callDepth + 1); psd.MethodEffectsDic[method.GlobalIndex] = effects; return(true); } catch (Exception ex) { host.Log.LogErrorFromException(ex, WikiTopics.MissingWikiTopic, "methodeffects", "Failed to compute method effects for method " + method.FullName + "," + ex.Message); effects = null; return(false); } }
/// <summary> /// Tries to get the assembly set up tear down attribute. /// </summary> /// <param name="assembly">The assembly.</param> /// <param name="setUp">The set up.</param> /// <param name="tearDown">The tear down.</param> /// <returns>True if found.</returns> public override bool TryGetAssemblySetupTeardownMethods( AssemblyEx assembly, out Method setUp, out Method tearDown) { // <preconditions> SafeDebug.AssumeNotNull((object)assembly, "assembly"); // </preconditions> setUp = tearDown = null; // look for [TestClass] types foreach (var typeDefinition in assembly.TypeDefinitions) { if (typeDefinition.IsVisible(VisibilityContext.Exported)) { if (typeDefinition.IsEnumType || typeDefinition.GenericTypeParameters.Length > 0) { continue; } if (!this.IsFixture(typeDefinition)) { continue; } // looking for assembly setup/teardown methods foreach (var methodDefinition in typeDefinition.DeclaredStaticMethods) { if (methodDefinition.IsVisible(VisibilityContext.Exported) && methodDefinition.GenericMethodParameters.Length == 0) { if (AttributeHelper.IsDefined(methodDefinition, this.AssemblySetUpAttribute, true)) { setUp = methodDefinition.Instantiate(TypeEx.NoTypes, TypeEx.NoTypes); } if (AttributeHelper.IsDefined(methodDefinition, this.AssemblyTearDownAttribute, true)) { tearDown = methodDefinition.Instantiate(TypeEx.NoTypes, TypeEx.NoTypes); } // nothing else to look for if (setUp != null && tearDown != null) { break; } } } // nothing else to look for if (setUp != null && tearDown != null) { break; } } } return(setUp != null || tearDown != null); }
/// <summary> /// Initializes a new instance /// </summary> /// <param name="host">The host.</param> protected ComponentElementBase(IChessCopComponent host) { SafeDebug.AssumeNotNull(host, "host"); this._host = host; }
/// <summary> /// Removes the uncovered location store. Mainly keeps the sequence /// that helped to cover the target location and drops all others /// </summary> /// <param name="pucls"></param> /// <param name="successful">Helps to distinguish between a removal during success and failure</param> internal void RemoveUncoveredLocationStore(PersistentUncoveredLocationStore pucls, bool successful, PexMeDynamicDatabase pmd) { var key = UncoveredCodeLocationStore.GetKey(pucls.CodeLocation, pucls.ExplorableType, pucls.TermIndex); this.locationStoreSpecificSequences.Remove(key); if (!successful) { return; } this.SuccessfulCoveredLocations.Add(key); this.PermanentFailedUncoveredLocations.Remove(key); this.TemporaryFailedUncoveredLocations.Remove(key); this.UncoveredSystemLibLocations.Remove(key); //Get the method associated with the current exploring PUT string methodcallname = PexMeConstants.DEFAULT_FINAL_SUGGESTION_STORE; Method assocMethod; if (PUTGenerator.PUTGenerator.TryRetrieveMethodCall(pmd.CurrentPUTMethod, out assocMethod)) { methodcallname = MethodOrFieldAnalyzer.GetMethodSignature(assocMethod); } //Get PUT independent sequence list MethodSignatureSequenceList putIndependentMssl; if (!this.FinalSuggestedMethodSequences.TryGetValue(methodcallname, out putIndependentMssl)) { putIndependentMssl = new MethodSignatureSequenceList(); this.FinalSuggestedMethodSequences.Add(methodcallname, putIndependentMssl); } //Also update the PUT specific sequences. These gets cleared once a //PUT is completely explored. var putsignature = MethodOrFieldAnalyzer.GetMethodSignature(pmd.CurrentPUTMethod); MethodSignatureSequenceList putSpecificMssl; if (!this.FinalPUTSequences.TryGetValue(putsignature, out putSpecificMssl)) { putSpecificMssl = new MethodSignatureSequenceList(); this.FinalPUTSequences.Add(putsignature, putSpecificMssl); } //Any Persistent Uncovered location store that is successfully //covered gets a hit sequence SafeDebug.AssumeNotNull(pucls.HitSequence, "pucls.HitSequence"); MethodSignatureSequence matchingseq; if (!FactorySuggestionStore.TryGetMatchingSequence(pucls.HitSequence, pucls.SuggestedMethodSequences, out matchingseq)) { //Failed to retrieve the hit sequence. However, a heuristic //can be used where there is only one suggested sequence if (pucls.SuggestedMethodSequences.Count == 1) { matchingseq = pucls.SuggestedMethodSequences[0]; putIndependentMssl.Add(matchingseq); putSpecificMssl.Add(matchingseq); } else { pmd.Log.LogWarning(WikiTopics.MissingWikiTopic, "SequenceMatch", "Failed to retrieve a matching sequence for a hit sequence, adding complete hit sequence " + pucls.HitSequence); var hitSubSequence = new MethodSignatureSequence(); foreach (var mhit in pucls.HitSequence.Sequence) { if (mhit.Contains("..ctor(")) //Don't add constructors { continue; } if (!mhit.Contains(this.DeclaringType)) //Ignore the method calls from other types { continue; } hitSubSequence.Sequence.Add(mhit); } //Add all sequences to final set of sequences for further usage. putIndependentMssl.Add(hitSubSequence); putSpecificMssl.Add(hitSubSequence); //this.UpgradeActiveULStores(putsignature, pucls.SuggestedMethodSequences); } } else { //Add all sequences to final set of sequences for further usage. putIndependentMssl.Add(matchingseq); putSpecificMssl.Add(matchingseq); //this.UpgradeActiveULStores(putsignature, matchingseq); } }
/// <summary> /// Tries to load dynamic database /// </summary> /// <param name="pmd"></param> /// <returns></returns> public static bool TryLoadDynamicDatabase(PexMeDynamicDatabase pmd) { SafeDebug.AssumeNotNull(pmd, "pmd"); var suggestionstore = Path.Combine(PexMeConstants.PexMeStorageDirectory, PexMeConstants.PexMeFactorySuggestionStore); if (!File.Exists(suggestionstore)) { pmd.FactorySuggestionsDictionary = new System.Collections.Generic.Dictionary <string, PexMe.ObjectFactoryObserver.FactorySuggestionStore>(); } else { try { Stream streamRead = File.OpenRead(suggestionstore); BinaryFormatter binaryRead = new BinaryFormatter(); pmd.FactorySuggestionsDictionary = binaryRead.Deserialize(streamRead) as System.Collections.Generic.Dictionary <string, FactorySuggestionStore>; streamRead.Close(); } catch (Exception ex) { //host.Log.LogErrorFromException(ex, WikiTopics.MissingWikiTopic, "dumpreader", // "Failed to read the factory suggestion store"); pmd.FactorySuggestionsDictionary = new System.Collections.Generic.Dictionary <string, PexMe.ObjectFactoryObserver.FactorySuggestionStore>(); } } if (PexMeConstants.ENABLE_DYNAMICDB_STORAGE) { var fieldstore = Path.Combine(PexMeConstants.PexMeStorageDirectory, PexMeConstants.PexMeDynamicFieldStore); if (!File.Exists(fieldstore)) { pmd.FieldDictionary = new SafeDictionary <Field, FieldStore>(); } else { try { Stream streamRead = File.OpenRead(fieldstore); BinaryFormatter binaryRead = new BinaryFormatter(); System.Collections.Generic.Dictionary <string, PersistentFieldStore> pfs = binaryRead.Deserialize(streamRead) as System.Collections.Generic.Dictionary <string, PersistentFieldStore>; pmd.FieldDictionary = GetFieldDictionary(pmd, pfs); streamRead.Close(); } catch (Exception) { //host.Log.LogErrorFromException(ex, WikiTopics.MissingWikiTopic, "dumpreader", // "Failed to read the dynamic field store"); pmd.FieldDictionary = new SafeDictionary <Field, FieldStore>(); } } } else { pmd.FieldDictionary = new SafeDictionary <Field, FieldStore>(); } if (PexMeConstants.ENABLE_DYNAMICDB_STORAGE) { var methodstore = Path.Combine(PexMeConstants.PexMeStorageDirectory, PexMeConstants.PexMeDynamicMethodStore); if (!File.Exists(methodstore)) { pmd.MethodDictionary = new SafeDictionary <Method, MethodStore>(); } else { try { Stream streamRead = File.OpenRead(methodstore); BinaryFormatter binaryRead = new BinaryFormatter(); System.Collections.Generic.Dictionary <string, PersistentMethodStore> pfs = binaryRead.Deserialize(streamRead) as System.Collections.Generic.Dictionary <string, PersistentMethodStore>; pmd.MethodDictionary = GetMethodDictionary(pmd, pfs); streamRead.Close(); } catch (Exception) { //host.Log.LogErrorFromException(ex, WikiTopics.MissingWikiTopic, "dumpreader", // "Failed to read the dynamic field store"); pmd.MethodDictionary = new SafeDictionary <Method, MethodStore>(); } } } else { pmd.MethodDictionary = new SafeDictionary <Method, MethodStore>(); } var expstore = Path.Combine(PexMeConstants.PexMeStorageDirectory, PexMeConstants.PexMeDynamicExploredMethods); if (!File.Exists(expstore)) { pmd.AllExploredMethods = new HashSet <string>(); } else { try { Stream streamRead = File.OpenRead(expstore); BinaryFormatter binaryRead = new BinaryFormatter(); pmd.AllExploredMethods = binaryRead.Deserialize(streamRead) as HashSet <string>; streamRead.Close(); } catch (Exception) { //host.Log.LogErrorFromException(ex, WikiTopics.MissingWikiTopic, "dumpreader", // "Failed to read the dynamic field store"); pmd.AllExploredMethods = new HashSet <string>(); } } var pendingstore = Path.Combine(PexMeConstants.PexMeStorageDirectory, PexMeConstants.PexMePendingExplorationMethods); if (!File.Exists(pendingstore)) { pmd.PendingExplorationMethods = new HashSet <string>(); } else { try { Stream streamRead = File.OpenRead(pendingstore); BinaryFormatter binaryRead = new BinaryFormatter(); pmd.PendingExplorationMethods = binaryRead.Deserialize(streamRead) as HashSet <string>; streamRead.Close(); } catch (Exception) { //host.Log.LogErrorFromException(ex, WikiTopics.MissingWikiTopic, "dumpreader", // "Failed to read the dynamic field store"); pmd.PendingExplorationMethods = new HashSet <string>(); } } return(true); }
/// <summary> /// Call-back that gets invoked when Pex requires a factory method /// for a specific type. /// TODO: May not be invoked when there is some existing factory method /// already there and the new uncovered branch is due to object creation issue /// Or will be invoked only if Pex thinks that it needs a factory method. /// </summary> /// <param name="explorableType"></param> /// <returns></returns> public IEnumerable <PexExplorableCandidate> GuessExplorables(TypeEx explorableType) { SafeDebug.AssumeNotNull(explorableType, "explorableType"); this.host.Log.LogMessage(PexMeLogCategories.MethodBegin, "Beginning of PexMeFactoryGuesser.GuessExplorables method"); this.host.Log.LogMessage(PexMeLogCategories.Debug, "Requested for type: " + explorableType); //A trick to make generics work properly with the combination of inheritance. //Check the class PreDefinedGenericClasses for more details of why this line of code is required PreDefinedGenericClasses.recentAccessedTypes.Add(explorableType.FullName); var visibilityContext = VisibilityContext.Exported; if (!explorableType.IsVisible(visibilityContext))//if the type is not public { yield break; } //Giving mseqgen factories the highest preferemce if (PexMeConstants.ENABLE_MSEQGEN_RECOMMENDER) { if (mseqgen == null) { mseqgen = this.pmd.GetService <MSeqGenRecommender>(); } foreach (var factory in mseqgen.GetMSeqGenFactories(explorableType)) { yield return(factory); } } //the following factory is not returned to be used in sequence explroation but used to check //whether things are valid PexExplorableFactory localExplorableFactory; bool result = PexExplorableFactory.TryGetExplorableFactory(this.host, explorableType, out localExplorableFactory); Method bestConstructorMethod = null; if (explorableType.DefaultConstructor == null) { #region scan visible constructors, order by call depth, select best constructor var orderedMethodEffectsList = new SafeList <OrderedMethodEffects>(); var bestConstructor = new OrderedMethodEffects(); bool bNoVisibleConstructors = true; foreach (var constructor in explorableType.GetVisibleInstanceConstructors(visibilityContext)) { if (!localExplorableFactory.IsValidFactoryMethod(constructor)) { continue; } orderedMethodEffectsList.Add(new OrderedMethodEffects(this.host, constructor)); bNoVisibleConstructors = false; } if (!bNoVisibleConstructors) { //Finding the default constructor. We always start with the default constructor orderedMethodEffectsList.Sort(); foreach (var entry in orderedMethodEffectsList) { if (bestConstructor.Method == null || bestConstructor.Effects.WrittenInstanceFields.Count > entry.Effects.WrittenInstanceFields.Count) { bestConstructor = entry; } } orderedMethodEffectsList.Clear(); if (bestConstructor.Method != null) //cannot find a constructor { bestConstructorMethod = bestConstructor.Method; } } if (bestConstructorMethod == null) { if (!TypeAnalyzer.TryGetProducingMethods(this.pmd, explorableType, out bestConstructorMethod)) { yield break; } } #endregion } else { bestConstructorMethod = explorableType.DefaultConstructor; } #region default factory method from the original Pex: scan visible methods, order by call depth, add methods as setters //start building the method sequence PexExplorableFactory originalExplorableFactory; result = PexExplorableFactory.TryGetExplorableFactory(this.Host, explorableType, out originalExplorableFactory); //add constructor if (!originalExplorableFactory.TrySetFactoryMethod(bestConstructorMethod)) { SafeDebug.Fail("we checked before that it is valid"); yield break; } IPexExplorable originalExplorable1 = originalExplorableFactory.CreateExplorable(); CodeUpdate.AddMethodCodeUpdate originalPreviewUpdate1; CodeUpdate originalUpdate1 = originalExplorableFactory.CreateExplorableFactoryUpdate(out originalPreviewUpdate1); //return the original one after own suggested this.WriteOutMethodBody(explorableType, originalPreviewUpdate1); yield return(new PexExplorableCandidate(originalExplorable1, false, originalUpdate1)); var fsuggestions = this.pmd.FactorySuggestionsDictionary; //No suggestions for this type are available FactorySuggestionStore fss; if (fsuggestions.Count != 0 && fsuggestions.TryGetValue(explorableType.ToString(), out fss)) { var methodNameToMethodMapper = new SafeDictionary <string, Method>(); var propertyNameToPropertyMapper = new SafeDictionary <string, Property>(); //Trying to add the remaining method setters ExtractMethodsAndProperties(explorableType, methodNameToMethodMapper, propertyNameToPropertyMapper); //PexMe suggested factory methods foreach (var msequence in fss.GetSuggestedMethodSequences(this.pmd)) { PexExplorableFactory pexmeExplorableFactory; result = PexExplorableFactory.TryGetExplorableFactory(this.host, explorableType, out pexmeExplorableFactory); bool bRecommendThisFactoryMethod = false; try { //Check whether the sequence includes a constructor //If yes use the constructor Method bestConstructorMethodSuggested = null; foreach (var methodid in msequence.Sequence) { if (!methodid.Contains("..ctor(")) { continue; } Method tempMethod; if (methodNameToMethodMapper.TryGetValue(methodid, out tempMethod)) { bestConstructorMethodSuggested = tempMethod; } else { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "factoryguesser", "Failed to the get the method with ID: " + methodid); } } if (bestConstructorMethodSuggested == null) { if (!pexmeExplorableFactory.TrySetFactoryMethod(bestConstructorMethod)) { SafeDebug.Fail("we checked before that it is valid"); yield break; } } else { if (!pexmeExplorableFactory.TrySetFactoryMethod(bestConstructorMethodSuggested)) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "factoryguesser", "Failed to set best suggested constructor method " + bestConstructorMethodSuggested.FullName); yield break; } else { bRecommendThisFactoryMethod = true; } } //handle other methods foreach (var methodid in msequence.Sequence) { if (methodid.Contains("..ctor(")) { continue; } //Could be a setter method for the property if (methodid.Contains("set_")) { Property prop; if (propertyNameToPropertyMapper.TryGetValue(methodid, out prop)) { if (!pexmeExplorableFactory.TryAddPropertySetter(prop)) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "factoryguesser", "Failed to add property " + prop.FullName + " to the factory method"); } else { bRecommendThisFactoryMethod = true; } continue; } } Method smethod; if (methodNameToMethodMapper.TryGetValue(methodid, out smethod)) { if (!pexmeExplorableFactory.TryAddMethodSetter(smethod)) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "factoryguesser", "Failed to add method " + smethod.FullName + " to the factory method"); } else { bRecommendThisFactoryMethod = true; } } } } catch (System.Exception ex) { this.host.Log.LogError(WikiTopics.MissingWikiTopic, "ExplorableGuesser", " Exception occurred while constructing factory from suggested sequence " + ex.Message); continue; } //no method are being added to this sequence. This can be of no use. if (!bRecommendThisFactoryMethod) { continue; } IPexExplorable originalExplorable = pexmeExplorableFactory.CreateExplorable(); CodeUpdate.AddMethodCodeUpdate originalPreviewUpdate; CodeUpdate originalUpdate = pexmeExplorableFactory.CreateExplorableFactoryUpdate(out originalPreviewUpdate); this.WriteOutMethodBody(explorableType, originalPreviewUpdate); yield return(new PexExplorableCandidate(originalExplorable, false, originalUpdate)); } } #endregion yield break; }
/// <summary> /// Gets the target method that need to be invoked for setting a field. /// Based on static analysis and later uses dynamic analysis for giving /// more priority to those methods that are identified through dynamic analysis also. /// </summary> /// <param name="ucls"></param> /// <param name="targetField"></param> /// <param name="declaringType"></param> /// <param name="targetMethods"></param> /// <returns></returns> private bool GetTargetMethod(UncoveredCodeLocationStore ucls, Field targetField, out SafeSet <Method> targetMethods) { targetMethods = new SafeSet <Method>(); int numfields = ucls.AllFields.Count; for (int count = 0; count < numfields; count++) { var field = ucls.AllFields[count]; //Get all write methods for this field SafeSet <Method> writeMethods = null; //Get the declaring type of the field. There are two possibilities of choosing //a declaring type: from the next field or the enclosing type TypeEx declaringType1 = null, declaringType2 = null; //If there is a parent field, the declaring type should //be upgraded to the type of the next field in the list, which could be //a sub-class of the actual declaring type if (count < numfields - 1) { var nextField = ucls.AllFields[count + 1]; declaringType1 = nextField.Type; } if (!MethodOrFieldAnalyzer.TryGetDeclaringTypeEx(this.host, field, out declaringType2)) { SafeDebug.AssumeNotNull(declaringType2, "declaringType"); } var declaringType = declaringType2; if (declaringType1 != null && declaringType1 != declaringType2) { declaringType = this.ChooseADeclaringType(declaringType1, declaringType2); } //Chosen declaringType should be a part of all field types stored //in UCLS. If not, there can be inheritance issues if (!ucls.AllFieldTypes.Contains(declaringType)) { //Find out the type to which declaringType is assignable and update it foreach (var tex in ucls.AllFieldTypes) { if (tex.IsAssignableTo(declaringType)) { declaringType = tex; break; } } } //For the first field, get all the methods that modify the field //using static analysis if (targetMethods.Count == 0) { //Try from static analysis store if (!this.psd.TryGetFilteredWriteMethods(field, declaringType, ucls.DesiredFieldModificationType, out writeMethods)) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "factoryguesser", "Failed to get write methods for the field " + field.FullName); return(false); } //Try from dynamic analysis //if (!this.pmd.FieldDictionary.TryGetValue(field.GlobalIndex, out fs)) targetMethods.AddRange(writeMethods); } else { //Get the callers of all methods in targetmethods SafeSet <Method> callerMethods = new SafeSet <Method>(); foreach (var tmw in targetMethods) { SafeSet <Method> callingMethods; //TODO: Performance improvements can be done here as we repeat the loops inside //the method for each method in targetMethods if (!this.psd.TryGetCallingMethodsInType(tmw, field, declaringType, out callingMethods)) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "factoryguesser", SafeString.Format("Failed to get calling methods of {0} through static and dynamic analysis", tmw)); continue; } //Filter the called methods based on field to avoid //unnecessary additional methods SafeSet <Method> subcallingMethods = this.psd.FilterCallingMethodsBasedOnField(tmw, field, callingMethods); if (callingMethods.Count > 0 && subcallingMethods.Count == 0) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "callingmethods", "Failed to filter calling methods based on field, adding all methods"); subcallingMethods.AddRange(callingMethods); } //Check in dynamic analysis portion //if (!this.pmd.MethodDictionary.TryGetValue(tmw.GlobalIndex, out mstore)) //{ //} //else // callingMethods = mstore.CallingMethods[declaringType]; callerMethods.AddRange(subcallingMethods); } //All caller methods in the parent type targetMethods = callerMethods; } //Our objective is to search for the methods that belong to our target field. //Stop traversal once the desired method is found if (field == targetField) { break; } } return(true); }