protected override IEnumerable <IValueEntity> GetChildren(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { // GetChildren is always called with evaluation enabled (e.g. to calculate IEnumerable's "Results" node). // If the user has disabled "Allow property evaluation..." we shouldn't show the "Scene Path" item. // Ideally, we should add it with a "Refresh" link to calculate it if required. This involves returning a // reference to calculate the value rather than calculating it eagerly. // TODO: Make "Scene Path" lazy in 212 if (mySession.EvaluationOptions.AllowTargetInvoke) { var scenePathValue = ScenePathValueHelper.GetScenePathValue(valueRole, options, ValueServices, Logger); if (scenePathValue != null) { yield return(scenePathValue); } } yield return(new GameObjectComponentsGroup(valueRole, ValueServices, Logger)); yield return(new GameObjectChildrenGroup(valueRole, ValueServices, Logger)); foreach (var valueEntity in base.GetChildren(valueRole, instanceType, options, dataHolder, token)) { yield return(valueEntity); } }
public override bool IsApplicable(IValueRole <TValue> role, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder) { return(myUnityOptions.ExtensionsEnabled && role.ValueReference is ExtraDetailValueReferenceDecorator <TValue>); }
private bool TryCacheDebuggerDisplay(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IUserDataHolder userDataHolder) { // Special case. Replace with a second dictionary or whatever if we need to handle more types if (valueRole.ValueReference is NamedReferenceDecorator <TValue> reference && reference.IsNameFromValue && instanceType.FullName == "UnityEngine.GameObject") { userDataHolder.PutData(ourDebuggerDisplayStringKey, GameObjectDebuggerDisplayStringWithoutName); return(true); } // DebuggerDisplayAttribute is inherited. This is important for applying a debug string on Behaviour, and // having it used in custom MonoBehaviour classes var current = instanceType; while (current != null) { if (myDebuggerDisplayValues.TryGetValue(current.GetGenericTypeDefinition().FullName, out var displayString)) { userDataHolder.PutData(ourDebuggerDisplayStringKey, displayString); return(true); } current = current.BaseType; } return(false); }
protected override IEnumerable <IValueEntity> GetChildren(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { // GetChildren is passed options that always allow evaluation, e.g. to calculate IEnumerable's "Results" // node. We eagerly evaluate Scene Path here, we should return a lazy reference to allow evaluating during // presentation, so that we get the "Refresh" link if the user has disabled evaluation // TODO: Make "Scene Path" lazy in 212 if (mySession.EvaluationOptions.AllowTargetInvoke) { // Only add "Scene Path" to the most derived type, not every "base" node back to Component var valueType = valueRole.ValueReference.GetValueType(options, ValueServices.ValueMetadataProvider); if (valueType.Equals(instanceType)) { var scenePathValue = GetGameObjectScenePath(valueRole, options); if (scenePathValue != null) { yield return(scenePathValue); } } } foreach (var valueEntity in base.GetChildren(valueRole, instanceType, options, dataHolder, token)) { yield return(valueEntity); } }
public override bool IsApplicable(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder) { return(myUnityOptions.ExtensionsEnabled && instanceType.Is("UnityEditor.SerializedProperty")); }
protected override bool IsApplicable(IMetadataTypeLite type, IPresentationOptions options, IUserDataHolder dataHolder) { // Check debugger type proxy settings to avoid recursion while rendering Raw View. See GetChildren return(myUnityOptions.ExtensionsEnabled && options.EvaluateDebuggerTypeProxy && type.Is("UnityEditor.SerializedProperty")); }
public override bool IsApplicable(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder) { // Note that DebuggerDisplayObjectPresenter checks options.AllowTargetInvoke here return(myUnityOptions.ExtensionsEnabled && options.AllowDebuggerDisplayEvaluation && TryCacheDebuggerDisplay(valueRole, instanceType.GetGenericTypeDefinition(), dataHolder)); }
protected override IEnumerable <IValueEntity> GetChildren(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { yield return(new ChildrenGroup(valueRole, ValueServices, myLogger)); }
public NamedReferenceDecorator(IValueReference <TValue> originalReference, [NotNull] string name, ValueOriginKind kind, [CanBeNull] IMetadataTypeLite declaredType, IValueRoleFactory <TValue> roleFactory) { myOriginalReference = originalReference; DefaultName = name; OriginKind = kind; DeclaredType = declaredType; myRoleFactory = roleFactory; }
protected override IEnumerable <IValueEntity> GetChildren(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { var references = EnumerateChildren(valueRole, options, token); references = FilterChildren(references); references = SortChildren(references); return(RenderChildren(valueRole, references, options, token)); }
protected override IEnumerable <IValueEntity> GetChildren(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { // GetRootGameObjects was introduced in Unity 5.3.2 var getRootObjectsMethod = valueRole.ReifiedType.MetadataType.GetMethods() .FirstOrDefault(ourGetRootGameObjectsSelector); if (getRootObjectsMethod != null) { yield return(new GameObjectsGroup(valueRole, getRootObjectsMethod, ValueServices, myLogger)); } }
protected override IEnumerable <IValueEntity> GetChildren(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { // Keep an eye on iterators and enumeration: we need to eagerly evaluate GetChildrenImpl so we can catch any // exceptions. The return value of GetChildren is eagerly evaluated, so we're not changing any semantics return(Logger.CatchEvaluatorException <TValue, IEnumerable <IValueEntity> >( () => GetChildrenImpl(valueRole, instanceType, options, dataHolder, token).ToList(), exception => Logger.LogThrownUnityException(exception, valueRole.ValueReference.OriginatingFrame, ValueServices, options)) ?? base.GetChildren(valueRole, instanceType, options, dataHolder, token)); }
public static IMetadataTypeLite FindTypeThroughHierarchy([NotNull] this IMetadataTypeLite metadataType, string fullClrName) { var current = metadataType; while (current != null) { if (current.Is(fullClrName)) { return(current); } current = current.BaseType; } return(null); }
public NamedReferenceDecorator(IValueReference <TValue> originalReference, [NotNull] string name, ValueOriginKind kind, ValueFlags flags, [CanBeNull] IMetadataTypeLite declaredType, IValueRoleFactory <TValue> roleFactory, bool isNameFromValue = false) { myOriginalReference = originalReference; DefaultName = name; OriginKind = kind; DefaultFlags = flags; DeclaredType = declaredType; myRoleFactory = roleFactory; IsNameFromValue = isNameFromValue; }
protected override IEnumerable <IValueEntity> GetChildren(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { yield return(new GameObjectComponentsGroup(valueRole, ValueServices, myLogger)); // The children of the current GameObject (as seen in Unity's Hierarchy view) are actually the children of // GameObject.transform. This should never be null var transformProperty = valueRole.GetInstancePropertyReference("transform"); if (transformProperty != null) { yield return(new GameObjectChildrenGroup(transformProperty, ValueServices)); } }
// Return null to allow other providers a chance. If we throw EvaluatorException, it will be presented to the // user. OperationCancelledException will be logged and we move on to the next presenter. Any other exception // will leak public override IValuePresentation PresentValue(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { var debuggerDisplayString = dataHolder.GetData(ourDebuggerDisplayStringKey); try { var valueReference = valueRole.ValueReference; var thisObj = valueReference.GetValue(options); var evaluationOptions = valueReference.OriginatingFrame.DebuggerSession.Options.EvaluationOptions.Apply(options); // This can throw if there are members missing, which is entirely possible when debugging on a device, // due to stripping. It will throw EvaluatorException. Anything else is logged and thrown as a new // EvaluatorException. We can also get InvalidOperationException, but only if no other evaluators can // handle the current context, which is unlikely var displayString = ExpressionEvaluators.EvaluateDisplayString(valueReference.OriginatingFrame, thisObj, debuggerDisplayString, evaluationOptions, token); var flags = valueReference.DefaultFlags; if (valueReference is CalculatedValueReferenceDecorator <TValue> reference && !reference.AllowDefaultTypePresentation) { flags |= ValueFlags.IsDefaultTypePresentation; } return(SimplePresentation.CreateSuccess( ValuePresentationPart.Default(DisplayStringUtil.EscapeString(displayString)), flags, instanceType, displayString)); } catch (Exception ex) { // Log as warning, not error - there's nothing the user can do, and we're likely to encounter this with // device builds myLogger.Warn(ex, comment: $"Unable to evaluate debugger display string for type {instanceType.GetGenericTypeDefinition().FullName}: {debuggerDisplayString}. " + "Expected behaviour on devices due to stripping"); return(null); } }
public override IValuePresentation PresentValue(IValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { var extraDetail = (ExtraDetailValueReferenceDecorator <TValue>)valueRole.ValueReference; var presentation = extraDetail.UnderlyingValueReference.ToValue(ValueServices).GetValuePresentation(options, token); if (presentation.ResultKind == ValueResultKind.Success) { var presentationBuilder = PresentationBuilder.New(presentation.Value.ToArray()) .Add(ValuePresentationPart.Space) .SpecialSymbol("(").Default(extraDetail.ExtraDetail).SpecialSymbol(")"); return(SimplePresentation.CreateSuccess(presentationBuilder.Result(), presentation.Flags, presentation.Type, presentation.PrimitiveValue)); } return(presentation); }
protected override IEnumerable <IValueEntity> GetChildren(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { var scenePathValue = ScenePathValueHelper.GetScenePathValue(valueRole, options, ValueServices, myLogger); if (scenePathValue != null) { yield return(scenePathValue); } yield return(new GameObjectComponentsGroup(valueRole, ValueServices, myLogger)); yield return(new GameObjectChildrenGroup(valueRole, ValueServices, myLogger)); foreach (var valueEntity in base.GetChildren(valueRole, instanceType, options, dataHolder, token)) { yield return(valueEntity); } }
protected override IEnumerable <IValueEntity> GetChildren(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { // Only add "Scene Path" to the most derived type, not every "base" node back to Component var valueType = valueRole.ValueReference.GetValueType(options, ValueServices.ValueMetadataProvider); if (valueType.Equals(instanceType)) { var scenePathValue = GetGameObjectScenePath(valueRole, options); if (scenePathValue != null) { yield return(scenePathValue); } } foreach (var valueEntity in base.GetChildren(valueRole, instanceType, options, dataHolder, token)) { yield return(valueEntity); } }
public override IValuePresentation PresentValue(IStringValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { // Present the value's string as plain text, without any syntax highlighting or quote handling. Don't use // ValueFlags.IsString, as it will add an unnecessary "View" link - our text is always short var text = valueRole.GetString(); return(SimplePresentation.CreateSuccess(ValuePresentationPart.Default(text), valueRole.ValueReference.DefaultFlags | ValueFlags.NoChildren, instanceType, text)); }
protected override bool IsApplicable(IMetadataTypeLite type, IPresentationOptions options, IUserDataHolder dataHolder) { return(type.Is("UnityEngine.GameObject")); }
protected override bool IsApplicable(IMetadataTypeLite type, IPresentationOptions options, IUserDataHolder dataHolder) { // UnityEngine.SceneManagement.Scene was introduced in Unity 5.3 return(type.Is("UnityEngine.SceneManagement.Scene")); }
protected override IEnumerable <IValueEntity> GetChildren(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { return(options.FlattenHierarchy ? EnumerateMembersFlat(valueRole, options, token, ValueServices) : EnumerateMembersWithBaseNode(valueRole, options, token, ValueServices)); }
protected override bool IsApplicable(IMetadataTypeLite type, IPresentationOptions options, IUserDataHolder dataHolder) { return(myUnityOptions.ExtensionsEnabled && type.FindTypeThroughHierarchy("UnityEngine.Component") != null); }
protected override bool IsApplicable(IObjectValueRole <TValue> role, IMetadataTypeLite type, IPresentationOptions options, IUserDataHolder dataHolder) { return(myUnityOptions.ExtensionsEnabled && type.Is("UnityEditor.SerializedObject")); }
private IEnumerable <IValueEntity> GetChildrenImpl(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { var enumValueObject = valueRole.GetInstancePropertyReference("propertyType") ?.AsObjectSafe(options)?.GetEnumValue(options); var propertyType = (SerializedPropertyKind)Enum.ToObject(typeof(SerializedPropertyKind), enumValueObject ?? SerializedPropertyKind.Invalid); // Fall back to showing everything if we don't have any special handling for the property type. This should // protect us if Unity introduces a new serialised property type. if (!myHandledPropertyTypes.Contains(propertyType)) { foreach (var valueEntity in base.GetChildren(valueRole, instanceType, options, dataHolder, token)) { yield return(valueEntity); } yield break; } var propertySpecificFields = myPerTypeFieldNames[propertyType]; var isArray = false; var isFixedBuffer = false; // Generic means a custom serializable struct, an array or a fixed buffer (public unsafe fixed int buf[10]) // Strings are also arrays, and have properties for each character. We'll show them too. if (propertyType == SerializedPropertyKind.Generic || propertyType == SerializedPropertyKind.String) { if (!Util.TryEvaluatePrimitiveProperty(valueRole, "isArray", options, out isArray) || !isArray) { Util.TryEvaluatePrimitiveProperty(valueRole, "isFixedBuffer", options, out isFixedBuffer); } } // We filter all non-public members, so make sure we don't show the group var effectiveOptions = options.WithOverridden(o => o.GroupPrivateMembers = false); var references = EnumerateChildren(valueRole, effectiveOptions, token); references = FilterChildren(references, propertySpecificFields, isArray, isFixedBuffer); references = DecorateChildren(valueRole, references, propertyType, options); references = SortChildren(references); foreach (var valueEntity in RenderChildren(valueRole, references, effectiveOptions, token)) { yield return(valueEntity); } if (!Util.TryEvaluatePrimitiveProperty(valueRole, "hasChildren", options, out bool hasChildren)) { Logger.Warn("Cannot evaluate hasChildren for serializedProperty"); } else if (hasChildren) { // Arrays, fixed buffer arrays and strings (which are arrays) all say they have children. They don't. // They have a special sibling (i.e. same depth) that can only be enumerated with Next(true), and is // skipped with Next(false). // We don't show these special siblings, because they're not children, and the data is already displayed // as part of the array/fixed buffer element group. // TODO: Should we show this? // It might be confusing if these special properties are never shown, especially if someone is using // the debugger to try to figure out the shape of the serialised stream. The question is, how do we show // something that is enumerated as a child, but stored as a sibling? The best solution is a dump of the // whole serialised stream, which is not what we're doing as part of the debugger. One solution would be // to add an "Array" node that is shown instead of "Children" - but that would still look like a child // node, and would only include the "Size" node over the existing array/fixed buffer element group. // For now, just ignore these special properties and leave it to the array/fixed buffer element group. if (!isArray && !isFixedBuffer && propertyType != SerializedPropertyKind.String) { yield return(new ChildrenGroup(valueRole, ValueServices, Logger)); } } if (isArray) { if (!Util.TryEvaluatePrimitiveProperty(valueRole, "arraySize", options, out int arraySize)) { Logger.Warn("Cannot evaluate arraySize for serializedProperty"); } else if (arraySize > 0) { yield return(new ArrayElementsGroup(valueRole, arraySize, MethodSelectors.SerializedProperty_GetArrayElementAtIndex, ValueServices, Logger)); } } else if (isFixedBuffer) { if (!Util.TryEvaluatePrimitiveProperty(valueRole, "fixedBufferSize", options, out int fixedBufferSize)) { Logger.Warn("Cannot evaluate fixedBufferSize for serializedProperty"); } else if (fixedBufferSize > 0) { yield return(new ArrayElementsGroup(valueRole, fixedBufferSize, MethodSelectors.SerializedProperty_GetFixedBufferElementAtIndex, ValueServices, Logger)); } } // Disable debugger type proxy options to avoid recursion. See IsApplicable. var rawViewOptions = options.WithOverridden(o => o.EvaluateDebuggerTypeProxy = false); yield return(new SimpleEntityGroup(PresentationOptions.RawViewGroupName, valueRole.ValueReference.ToValue(ValueServices).GetChildren(rawViewOptions, token))); }
public override IValuePresentation PresentValue(IStringValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { // Note that ValueFlags.IsString will add the "View" link to see a string in a popup. We don't need this var text = valueRole.GetString(); return(SimplePresentation.CreateSuccess(ValuePresentationPart.Default(text), valueRole.ValueReference.DefaultFlags | ValueFlags.NoChildren, instanceType, text)); }
public override IValuePresentation PresentValue(IObjectValueRole <TValue> valueRole, IMetadataTypeLite instanceType, IPresentationOptions options, IUserDataHolder dataHolder, CancellationToken token) { var showName = (valueRole.ValueReference as CalculatedValueReferenceDecorator <TValue>)?.AllowNameInValue ?? true; var showTypeName = (valueRole.ValueReference as CalculatedValueReferenceDecorator <TValue>) ?.AllowDefaultTypePresentation ?? true; var nameValuePresentation = valueRole.GetInstancePropertyReference("name")?.ToValue(ValueServices) ?.GetValuePresentation(options); var propertyTypeReference = valueRole.GetInstancePropertyReference("propertyType"); var propertyTypeValuePresentation = propertyTypeReference?.ToValue(ValueServices)?.GetValuePresentation(options); var propertyTypeEnumValueObject = propertyTypeReference?.AsObjectSafe(options)?.GetEnumValue(options); var propertyType = (SerializedPropertyKind)Enum.ToObject(typeof(SerializedPropertyKind), propertyTypeEnumValueObject ?? SerializedPropertyKind.Generic); int? arraySize = null; string arrayElementType = null; string genericType = null; if (propertyType == SerializedPropertyKind.Generic) { if (Util.TryEvaluatePrimitiveProperty(valueRole, "isArray", options, out bool isArray) && isArray) { arraySize = valueRole.GetInstancePropertyReference("arraySize")?.AsPrimitiveSafe(options) ?.GetPrimitive <int>(); arrayElementType = valueRole.GetInstancePropertyReference("arrayElementType")?.AsStringSafe(options)?.GetString(); } else if (Util.TryEvaluatePrimitiveProperty(valueRole, "isFixedBuffer", options, out bool isFixedBuffer) && isFixedBuffer) { arraySize = valueRole.GetInstancePropertyReference("fixedBufferSize")?.AsPrimitiveSafe(options) ?.GetPrimitive <int>(); arrayElementType = valueRole.GetInstancePropertyReference("arrayElementType")?.AsStringSafe(options)?.GetString(); } else { genericType = valueRole.GetInstancePropertyReference("type")?.AsStringSafe(options)?.GetString(); } } var valuePresentation = GetValuePresentation(valueRole, propertyType, options, out var extraDetail); var parts = PresentationBuilder.New(); parts.OpenBrace(); if (showName && nameValuePresentation != null) { parts.Comment("name: ").Add(nameValuePresentation.Value.ToArray()) .Add(ValuePresentationPart.Space); } parts.Comment("propertyType: "); if (propertyType == SerializedPropertyKind.Generic && arraySize != null && arrayElementType != null) { parts.Default($"{arrayElementType}[{arraySize}]"); } else if (genericType != null) { parts.Default(genericType); } else if (propertyTypeValuePresentation != null) { parts.Add(propertyTypeValuePresentation.Value.ToArray()); } else { parts.Comment("(Unknown)"); } if (valuePresentation != null) { parts.Add(ValuePresentationPart.Space) .Comment("value: ").Add(valuePresentation.Value.ToArray()); if (!string.IsNullOrEmpty(extraDetail)) { parts.Add(ValuePresentationPart.Space).SpecialSymbol("(").Default(extraDetail).SpecialSymbol(")"); } } parts.ClosedBrace(); // Hide the default type presentation if we've been asked to var flags = !showTypeName ? ValueFlags.IsDefaultTypePresentation : 0; return(SimplePresentation.Create(parts.Result(), ValueResultKind.Success, ValueFlags.None | flags, instanceType)); }