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); } }
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); } }
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))); }
/// <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); } }
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()); } }
/// <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); } }