/// <summary> /// Adds a default method-call sequence that represents the first execution /// of the PUT /// </summary> internal void AddDefaultSequence(PexMeDynamicDatabase pmd, MethodSignatureSequence defaultSeq) { //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); putIndependentMssl.Add(defaultSeq); } //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); putSpecificMssl.Add(defaultSeq); } }
public static bool TryCheckReturnTypeOfMethod(PexMeDynamicDatabase pmd, TypeDefinition tdef, MethodDefinition mdef, TypeEx targetTypeEx, out Method producingMethod) { var retType = mdef.ResultType; if (retType.ToString() == targetTypeEx.FullName) { producingMethod = mdef.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(pmd, tdef), MethodOrFieldAnalyzer.GetGenericMethodParameters(pmd, mdef)); return(true); } //Get the actual type of return type and see whether it is assinable TypeEx retTypeEx; if (MethodOrFieldAnalyzer.TryGetTypeExFromName(pmd, pmd.CurrAssembly, retType.ToString(), out retTypeEx)) { if (targetTypeEx.IsAssignableTo(retTypeEx)) { producingMethod = mdef.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(pmd, tdef), MethodOrFieldAnalyzer.GetGenericMethodParameters(pmd, mdef)); return(true); } } producingMethod = null; return(false); }
private void ExtractMethodsAndProperties(TypeEx explorableType, SafeDictionary <string, Method> methodNameToMethodMapper, SafeDictionary <string, Property> propertyNameToPropertyMapper) { for (TypeEx type = explorableType; type != null; type = type.BaseType) { if (type.ToString() == "System.Object") { continue; } var typedef = type.Definition; foreach (var constructor in typedef.DeclaredInstanceConstructors) { Method method = constructor.Instantiate(type.GenericTypeArguments, MethodOrFieldAnalyzer.GetGenericMethodParameters(host, constructor)); methodNameToMethodMapper[MethodOrFieldAnalyzer.GetMethodSignature(constructor)] = method; } foreach (var methodDefinition in typedef.DeclaredInstanceMethods) { Method method = methodDefinition.Instantiate(type.GenericTypeArguments, MethodOrFieldAnalyzer.GetGenericMethodParameters(host, methodDefinition)); methodNameToMethodMapper[MethodOrFieldAnalyzer.GetMethodSignature(method)] = method; } foreach (var propDefinition in typedef.DeclaredProperties) { Property prop = propDefinition.Instantiate(type.GenericTypeArguments); if (prop.Setter != null) { propertyNameToPropertyMapper[MethodOrFieldAnalyzer.GetMethodSignature(prop.Setter)] = prop; } } } }
/// <summary> /// Gets invoked befor the state of the exploration /// </summary> /// <param name="host"></param> /// <returns></returns> object IPexExplorationPackage.BeforeExploration(IPexExplorationComponent host) { this.pmd.CurrentPUTMethod = host.ExplorationServices.CurrentExploration.Exploration.Method; var currPUTSignature = MethodOrFieldAnalyzer.GetMethodSignature(pmd.CurrentPUTMethod); //Activate the methods of the current PUT from dormant foreach (var fss in pmd.FactorySuggestionsDictionary.Values) { foreach (var pucls in fss.locationStoreSpecificSequences.Values) { if (pucls.IsDormat()) { pucls.ActivateFromDormant(currPUTSignature); } } } pmd.PendingExplorationMethods.Add(currPUTSignature); //This code includes MSeqGen related stuff, primarily for evaluating the combined approach //if (PexMeConstants.ENABLE_MSEQGEN_RECOMMENDER) //{ // var explorableManager = host.ExplorationServices.ExplorableManager; // int numMethodsRecommended = 0; // foreach (var explorableCandidate in mseqgen.GetExplorableCandidates()) // { // explorableManager.AddExplorableCandidate(explorableCandidate); // numMethodsRecommended++; // } // // host.Log.LogMessage("MSeqGenRecommender", "Recommended " + numMethodsRecommended + " factory methods"); //} return(null); }
private static SafeDictionary <Method, MethodStore> GetMethodDictionary(IPexComponent host, System.Collections.Generic.Dictionary <string, PersistentMethodStore> pmethoddic) { var methoddic = new SafeDictionary <Method, MethodStore>(); foreach (var methodstr in pmethoddic.Keys) { Method method; bool bresult = MethodOrFieldAnalyzer.TryGetMethodFromPersistentStringForm(host, methodstr, out method); if (!bresult) { continue; } MethodStore ms; bresult = PersistentMethodStore.TryGetMethodStore(host, pmethoddic[methodstr], out ms); if (!bresult) { continue; } //SafeDebug.Assume(bresult, "Failed to get method from persistent store!!!"); methoddic[method] = ms; } return(methoddic); }
/// <summary> /// Function the retrieves associated Persistent store for each MethodStore /// </summary> /// <param name="ms"></param> /// <param name="pms"></param> /// <returns></returns> public static bool TryGetPersistentMethodStore(MethodStore ms, out PersistentMethodStore pms) { pms = new PersistentMethodStore(); pms.methodName = MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(ms.methodName); //foreach (var field in ms.ReadFields) // pms.ReadFields.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfField(field)); foreach (var field in ms.WriteFields) { pms.WriteFields.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfField(field)); } //foreach (var typeex in ms.CallingMethods.Keys) //{ // HashSet<string> wmethods = new HashSet<string>(); // pms.CallingMethods.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfTypeEx(typeex), wmethods); // var methods = ms.CallingMethods[typeex]; // var assemblyname = typeex.Definition.Module.Assembly.Location; // var typename = typeex.FullName; // foreach (var m in methods) // { // wmethods.Add(assemblyname + PexMeConstants.PexMePersistenceFormSeparator // + typename + PexMeConstants.PexMePersistenceFormSeparator // + MethodOrFieldAnalyzer.GetMethodSignature(m)); // } //} //foreach (var calledMethod in ms.CalledMethods) // pms.CalledMethods.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(calledMethod)); return(true); }
public void AfterExecution(IPexComponent host, object data) { if (this.pmd.CurrentPUTMethod == null) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "PUTExploration", "Return, not current PUT method is set"); WriteStopStatus(); return; } SafeDebug.AssertNotNull(this.pmd.CurrentPUTMethod, "CurrentPUTMethod should be set by this time"); var currPUTSignature = MethodOrFieldAnalyzer.GetMethodSignature(this.pmd.CurrentPUTMethod); if (this.pmd.AllExploredMethods.Contains(currPUTSignature)) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "PUTExploration", "Ignoring the post processing of the PUT " + currPUTSignature + " since it is explored earlier!!!"); WriteStopStatus(); return; } //Add this to pending methods PexMePostProcessor ppp = new PexMePostProcessor(host); ppp.AfterExecution(); }
/// <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); }
/// <summary> /// Adds a field entity /// </summary> /// <param name="fd"></param> public void AddFieldEntity(TypeDefinition td, FieldDefinition fd) { if (!fieldEntities.ContainsKey(fd.FullName)) { var field = fd.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(this.host, td)); DeclFieldEntity dfe = new DeclFieldEntity(field); fieldEntities[field.FullName] = dfe; } }
/// <summary> /// Adds a declared entity. Returns either the existing one or creates a new one /// </summary> /// <param name="de"></param> public void AddToDeclEntityDic(TypeDefinition td, out DeclClassEntity dce) { if (!this.declEntityDic.TryGetValue(td.FullName, out dce)) { TypeEx type = td.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(this.Host, td)); dce = new DeclClassEntity(type); declEntityDic[type.FullName] = dce; } }
/// <summary> /// Collects all definitions and uses among each class in the assembly under analysis /// </summary> /// <param name="ade"></param> private static void CollectAllDefsAndUsesInTypeDef(TypeDefinition td, DeclClassEntity ade) { var host = DUCoverStore.GetInstance().Host; SideEffectStore ses = SideEffectStore.GetInstance(); var psd = host.GetService <PexMeStaticDatabase>() as PexMeStaticDatabase; foreach (var constructor in td.DeclaredInstanceConstructors) { var method = constructor.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(host, td), MethodOrFieldAnalyzer.GetGenericMethodParameters(host, constructor)); CollectDefsAndUsesInMethod(psd, td, ade, method, null, ses); } foreach (var mdef in td.DeclaredInstanceMethods) { try { var method = mdef.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(host, td), MethodOrFieldAnalyzer.GetGenericMethodParameters(host, mdef)); CollectDefsAndUsesInMethod(psd, td, ade, method, null, ses); } catch (Exception ex) { logger.ErrorException("Failed to instantiate method " + mdef.FullName, ex); } } foreach (var prop in td.DeclaredProperties) { var getter = prop.Getter; if (getter != null) { Field usedField; int foffset; var method = getter.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(host, td), MethodOrFieldAnalyzer.GetGenericMethodParameters(host, getter)); if (TryGetFieldOfGetter(method, out usedField, out foffset)) { DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(usedField.FullName, out dfe)) { //Found an accessor. register the usage dfe.AddToUseList(method, foffset); } } } var setter = prop.Setter; if (setter != null) { var method = setter.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(host, td), MethodOrFieldAnalyzer.GetGenericMethodParameters(host, setter)); CollectDefsAndUsesInMethod(psd, td, ade, method, null, ses); } } }
/// <summary> /// Generates nested command files. Ignores if there are any PUTs in /// pmd.PendingExplorationMethods since those methods can cause cycles. /// </summary> /// <param name="allSuggestedNewPUTs"></param> /// <param name="cmdfile"></param> private void GenerateNestedCommandFile(SafeSet <Method> allSuggestedNewPUTs, string cmdfile) { using (StreamWriter sw = new StreamWriter(cmdfile)) { foreach (var newput in allSuggestedNewPUTs) { var newputsig = MethodOrFieldAnalyzer.GetMethodSignature(newput); sw.WriteLine(PUTGenerator.PUTGenerator.GeneratePUTCommand(newput)); } } }
GetPersistentFieldDictionary(SafeDictionary <Field, FieldStore> fielddic) { var pfielddic = new System.Collections.Generic.Dictionary <string, PersistentFieldStore>(); foreach (var field in fielddic.Keys) { var fieldstr = MethodOrFieldAnalyzer.GetPersistentStringFormOfField(field); PersistentFieldStore pfs; bool bresult = PersistentFieldStore.TryGetPersistentFieldStore(this.host, fielddic[field], out pfs); SafeDebug.Assume(bresult, "Failed to get persistent field store!!!"); pfielddic[fieldstr] = pfs; } return(pfielddic); }
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); }
/// <summary> /// Checks whether there are any looping requireements based on looping threshold and enhances /// the sequence accordingly. Applies only for INCREMENT and DECREMENT field modification types /// </summary> /// <param name="pucls"></param> /// <param name="p"></param> private void CheckNEnhanceForLooping(PersistentUncoveredLocationStore pucls, int fitnessval, FieldModificationType fmt, SafeList <Field> culpritFields) { if (fmt != FieldModificationType.INCREMENT && fmt != FieldModificationType.DECREMENT) { return; } //Not even a single execution happened on this location. if (fitnessval == Int32.MaxValue) { return; } var field = culpritFields[0]; FieldStore fs; if (!this.pmd.FieldDictionary.TryGetValue(field, out fs)) { return; } Dictionary <string, Method> writeMethods = new Dictionary <string, Method>(); foreach (var mset in fs.WriteMethods.Values) { foreach (var m in mset) { var sig = MethodOrFieldAnalyzer.GetMethodSignature(m); writeMethods.Add(sig, m); } } foreach (var seq in pucls.SuggestedMethodSequences) { string loop_method; if (!this.IsEligibleForLooping(seq, field, writeMethods, fs, out loop_method)) { continue; } pucls.LoopingFeatureApplied = true; this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "LoopingFeature", "Applying looping feature on method: " + loop_method + " (" + (fitnessval - 1) + ")"); for (int count = 1; count < fitnessval; count++) { seq.Sequence.Add(loop_method); } } }
GetPersistentMethodDictionary(SafeDictionary <Method, MethodStore> methoddic) { var pmethoddic = new System.Collections.Generic.Dictionary <string, PersistentMethodStore>(); foreach (var method in methoddic.Keys) { var methodstr = MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(method); PersistentMethodStore pms; bool bresult = PersistentMethodStore.TryGetPersistentMethodStore(methoddic[method], out pms); SafeDebug.Assume(bresult, "Failed to get persistent method store!!!"); pmethoddic[methodstr] = pms; } return(pmethoddic); }
/// <summary> /// Function the retrieves associated Persistent store for each MethodStore /// </summary> /// <param name="ms"></param> /// <param name="pms"></param> /// <returns></returns> public static bool TryGetPersistentFieldStore(IPexComponent host, FieldStore fs, out PersistentFieldStore pfs) { pfs = new PersistentFieldStore(); pfs.FieldName = MethodOrFieldAnalyzer.GetPersistentStringFormOfField(fs.FieldName); //foreach(var value in fs.FieldValues) // pfs.FieldValues.Add(value); //TODO: Performance can be improved via caching over here foreach (var m in fs.ReadMethods) { pfs.ReadMethods.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(m)); } foreach (var typeex in fs.WriteMethods.Keys) { HashSet <string> wmethods = new HashSet <string>(); pfs.WriteMethods.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfTypeEx(typeex), wmethods); SafeSet <Method> methods; bool bresult = fs.WriteMethods.TryGetValue(typeex, out methods); SafeDebug.Assume(bresult, "Failed to get associated set of methods for a type"); var assemblyname = typeex.Definition.Module.Assembly.Location; var typename = typeex.FullName; foreach (var m in methods) { wmethods.Add(assemblyname + PexMeConstants.PexMePersistenceFormSeparator + typename + PexMeConstants.PexMePersistenceFormSeparator + MethodOrFieldAnalyzer.GetMethodSignature(m)); } } foreach (var m in fs.ModificationTypeDictionary.Keys) { var value = fs.ModificationTypeDictionary[m]; pfs.ModificationTypeDictionary.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(m), value); } foreach (var m in fs.PreciseModificationTypeDictionary.Keys) { var value = fs.PreciseModificationTypeDictionary[m]; pfs.PreciseModificationTypeDictionary.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(m), value); } return(true); }
private static SafeDictionary <Field, FieldStore> GetFieldDictionary(IPexComponent host, System.Collections.Generic.Dictionary <string, PersistentFieldStore> pfielddic) { var fielddic = new SafeDictionary <Field, FieldStore>(); foreach (var fieldstr in pfielddic.Keys) { Field field; bool bresult = MethodOrFieldAnalyzer.TryGetFieldFromPersistentStringForm(host, fieldstr, out field); SafeDebug.Assume(bresult, "Failed to get field from persistent store!!!"); FieldStore fs; bresult = PersistentFieldStore.TryGetFieldStore(host, pfielddic[fieldstr], out fs); SafeDebug.Assume(bresult, "Failed to get field store!!!"); fielddic[field] = fs; } return(fielddic); }
/// <summary> /// Gets a MethodSignatureSequenceList for each putmethod. If one does not exist, /// creates a fresh one /// </summary> /// <param name="putmethod"></param> /// <returns></returns> public bool TryGetListFromFinalSuggestedSequences(Method putmethod, out MethodSignatureSequenceList mssl) { mssl = null; Method assocMethod; if (!PUTGenerator.PUTGenerator.TryRetrieveMethodCall(putmethod, out assocMethod)) { return(false); } var methodcallname = MethodOrFieldAnalyzer.GetMethodSignature(assocMethod); if (!this.FinalSuggestedMethodSequences.TryGetValue(methodcallname, out mssl)) { mssl = new MethodSignatureSequenceList(); this.FinalSuggestedMethodSequences.Add(methodcallname, mssl); } return(true); }
public PersistentUncoveredLocationStore(CodeLocation cl, TypeEx explorableType, int termIndex, int fitnessvalue, FactorySuggestionStore fss) { this.CodeLocation = cl.ToString(); this.MethodSignature = MethodOrFieldAnalyzer.GetMethodSignature(cl.Method); TypeDefinition declaringType; if (!cl.Method.TryGetDeclaringType(out declaringType)) { //TODO:Error } this.ExplorableType = explorableType.ToString(); this.Offset = cl.Offset; this.AssemblyShortName = declaringType.Module.Assembly.Location; this.declaringTypeStr = declaringType.ToString(); this.Fitnessvalue = fitnessvalue; this.TermIndex = termIndex; this.parentfss = fss; }
/// <summary> /// Parses each record and stores into internal dictionary /// </summary> /// <param name="assemblyname"></param> /// <param name="typename"></param> /// <param name="fieldname"></param> /// <param name="fmttype"></param> /// <param name="methodname"></param> private static void ParseRecord(IPexComponent host, string assemblyname, string typename, string fieldname, string fmttype, string methodname) { Field field; if (!MethodOrFieldAnalyzer.TryGetField(host, assemblyname, typename, fieldname, out field)) { host.Log.LogWarning(WikiTopics.MissingWikiTopic, "PredefinedEffects", "Failed to load field: " + fieldname); return; } FieldModificationType fmt = FieldStore.GetModificationTypeFromString(fmttype); Method method; if (!MethodOrFieldAnalyzer.TryGetMethod(host, assemblyname, typename, methodname, out method)) { host.Log.LogWarning(WikiTopics.MissingWikiTopic, "PredefinedEffects", "Failed to load method: " + methodname); return; } //storing into the effects store PreDefinedMethodEffectsStore pdme = new PreDefinedMethodEffectsStore(field, fmt); List <Method> suggestedMethods; PreDefinedMethodEffectsStore existingPdme; if (!effectsStore.TryGetValue(pdme, out existingPdme)) { suggestedMethods = new List <Method>(); pdme.suggestedmethodList = suggestedMethods; effectsStore.Add(pdme, pdme); } else { suggestedMethods = existingPdme.suggestedmethodList; } suggestedMethods.Add(method); }
/// <summary> /// Dumps the graph to an XML file /// </summary> /// <param name="filename"></param> public void DumpToXMLFile(StreamWriter sw) { sw.WriteLine("\t<cfg methodName=\"" + MethodOrFieldAnalyzer.GetMethodSignature(this.method) + "\">"); //dumping vertices sw.WriteLine("\t<vertices>"); StringBuilder edgeSb = new StringBuilder("\t<edges>\r\n"); if (this.rootVertex != null) { sw.WriteLine("\t\t<vertex id=\"" + this.rootVertex.Instruction.Offset + "\" kind=\"Entry\" offset=\"" + this.rootVertex.Instruction.Offset + "\"></vertex>"); foreach (var vertex in this.vertices.Values) { if (vertex != this.rootVertex) { sw.WriteLine("\t\t<vertex id=\"" + vertex.Instruction.Offset + "\" kind=\"Normal\" offset=\"" + vertex.Instruction.Offset + "\"></vertex>"); } //add edges of this vertex to the edge string foreach (var outedge in this.vertexOutEdges[vertex]) { var sourceVertex = outedge.Source as InstructionVertex; var targetVertex = outedge.Target as InstructionVertex; edgeSb.Append("\t\t<edge sourceid=\"" + sourceVertex.Instruction.Offset + "\" targetid=\"" + targetVertex.Instruction.Offset + "\"></edge>\r\n"); } } } sw.WriteLine("\t</vertices>"); edgeSb.Append("\t</edges>\n"); //dumping edges sw.WriteLine(edgeSb.ToString()); sw.WriteLine("\t</cfg>"); }
/// <summary> /// Method is allowed to be invoked only once. Therefore the order of loading classes into the Dictionary is /// quite important. /// </summary> /// <param name="host"></param> public static bool LoadPredefinedGenericClasses(IPexComponent host, string assemblyName) { //QuickGraph: TEdge -> Edge<int> TypeEx edgeTypeEx; PreDefinedGenericClassesStore tedgePdgc = new PreDefinedGenericClassesStore(); predefinedClasses.Add("TEdge", tedgePdgc); if (MethodOrFieldAnalyzer.TryGetTypeExFromName(host, assemblyName, "QuickGraph.Edge`1", out edgeTypeEx)) { tedgePdgc.AddToPredinedStore("QuickGraph.AdjacencyGraph`2", edgeTypeEx); tedgePdgc.AddToPredinedStore("QuickGraph.IGraph`2", edgeTypeEx); } //Dsa: TNode for BinarySearchTree -> Dsa.DataStructures.BinaryTreeNode`1 PreDefinedGenericClassesStore tnodePdgc = new PreDefinedGenericClassesStore(); predefinedClasses.Add("TNode", tnodePdgc); TypeEx binNodeEx; if (MethodOrFieldAnalyzer.TryGetTypeExFromName(host, assemblyName, "Dsa.DataStructures.BinaryTreeNode`1", out binNodeEx)) { tnodePdgc.AddToPredinedStore("Dsa.DataStructures.BinarySearchTree`1", binNodeEx); tnodePdgc.AddToPredinedStore("Dsa.DataStructures.CommonBinaryTree`2", binNodeEx); tnodePdgc.AddToPredinedStore("System.Collections.Generic.Queue`1", binNodeEx); } TypeEx avltreeNodeEx = null; if (MethodOrFieldAnalyzer.TryGetTypeExFromName(host, assemblyName, "Dsa.DataStructures.AvlTreeNode`1", out avltreeNodeEx)) { tnodePdgc.AddToPredinedStore("Dsa.DataStructures.AvlTree`1", avltreeNodeEx); tnodePdgc.AddToPredinedStore("Dsa.DataStructures.CommonBinaryTree`2", avltreeNodeEx); tnodePdgc.AddToPredinedStore("System.Collections.Generic.Queue`1", avltreeNodeEx); } return(true); }
/// <summary> /// Helps guess factory methods for each uncovered condition /// </summary> private void GuessFactorymethods(out SafeSet <Method> allNewSuggestedPUTs, string currPUTSignature, out bool bHasSomeCoveredLocation, out bool bAllAreNewLocations, out bool bNoneAreNewLocations) { PexMeFactoryGuesser pfg = new PexMeFactoryGuesser(this.host); HashSet <string> allGivenUpLocations, allCoveredLocations, newUnCoveredLocations; //Analyze the current uncovered and previously uncovered locations this.pmd.AnalyzePreviousAndCurrentUncoveredLoc(currPUTSignature, out allGivenUpLocations, out allCoveredLocations, out newUnCoveredLocations, out bHasSomeCoveredLocation, out bAllAreNewLocations, out bNoneAreNewLocations); allNewSuggestedPUTs = new SafeSet <Method>(); //Iterate through each uncovered location foreach (var ucovLocList in pmd.UncoveredLocationDictionary.Values) { //TODO: Classify the uncovered locations into different groups //Because, it can happen that a single code location can have multiple terms which //cannot be merged together. if (ucovLocList.StoreList.Count == 0) { continue; } //Check whether this location is earlier attempted and is failed. no //need to try this location again FactorySuggestionStore fss = null; string key = null; if (this.pmd.FactorySuggestionsDictionary.TryGetValue(ucovLocList.ExplorableType, out fss)) { key = UncoveredCodeLocationStore.GetKey(ucovLocList.Location.ToString(), ucovLocList.ExplorableType, ucovLocList.TermIndex); //A fix to keep track of uncovered locations in system libraries if (TargetBranchAnalyzer.IsUncoveredLocationInSystemLib(ucovLocList.Location)) { fss.UncoveredSystemLibLocations.Add(key); } if (allGivenUpLocations.Contains(key)) { continue; } //Already covered locations can be reported again due to different PUTs or different call sites //if (allCoveredLocations.Contains(key)) // continue; if (fss.PermanentFailedUncoveredLocations.Contains(key)) { continue; } //if (fss.SuccessfulCoveredLocations.Contains(key)) // continue; } //A single element of ucovLoc is sufficient here var ucovLoc = ucovLocList.StoreList[0]; if (!pfg.TryInferFactoryMethod(ucovLoc, out ucovLoc.SuggestedMethodSetforFactory)) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "postprocessor", "Failed to suggest factory methods for uncovered location " + ucovLoc.ToString() + " -> Adding to permanent failed locations"); if (fss != null && key != null) { fss.PermanentFailedUncoveredLocations.Add(key); } continue; } //If a suggested method is not yet explored, add it to all new suggested method if (ucovLoc.SuggestedMethodSetforFactory != null) { foreach (var suggestedm in ucovLoc.SuggestedMethodSetforFactory) { if (suggestedm.IsConstructor) { continue; } //Check if this is ever explored by this process by getting associated PUT Method pexmethod; bool bretval = PUTGenerator.PUTGenerator.TryRetrievePUT(this.pmd, this.currAssembly, suggestedm, out pexmethod); if (!bretval) { //The suggested method is out of scope of current library and //no need to explore it explicitly continue; } //Ignore self suggestions if (pexmethod == this.pmd.CurrentPUTMethod) { continue; } var signature = MethodOrFieldAnalyzer.GetMethodSignature(pexmethod); if (this.pmd.AllExploredMethods.Contains(signature)) { continue; } if (this.pmd.PendingExplorationMethods.Contains(signature)) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "Nested PUTs", "Ignoring the nested PUT due to cycle detection " + signature); continue; } allNewSuggestedPUTs.Add(pexmethod); } } } }
/// <summary> /// Updates all sequences in uncovered location stores with new suggestions that /// are also stored within the PUT itself /// </summary> private void UpdateUncoveredLocationsWithNewSuggestions(string currPUTSignature) { //Iterate through each uncovered location foreach (var ucovLocList in this.pmd.UncoveredLocationDictionary.Values) { //TODO: Classify the uncovered locations into different groups //Because, it can happen that a single code location can have multiple terms which //cannot be merged together. if (ucovLocList.StoreList.Count == 0) { continue; } //Check whether this location is earlier attempted and is failed. no //need to try this location again FactorySuggestionStore fss; if (!this.pmd.FactorySuggestionsDictionary.TryGetValue(ucovLocList.ExplorableType, out fss)) { this.host.Log.LogWarning(WikiTopics.MissingWikiTopic, "UncoveredLocations", "Failed to retrieve factory suggestion store for explorable type " + ucovLocList.ExplorableType); continue; } MethodSignatureSequenceList putspecificlist; if (!fss.FinalPUTSequences.TryGetValue(currPUTSignature, out putspecificlist)) { putspecificlist = new MethodSignatureSequenceList(); } var ucovLoc = ucovLocList.StoreList[0]; //If a suggested method is not yet explored, add it to all new suggested method if (ucovLoc.SuggestedMethodSetforFactory != null) { //Prepare new sequences with the suggested method var newmssl = new MethodSignatureSequenceList(); foreach (var suggestedm in ucovLoc.SuggestedMethodSetforFactory) { //Get all the pre-requisite sequences for this suggested method var suggestedmsig = MethodOrFieldAnalyzer.GetMethodSignature(suggestedm); MethodSignatureSequenceList mssl; fss.FinalSuggestedMethodSequences.TryGetValue(suggestedmsig, out mssl); if (mssl == null || mssl.SequenceList.Count == 0) { var tempmss = new MethodSignatureSequence(); tempmss.Sequence.Add(suggestedmsig); newmssl.SequenceList.Add(tempmss); } else { //Make a new sequence from the suggested method and its pre-requisite foreach (var seq in mssl.SequenceList) { var tempmss = new MethodSignatureSequence(); tempmss.Sequence.AddRange(seq.Sequence); tempmss.Sequence.Add(suggestedmsig); newmssl.SequenceList.Add(tempmss); } } } //Add all these suggestions to the uncovered location store itself bool bNewlyCreated = false; var pucls = fss.GetPersistentLocationstore(ucovLoc, out bNewlyCreated); pucls.UpdateSuggestedMethodSequences(newmssl, putspecificlist); //Check whether any looping is required. If a method //is repeated more than 3 times, in a sequence, we consider //it as a looping requirement. This is only a heuristic based. if (!PexMeConstants.IGNORE_LOOP_FEATURE && !pucls.LoopingFeatureApplied) { this.CheckNEnhanceForLooping(pucls, pucls.Fitnessvalue, ucovLoc.DesiredFieldModificationType, ucovLoc.AllFields); } //Check for the number of sequences in this pucls. If they //exceed the limit, delete the sequences if ((pucls.SuggestedMethodSequences.Count - fss.FinalSuggestedMethodSequences.Values.Count) > PexMeConstants.MAX_ALLOWED_SEQUENCES) { fss.RemoveUncoveredLocationStore(pucls, false, this.pmd); var key = UncoveredCodeLocationStore.GetKey(pucls.CodeLocation, pucls.ExplorableType, pucls.TermIndex); fss.PermanentFailedUncoveredLocations.Add(key); fss.TemporaryFailedUncoveredLocations.Add(key, PexMeConstants.MAX_UNCOVEREDLOC_ATTEMPTS); this.pmd.Log.LogWarning(WikiTopics.MissingWikiTopic, "uncoveredlocation", @"Sequences for uncovered location " + pucls.CodeLocation + "crossed the threshold " + PexMeConstants.MAX_ALLOWED_SEQUENCES + ", Deleted forever"); } } } //Add default sequences to the newly created factory suggestion stores foreach (var ucovLocList in this.pmd.UncoveredLocationDictionary.Values) { if (ucovLocList.StoreList.Count == 0) { continue; } FactorySuggestionStore fss; if (!this.pmd.FactorySuggestionsDictionary.TryGetValue(ucovLocList.ExplorableType, out fss)) { continue; } var ucovLoc = ucovLocList.StoreList[0]; if (fss.BCreatedNow) { fss.BCreatedNow = false; var mss = new MethodSignatureSequence(); var explorableType = ucovLocList.ExplorableType; foreach (var methodinucov in ucovLoc.MethodCallSequence.Sequence) { if (methodinucov.Contains("..ctor(")) //Don't add constructors { continue; } if (!methodinucov.Contains(explorableType)) //Ignore the method calls from other types { continue; } mss.Sequence.Add(methodinucov); } fss.AddDefaultSequence(this.pmd, mss); } } }
/// <summary> /// 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. The primary objective is to minimize the search space /// as much as possible. /// </summary> /// <param name="ucls"></param> /// <param name="targetField"></param> /// <returns></returns> public static bool GetTargetExplorableField(IPexComponent host, SafeList <Field> allFields, out Field targetField, out TypeEx declaringType) { targetField = null; var allInvolvedFields = new SafeList <Field>(); allInvolvedFields.AddRange(allFields); int numFields = allInvolvedFields.Count; if (numFields == 1) { targetField = allInvolvedFields[0]; if (!MethodOrFieldAnalyzer.TryGetDeclaringTypeEx(host, targetField, out declaringType)) { declaringType = null; return(false); } return(true); } allInvolvedFields.Reverse(); //Commenting the following functionality, which is actually intended //for reducing the enormous search space in the list of fields. However, //since our approach is not using the Pex's default factory method mechanism //this may not be of any use. //TypeEx prevFieldType = null; //for (int count = 0; count < allInvolvedFields.Count; count++) //{ // var currentField = allInvolvedFields[count]; // if (!MethodOrFieldAnalyzer.TryGetDeclaringTypeDefinition(host, currentField, out declaringType)) // { // host.Log.LogError(WikiTopics.MissingWikiTopic, "targetfield", // "Failed to get the declaring type for the field " + currentField.FullName); // return false; // } // SafeDebug.Assume(prevFieldType == null || prevFieldType == declaringType || prevFieldType.IsAssignableTo(declaringType) // || declaringType.IsAssignableTo(prevFieldType), // "The current field type (" + declaringType + ") should be the same as the previous field type (" + prevFieldType + ")"); // if (MethodOrFieldAnalyzer.IsFieldExternallyVisible(host, declaringType, currentField)) // { // prevFieldType = currentField.Type; // continue; // } // else // { // targetField = currentField; // return true; // } //} targetField = allInvolvedFields[0]; if (!MethodOrFieldAnalyzer.TryGetDeclaringTypeEx(host, targetField, out declaringType)) { host.Log.LogError(WikiTopics.MissingWikiTopic, "targetfield", "Failed to get the declaring type for the field " + targetField.FullName); return(false); } return(true); }
/// <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); }
/// <summary> /// Gets invoked after the execution of the entire pex process /// </summary> public void AfterExecution() { try { //this.host.Log.LogMessage(PexMeLogCategories.MethodBegin, "Begin of PexMePostProcessor.AfterExecution() method"); DirectoryHelper.CheckExistsOrCreate(PexMeConstants.PexMeStorageDirectory); //Filter covered locations from uncovered locations this.pmd.FilterOutCoveredCodeLocations(); var currPUTSignature = MethodOrFieldAnalyzer.GetMethodSignature(this.pmd.CurrentPUTMethod); //Suggest factory methods SafeSet <Method> allSuggestedNewPUTs; bool bHasSomeCoveredLocation, bAllAreNewLocations, bNoneAreNewLocations; this.GuessFactorymethods(out allSuggestedNewPUTs, currPUTSignature, out bHasSomeCoveredLocation, out bAllAreNewLocations, out bNoneAreNewLocations); var filename = Path.Combine(PexMeConstants.PexMeStorageDirectory, PexMeConstants.ReExecutionStatusFile); using (StreamWriter sw = new StreamWriter(filename)) { //nestingdepth == null represents that this is not run from the Perl //script. So, ignoring the generation of alternative PUTs. if (allSuggestedNewPUTs.Count == 0 || this.ndepth == -1 || this.ndepth >= PexMeConstants.MAX_ALLOWED_NESTED_DEPTH) { this.pmd.PendingExplorationMethods.Remove(currPUTSignature); //Decide to re-execute or stop. So update all sequences //within uncovered locations with new suggestions and prepare for re-execute this.UpdateUncoveredLocationsWithNewSuggestions(currPUTSignature); //Check whether there is a need to further continue based on requirement //in uncovered locations in factory suggestion store. Used to communicate to outside //process for re-execution if (this.pmd.NeedReExecute(bHasSomeCoveredLocation, bAllAreNewLocations, bNoneAreNewLocations)) { sw.WriteLine("REEXECUTE"); } else { sw.WriteLine("STOP"); //Marks a successful exploration of this PUT this.pmd.AllExploredMethods.Add(currPUTSignature); //Remove all PUT specific sequences from the permanent store this.EndOfPUTCleanUp(currPUTSignature); } } else { //Set up new targets for additional explorations which are required for achieving //the current target. var newCommandFile = "PexMe." + System.Environment.TickCount + ".txt"; this.GenerateNestedCommandFile(allSuggestedNewPUTs, newCommandFile); sw.WriteLine("NESTEDEXECUTE"); sw.WriteLine(newCommandFile); //Putting all current information on uncovered locations to dormant //stage. Will be re-activated when required and when this PUT is again //brought to action. var currPUT = MethodOrFieldAnalyzer.GetMethodSignature(this.pmd.CurrentPUTMethod); this.SendToDormant(currPUT); } } this.pdw.DumpDynamicDatabase(this.pmd as PexMeDynamicDatabase); this.pdw.DumpStaticDatabase(this.psd as PexMeStaticDatabase); } catch (Exception ex) { this.host.Log.LogCriticalFromException(ex, WikiTopics.MissingWikiTopic, "postprocessor", ex.StackTrace); } }
/// <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> /// Gets the entire list of suggested methods /// </summary> /// <returns></returns> public IEnumerable <MethodSignatureSequence> GetSuggestedMethodSequences(PexMeDynamicDatabase pmd) { var uniqueSequenceList = new List <MethodSignatureSequence>(); //Gather all sequences among all location stores. Detect the unique //sequences among them and suggest the complete unique sequences foreach (var pucls in this.locationStoreSpecificSequences.Values) { if (pucls.IsDormat()) { continue; } foreach (var ms in pucls.SuggestedMethodSequences) { if (ms.Sequence.Count == 0) { continue; } if (!uniqueSequenceList.Contains(ms)) { uniqueSequenceList.Add(ms); } } } //Return all final sequence ever collected to help cover more //at the first time itself. Along with the final suggested method, //we also need to add the method itself foreach (var methodid in this.FinalSuggestedMethodSequences.Keys) { var seqlist = this.FinalSuggestedMethodSequences[methodid]; foreach (var seq in seqlist.SequenceList) { MethodSignatureSequence tempseq = new MethodSignatureSequence(); tempseq.Sequence.AddRange(seq.Sequence); tempseq.Sequence.Add(methodid); if (!uniqueSequenceList.Contains(tempseq)) { uniqueSequenceList.Add(tempseq); } } } foreach (var seqlist in this.FinalSuggestedMethodSequences.Values) { foreach (var seq in seqlist.SequenceList) { if (seq.Sequence.Count == 0) { continue; } if (!uniqueSequenceList.Contains(seq)) { uniqueSequenceList.Add(seq); } } } //Return all previously collected sequences for this PUT, if there exist //no sequences specific to any uncovered location yet. var putsignature = MethodOrFieldAnalyzer.GetMethodSignature(pmd.CurrentPUTMethod); MethodSignatureSequenceList mssl; if (this.FinalPUTSequences.TryGetValue(putsignature, out mssl)) { foreach (var seq in mssl.SequenceList) { if (seq.Sequence.Count == 0) { continue; } if (!uniqueSequenceList.Contains(seq)) { uniqueSequenceList.Add(seq); } } } foreach (var ms in uniqueSequenceList) { yield return(ms); } }