/// <summary>
        /// Checks whether a given method is an observer or not
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        public bool IsAnObserver(Method method)
        {
            TypeEx declaringType;

            if (!method.TryGetDeclaringType(out declaringType))
            {
                return(false);
            }

            MethodEffects me;

            if (!MethodOrFieldAnalyzer.TryComputeMethodEffects(this, declaringType, method,
                                                               null, out me))
            {
                return(false);
            }

            if (me.WrittenInstanceFields.Count == 0)
            {
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Gets the set of write methods associated with a field in the given type
        /// </summary>
        /// <param name="field"></param>
        /// <returns></returns>
        public bool TryGetWriteMethods(Field field, TypeEx declaringType, out SafeSet <Method> writeMethods)
        {
            SafeDebug.AssumeNotNull(field, "field");
            SafeDebug.AssumeNotNull(declaringType, "declaringType");

            //Declaring type should include defintinion
            if (declaringType == null || declaringType.Definition == null)
            {
                this.Log.LogWarning(WikiTopics.MissingWikiTopic, "WriteMethods",
                                    "Missing definition for the declaring type " + declaringType.FullName);
                writeMethods = null;
                return(false);
            }

            FieldStore fs;

            if (this.FieldDictionary.TryGetValue(field, out fs))
            {
                if (fs.WriteMethods.TryGetValue(declaringType, out writeMethods))
                {
                    return(true);
                }
                else
                {
                    writeMethods = new SafeSet <Method>();
                    fs.WriteMethods[declaringType] = writeMethods;
                }
            }
            else
            {
                fs           = new FieldStore();
                fs.FieldName = field;
                writeMethods = new SafeSet <Method>();
                fs.WriteMethods[declaringType] = writeMethods;
                this.FieldDictionary[field]    = fs;
            }

            foreach (MethodDefinition instanceMethod in declaringType.Definition.DeclaredInstanceMethods)
            {
                //Ignore abstract methods
                if (instanceMethod.IsAbstract)
                {
                    continue;
                }

                //If the DISABLE_CALLING_METHODS_WITHIN_CLASS is set to true, then private methods need not be considered
                //since they will be filtered out.
                if (PexMeConstants.DISABLE_CALLING_METHODS_WITHIN_CLASS && instanceMethod.DeclaredVisibility == Visibility.Private)
                {
                    continue;
                }

                Method        method = instanceMethod.Instantiate(declaringType.GenericTypeArguments, MethodOrFieldAnalyzer.GetGenericMethodParameters(this, instanceMethod));
                MethodEffects me;

                if (!MethodOrFieldAnalyzer.TryComputeMethodEffects(this, declaringType, method, null, out me))
                {
                    this.Log.LogWarning(WikiTopics.MissingWikiTopic, "methodeffects",
                                        "Failed to get the method effects for method " + method);
                    continue;
                }

                if (me.WrittenInstanceFields.Contains(field.ShortName))
                {
                    writeMethods.Add(method);
                }

                FieldModificationType fmt;
                if (me.ModificationTypeDictionary.TryGetValue(field.ShortName, out fmt))
                {
                    fs.ModificationTypeDictionary[method] = fmt;
                }
            }

            //Check whether there are any private methods in calling methods.
            //If yes, replace them with their callers.
            if (!PexMeConstants.DISABLE_CALLING_METHODS_WITHIN_CLASS)
            {
                var newWriteMethods = new SafeSet <Method>();
                GetCallingMethods(field, declaringType, writeMethods, newWriteMethods);

                writeMethods.Clear();
                writeMethods.AddRange(newWriteMethods);
            }

            TypeEx baseType = declaringType.BaseType;

            if (baseType != null && baseType.FullName != "System.Object")
            {
                SafeSet <Method> innerWriteMethods;
                this.TryGetWriteMethods(field, baseType, out innerWriteMethods);
                if (innerWriteMethods != null)
                {
                    writeMethods.AddRange(innerWriteMethods);
                }
            }

            return(true);
        }
        /// <summary>
        /// Gets calling methods of a given called method on the given field in a given target type
        /// </summary>
        /// <returns></returns>
        public bool TryGetCallingMethodsInType(Method calledMethod, Field field, TypeEx targetType, out SafeSet <Method> callingMethods)
        {
            SafeDebug.AssumeNotNull(calledMethod, "method");
            SafeDebug.AssumeNotNull(targetType, "type");

            //Get the associated property of the field
            Property property;

            if (!MethodOrFieldAnalyzer.TryGetPropertyReadingField(this, targetType, field, out property))
            {
                //TODO: error;
            }

            MethodStore mstore = null;

            if (this.MethodDictionary.TryGetValue(calledMethod, out mstore))
            {
                if (mstore.CallingMethods.TryGetValue(targetType, out callingMethods))
                {
                    return(true);
                }
            }

            //No method store found. create a fresh one
            if (mstore == null)
            {
                mstore            = new MethodStore();
                mstore.methodName = calledMethod;
                this.MethodDictionary[calledMethod] = mstore;
            }

            callingMethods = new SafeSet <Method>();
            mstore.CallingMethods[targetType] = callingMethods;
            TypeEx calledMethodType;

            if (!calledMethod.TryGetDeclaringType(out calledMethodType))
            {
                this.Log.LogError(WikiTopics.MissingWikiTopic, "callingmethods",
                                  "Failed to get the declaring type for the method " + calledMethod.FullName);
                return(false);
            }

            //Needs to addess the array type issue over here.
            var targetdef = targetType.Definition;

            if (targetdef == null)
            {
                if (targetType.TypeKind != TypeKind.SzArrayElements)
                {
                    this.Log.LogError(WikiTopics.MissingWikiTopic, "callingmethods",
                                      "The definition for the type " + targetType.FullName + " is null");
                    return(false);
                }
                else
                {
                    targetdef = targetType.ElementType.Definition;
                }
            }

            //Analyze each method in the given type to identify the calling methods
            //of the given method
            foreach (var typeMethod in targetdef.DeclaredInstanceMethods)
            {
                Method minstance = typeMethod.Instantiate(targetType.GenericTypeArguments, MethodOrFieldAnalyzer.GetGenericMethodParameters(this, typeMethod));

                MethodEffects meffects;
                if (!MethodOrFieldAnalyzer.TryComputeMethodEffects(this, targetType, minstance, null, out meffects))
                {
                    continue;
                }

                //Check for a direct comparison
                if (meffects.DirectCalledMethods.Contains(calledMethod))
                {
                    callingMethods.Add(minstance);
                }
                else
                {
                    //Use vtable lookup for addressing the abstract issues
                    foreach (var dcallMethod in meffects.DirectCalledMethods)
                    {
                        if (dcallMethod.IsConstructor)
                        {
                            continue;
                        }

                        TypeEx dcallMethodType;
                        if (dcallMethod.TryGetDeclaringType(out dcallMethodType))
                        {
                            if (dcallMethodType == calledMethodType || !dcallMethodType.IsAbstract || !dcallMethodType.IsInterface)
                            {
                                continue;
                            }

                            if (!dcallMethodType.IsAssignableTo(calledMethodType) && !calledMethodType.IsAssignableTo(dcallMethodType))
                            {
                                continue;
                            }
                        }

                        try
                        {
                            var lookupMethod = calledMethodType.VTableLookup(dcallMethod);
                            if (lookupMethod != null && calledMethod == lookupMethod)
                            {
                                callingMethods.Add(minstance);
                                break;
                            }
                        }
                        catch (Exception ex)
                        {
                            this.Log.LogWarningFromException(ex, WikiTopics.MissingWikiTopic,
                                                             "vtablelookup", "Failed to perform vtablelookup for " + dcallMethod.FullName + " in type " + calledMethodType.FullName);
                        }
                    }
                }
            }

            //Check whether there are any private methods in calling methods.
            //If yes, replace them with their callers.
            if (!PexMeConstants.DISABLE_CALLING_METHODS_WITHIN_CLASS)
            {
                var newCallingMethods = new SafeSet <Method>();
                foreach (var callingM in callingMethods)
                {
                    if (callingM.Definition.DeclaredVisibility != Visibility.Private || callingM.IsConstructor)
                    {
                        newCallingMethods.Add(callingM);
                        continue;
                    }

                    //Get other calling methods within this type
                    SafeSet <Method> localCM;
                    if (this.TryGetCallingMethodsInType(callingM, field, targetType, out localCM))
                    {
                        newCallingMethods.AddRange(localCM);
                    }
                }

                callingMethods.Clear();
                callingMethods.AddRange(newCallingMethods);
            }

            //Needs to further analyze parent types
            TypeEx baseType = targetType.BaseType;

            if (baseType != null && baseType.FullName != "System.Object")   //TODO: Avoid string comparisons. needs to figure out how to do that
            {
                SafeSet <Method> baseCallingMethods;
                TryGetCallingMethodsInType(calledMethod, field, baseType, out baseCallingMethods);
                callingMethods.AddRange(baseCallingMethods);
            }

            return(true);
        }