Beispiel #1
0
        public override void Visit(IArrayIndexer arrayIndexer)
        {
            if (arrayIndexer.Indices.Count() == 1 && Names.NameTable.ContainsKey(arrayIndexer.IndexedObject))
            {
                // the array expression, e.g.: this.array
                var arrayName = Names.NameTable[arrayIndexer.IndexedObject];
                // the contents expression, e.g.: this.array[..]
                var arrayContents = NameBuilder.FormElementsExpression(arrayName);

                // mark array indexes as compatible
                var index = arrayIndexer.Indices.First();
                if (Names.NameTable.ContainsKey(index))
                {
                    // The array reference may not have been used in a comparable way yet.
                    if (!ids.ContainsKey(arrayContents))
                    {
                        ids.Add(arrayContents, comparability.AddElement());
                    }

                    if (!collectionIndexes.ContainsKey(arrayContents))
                    {
                        collectionIndexes.Add(arrayContents, new HashSet <string>());
                    }

                    if (collectionIndexes[arrayContents].Add(Names.NameTable[index]))
                    {
                        // we haven't seen this index before, so re-mark indexes
                        Mark(collectionIndexes[arrayContents]);
                    }
                }

                PropogateTypeReference(arrayIndexer.IndexedObject, arrayIndexer);
            }
        }
Beispiel #2
0
        public override void Visit(IMethodCall call)
        {
            var receiver = call.ThisArgument;
            var callee   = call.MethodToCall.ResolvedMethod;

            // Form comparability information for Collection classes
            if (!call.IsStaticCall && Names.NameTable.ContainsKey(receiver))
            {
                HandleCollectionMethod(call);
                HandleDictionaryMethod(call);
            }

            if (NameBuilder.IsSetter(callee))
            {
                // For setters, mark the property name as comparable with the argument
                Mark(Expand(new[] { call, call.Arguments.First() }));
            }

            if (!(callee is Dummy || callee.Name is Dummy))
            {
                namedCalls.Add(call);
            }

            if (!call.IsStaticCall)
            {
                PropogateTypeReference(call.ThisArgument, call);
            }
        }
Beispiel #3
0
        private void ObjectInvariant()
        {
            Contract.Invariant(Names != null);
            Contract.Invariant(Method != null);
            Contract.Invariant(Host != null);
            Contract.Invariant(ReferencedTypes != null);
            Contract.Invariant(Contract.ForAll(namedCalls, c => Names.NameTable.ContainsKey(c)));
            Contract.Invariant(Contract.ForAll(collectionIndexes.Keys, a => ids.ContainsKey(a)));
            // Array Indexes should correspond to the array contents entry: e.g., this.array[..] not this.array
            Contract.Invariant(Contract.ForAll(collectionIndexes.Keys, a => NameBuilder.IsElementsExpression(a)));
            Contract.Invariant(Contract.ForAll(collectionIndexes.Values, i => i.Count > 0));

            // Not true b/c a name is added whenever comparability is queried by Celeriacs's IL visitors
            // Contract.Invariant(Contract.ForAll(ids.Keys, n => n.Equals("return") || Names.NameTable.ContainsValue(n)));
        }
Beispiel #4
0
        /// <summary>
        /// If the method call is a call to a Dictionary method, update the comparability information
        /// for keys and values.
        /// </summary>
        /// <remarks>
        ///   This uses <c>Key</c> and <c>Value</c> instead of <c>Keys</c> and <c>Values</c> since the declaration
        ///   printer uses <c>Key</c> and <c>Value</c> (it grabs it from the dictionary entry, as
        /// </remarks>
        /// <param name="call">the method call</param>
        private void HandleDictionaryMethod(IMethodCall call)
        {
            var receiver = call.ThisArgument;
            var callee   = call.MethodToCall.ResolvedMethod;

            var keys   = new List <IExpression>();
            var values = new List <IExpression>();

            var genericDef = TypeHelper.UninstantiateAndUnspecialize(receiver.Type);

            if (TypeHelper.TypesAreEquivalent(genericDef, Host.PlatformType.SystemCollectionsGenericDictionary, true))
            {
                if (callee.Name.Value.OneOf("Remove", "TryGetValue", "ContainsKey", "set_Item", "get_Item"))
                {
                    keys.Add(call.Arguments.First());
                }
                else if (callee.Name.Value.OneOf("Add"))
                {
                    keys.Add(call.Arguments.ElementAt(0));
                    values.Add(call.Arguments.ElementAt(1));
                }
            }

            var collectionName = Names.NameTable[receiver];
            var xs             = new [] {
                Tuple.Create(collectionName + ".Keys", keys),
                Tuple.Create(NameBuilder.FormElementsExpression(collectionName) + ".Key", keys),
                Tuple.Create(collectionName + ".Values", values),
                Tuple.Create(NameBuilder.FormElementsExpression(collectionName) + ".Value", values)
            };

            foreach (var x in xs.Where(c => c.Item2.Count > 0))
            {
                // The collection reference may not have been used in a comparable way yet.
                if (!ids.ContainsKey(x.Item1))
                {
                    ids.Add(x.Item1, comparability.AddElement());
                }

                var names = new List <string>();
                names.Add(x.Item1);
                names.AddRange(Names.Names(x.Item2));
                Mark(names);
            }
        }
Beispiel #5
0
        public MethodVisitor(IMethodDefinition method, IMetadataHost host, NameBuilder names)
        {
            Contract.Requires(method != null);
            Contract.Requires(names != null);
            Contract.Requires(host != null);
            Contract.Ensures(Names == names);
            Contract.Ensures(Method == method);
            Contract.Ensures(Host == host);

            Names           = names;
            Method          = method;
            Host            = host;
            ReferencedTypes = new Dictionary <IExpression, ITypeReference>();

            ids.Add("return", comparability.AddElement());

            foreach (var param in Method.Parameters)
            {
                ids.Add(param.Name.Value, comparability.AddElement());
            }
        }
Beispiel #6
0
        /// <summary>
        /// If the call is to a standard collection method, update the element and index comparability information
        /// </summary>
        /// <param name="call">the method call</param>
        private void HandleCollectionMethod(IMethodCall call)
        {
            var receiver = call.ThisArgument;
            var callee   = call.MethodToCall.ResolvedMethod;

            IExpression index    = null;
            var         elements = new List <IExpression>();

            foreach (var m in MemberHelper.GetImplicitlyImplementedInterfaceMethods(callee))
            {
                var genericDef = TypeHelper.UninstantiateAndUnspecialize(m.ContainingTypeDefinition);

                // IEnumerable does not define any methods that affect comparability

                // ICollection
                if (TypeHelper.TypesAreEquivalent(genericDef, Host.PlatformType.SystemCollectionsGenericICollection, true))
                {
                    if (m.Name.Value.OneOf("Add", "Remove", "Contains"))
                    {
                        elements.Add(call.Arguments.First());
                    }
                }

                // IList
                if (TypeHelper.TypesAreEquivalent(genericDef, Host.PlatformType.SystemCollectionsGenericIList, true))
                {
                    if (m.Name.Value.OneOf("IndexOf"))
                    {
                        elements.Add(call.Arguments.First());
                    }
                    else if (m.Name.Value.OneOf("get_Item", "set_Item", "RemoveAt"))
                    {
                        index = call.Arguments.First();
                    }
                    else if (m.Name.Value.OneOf("Insert"))
                    {
                        index = call.Arguments.ElementAt(0);
                        elements.Add(call.Arguments.ElementAt(1));
                    }
                }
            }

            if (index != null && Names.NameTable.ContainsKey(index))
            {
                var collectionName     = Names.NameTable[receiver];
                var collectionContents = NameBuilder.FormElementsExpression(collectionName);

                // The collection reference may not have been used in a comparable way yet.
                if (!ids.ContainsKey(collectionContents))
                {
                    ids.Add(collectionContents, comparability.AddElement());
                }

                if (!collectionIndexes.ContainsKey(collectionContents))
                {
                    collectionIndexes.Add(collectionContents, new HashSet <string>());
                }

                if (collectionIndexes[collectionContents].Add(Names.NameTable[index]))
                {
                    // we haven't seen this index before, so re-mark indexes
                    Mark(collectionIndexes[collectionContents]);
                }
            }

            if (elements.Count > 0)
            {
                var collectionName     = Names.NameTable[receiver];
                var collectionContents = NameBuilder.FormElementsExpression(collectionName);

                // The collection reference may not have been used in a comparable way yet.
                if (!ids.ContainsKey(collectionContents))
                {
                    ids.Add(collectionContents, comparability.AddElement());
                }

                var names = new List <string>();
                names.Add(collectionContents);
                names.AddRange(Names.Names(elements));
                Mark(names);
            }
        }