/// <summary> /// Gets the operation for the object being created that is being referenced by <paramref name="operation"/>. /// If the operation is referencing an implicit or an explicit this/base/Me/MyBase/MyClass instance, then we return "null". /// </summary> /// <param name="operation"></param> /// <param name="isInsideObjectInitializer">Flag to indicate if the operation is a descendant of an <see cref="IObjectOrCollectionInitializerOperation"/> or an <see cref="IAnonymousObjectCreationOperation"/>.</param> /// <remarks> /// PERF: Note that the parameter <paramref name="isInsideObjectInitializer"/> is to improve performance by avoiding walking the entire IOperation parent for non-initializer cases. /// </remarks> public static IOperation GetInstance(this IInstanceReferenceOperation operation, bool isInsideObjectInitializer) { Debug.Assert(isInsideObjectInitializer == (operation.GetAncestor <IObjectOrCollectionInitializerOperation>(OperationKind.ObjectOrCollectionInitializer) != null || operation.GetAncestor <IAnonymousObjectCreationOperation>(OperationKind.AnonymousObjectCreation) != null)); if (isInsideObjectInitializer) { for (IOperation current = operation; current != null && current.Kind != OperationKind.Block; current = current.Parent) { switch (current.Kind) { // VB object initializer allows accessing the members of the object being created with "." operator. // The syntax of such an IInstanceReferenceOperation points to the object being created. // Check for such an IObjectCreationOperation or IAnonymousObjectCreationOperation with matching syntax. // For example, instance reference for members ".Field1" and ".Field2" in "New C() With { .Field1 = 0, .Field2 = .Field1 }". case OperationKind.ObjectCreation: case OperationKind.AnonymousObjectCreation: if (current.Syntax == operation.Syntax) { return(current); } break; // IInstanceReferenceOperation on left of an IMemberInitializerOperation refers to the ancestor IObjectCreationOperation/IAnonymousObjectCreationOperation/IMemberInitializerOperation. // For example, implicit instance reference for member initializer "AnotherType" in "new C() { AnotherType = { IntField = 0 } };", where "AnotherType" is a member of named type kind. case OperationKind.MemberInitializer: var parentMemberInitializer = (IMemberInitializerOperation)current; if (parentMemberInitializer.InitializedMember.DescendantsAndSelf().Contains(operation)) { return(parentMemberInitializer.GetCreation()); } break; // IInstanceReferenceOperation on left of an ISimpleAssignmentOperation with an IObjectOrCollectionInitializerOperation parent refers to the parenting IObjectCreationOperation/IAnonymousObjectCreationOperation/IMemberInitializerOperation. // For example, implicit instance reference for "IntField" in "new C() { IntField = 0 };". case OperationKind.SimpleAssignment: var parentSimpleAssignmentInitialier = (ISimpleAssignmentOperation)current; if (parentSimpleAssignmentInitialier.Parent is IObjectOrCollectionInitializerOperation && parentSimpleAssignmentInitialier.Target.DescendantsAndSelf().Contains(operation)) { return(parentSimpleAssignmentInitialier.Parent.Parent); } break; } } } // For all other cases, IInstanceReferenceOperation refers to the implicit or explicit this/base/Me/MyBase/MyClass reference. // We return null for such cases. return(null); }
/// <summary> /// Gets the operation for the object being created that is being referenced by <paramref name="operation"/>. /// If the operation is referencing an implicit or an explicit this/base/Me/MyBase/MyClass instance, then we return "null". /// </summary> public static IOperation GetInstance(this IInstanceReferenceOperation operation) { // VB object initializer allows accessing the members of the object being created with "." operator. // The syntax of such an IInstanceReferenceOperation points to the object being created. // Check for such an IObjectCreationOperation or IAnonymousObjectCreationOperation with matching syntax. // For example, instance reference for members ".Field1" and ".Field2" in "New C() With { .Field1 = 0, .Field2 = .Field1 }". Func <IObjectCreationOperation, bool> isObjectCreation = creation => creation.Syntax == operation.Syntax; var objectCreation = operation.GetAncestor(OperationKind.ObjectCreation, isObjectCreation); if (objectCreation != null) { return(objectCreation); } Func <IAnonymousObjectCreationOperation, bool> isAnonymousObjectCreation = creation => creation.Syntax == operation.Syntax; var anonymousObjectCreation = operation.GetAncestor(OperationKind.AnonymousObjectCreation, isAnonymousObjectCreation); if (anonymousObjectCreation != null) { return(anonymousObjectCreation); } // IInstanceReferenceOperation on left of an IMemberInitializerOperation refers to the ancestor IObjectCreationOperation/IAnonymousObjectCreationOperation/IMemberInitializerOperation. // For example, implicit instance reference for member initializer "AnotherType" in "new C() { AnotherType = { IntField = 0 } };", where "AnotherType" is a member of named type kind. IMemberInitializerOperation parentMemberInitializer = operation.GetAncestor <IMemberInitializerOperation>(OperationKind.MemberInitializer); if (parentMemberInitializer != null && parentMemberInitializer.InitializedMember.DescendantsAndSelf().Contains(operation)) { return(parentMemberInitializer.GetCreation()); } // IInstanceReferenceOperation on left of an ISimpleAssignmentOperation with an IObjectOrCollectionInitializerOperation parent refers to the parenting IObjectCreationOperation/IAnonymousObjectCreationOperation/IMemberInitializerOperation. // For example, implicit instance reference for "IntField" in "new C() { IntField = 0 };". ISimpleAssignmentOperation parentSimpleAssignmentInitialier = operation.GetAncestor <ISimpleAssignmentOperation>(OperationKind.SimpleAssignment); if (parentSimpleAssignmentInitialier != null && parentSimpleAssignmentInitialier.Parent is IObjectOrCollectionInitializerOperation && parentSimpleAssignmentInitialier.Target.DescendantsAndSelf().Contains(operation)) { return(parentSimpleAssignmentInitialier.Parent.Parent); } // For all cases, IInstanceReferenceOperation refers to the implicit or explicit this/base/Me/MyBase/MyClass reference. // We return null for such cases. return(null); }