예제 #1
0
        protected override void Load(Microsoft.ExtendedReflection.ComponentModel.IContainer container)
        {
            this.pmd = new PexMeDynamicDatabase();
            container.AddComponent(null, pmd);

            this.psd = new PexMeStaticDatabase();
            container.AddComponent(null, psd);

            if (PexMeConstants.ENABLE_MSEQGEN_RECOMMENDER)
            {
                mseqgen = new MSeqGenRecommender();
                container.AddComponent(null, mseqgen);
            }

            base.Load(container);
        }
        /// <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;
        }