/// <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;
        }
Exemplo n.º 2
0
        /// <summary>
        /// scans the assembly and identifies all MSeqGen generated factory methods
        /// </summary>
        /// <returns></returns>
        public void LoadExplorableCandidates()
        {
            var pmd = this.GetService <PexMeDynamicDatabase>();
            var fss = pmd.FactorySuggestionsDictionary;

            foreach (var tdef in this.currAssembly.TypeDefinitions)
            {
                if (!tdef.ShortName.EndsWith(MSeqGenConstants.FACTORY_CLASS_SUFFIX))
                {
                    continue;
                }

                foreach (var mdef in tdef.DeclaredStaticMethods)
                {
                    PexExplorableFactory originalExplorableFactory = null;
                    TypeEx retTypeEx = null;
                    try
                    {
                        var retType = mdef.ResultType;

                        if (!MethodOrFieldAnalyzer.TryGetTypeExFromName(this, this.currAssembly, retType.ToString(), out retTypeEx))
                        {
                            this.Log.LogWarning(WikiTopics.MissingWikiTopic, "MSeqGenRecommender", "Failed to set typeex for " + retType.ToString());
                            continue;
                        }

                        //var retTypeEx = MetadataFromReflection.GetType(retType.GetType());
                        var methodEx = mdef.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(this, retTypeEx.Definition),
                                                        MethodOrFieldAnalyzer.GetGenericMethodParameters(this, mdef));

                        var result = PexExplorableFactory.TryGetExplorableFactory(this, retTypeEx, out originalExplorableFactory);
                        if (result == false)
                        {
                            this.Log.LogWarning(WikiTopics.MissingWikiTopic, "MSeqGenRecommender", "Failed to set create explorable for " + retTypeEx.FullName);
                            continue;
                        }

                        //add constructor
                        if (!originalExplorableFactory.TrySetFactoryMethod(methodEx))
                        {
                            this.Log.LogWarning(WikiTopics.MissingWikiTopic, "MSeqGenRecommender", "Failed to set factory method for " + mdef.FullName);
                            continue;
                        }
                    }
                    catch (Exception ex)
                    {
                        this.Log.LogError(WikiTopics.MissingWikiTopic, "MSeqGenRecommender", "Error occurred while parsing MSeqGen factories " + ex.Message);
                    }

                    if (originalExplorableFactory == null)
                    {
                        continue;
                    }

                    IPexExplorable originalExplorable1 = originalExplorableFactory.CreateExplorable();
                    CodeUpdate.AddMethodCodeUpdate originalPreviewUpdate1;
                    CodeUpdate originalUpdate1 = originalExplorableFactory.CreateExplorableFactoryUpdate(out originalPreviewUpdate1);
                    this.AddToRecommendedFactories(retTypeEx.FullName, new PexExplorableCandidate(originalExplorable1, false, originalUpdate1));
                }
            }
        }