/// <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> /// 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> /// Targets to remove those sequences with low or the same fitness /// </summary> /// <param name="ucovLocList"></param> /// <param name="persistentUncoveredLocationStore"></param> private void RemoveSuggestionsWithLowFitness(UncoveredCodeLocationStoreList ucovLocList, PersistentUncoveredLocationStore pucls, List <MethodSignatureSequence> putspecificsequences) { pucls.NumberOfUnsuccessfulAttempts++; int bestFitness = pucls.Fitnessvalue; foreach (var ucovloc in ucovLocList.StoreList) { if (ucovloc.Fitnessvalue < bestFitness) { bestFitness = ucovloc.Fitnessvalue; } } var explorableType = ucovLocList.ExplorableType; var tempSuggestedSequences = new List <MethodSignatureSequence>(); tempSuggestedSequences.AddRange(pucls.SuggestedMethodSequences); //remove those suggestions that have lower fitness values foreach (var ucovloc in ucovLocList.StoreList) { //Get matching sequence from pucls MethodSignatureSequence matchingseq; if (!FactorySuggestionStore.TryGetMatchingSequence(ucovloc.MethodCallSequence, tempSuggestedSequences, out matchingseq)) { //This sequence is not there in our suggested sequence. This should have happened //due to the case that it came from other uncovered location stores, and is helping //the current store. if (ucovloc.Fitnessvalue <= bestFitness) { var mss = new MethodSignatureSequence(); 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); } if (mss.Sequence.Count > 0) { pucls.SuggestedMethodSequences.Add(mss); } } continue; } tempSuggestedSequences.Remove(matchingseq); if (ucovloc.Fitnessvalue > bestFitness) { //Previous sequence is of no use as it is leading to higher fitness value pucls.SuggestedMethodSequences.Remove(matchingseq); } } if (tempSuggestedSequences.Count != 0) { //Not all sequences are assigned fitness values. Raise warnings for other sequences this.Log.LogWarning(WikiTopics.MissingWikiTopic, "sequencematching", "Fitness values are not available for some previous sequences, Needs to handle this case!!!"); //Remove those suggestions whose fitness value is not evaluated at all. Ideally //this case should not happen. Needs additional debugging. //foreach (var seq in tempSuggestedSequences) // pucls.SuggestedMethodSequences.Remove(seq); } //Update the previous fitness value with the current. If there is any improvement in the fitness, reset the number //of unsuccessful attempts if (pucls.Fitnessvalue != bestFitness) { pucls.NumberOfUnsuccessfulAttempts = 0; pucls.Fitnessvalue = bestFitness; } }