public static GetExpressionName ( DkmVisualizedExpression expression ) : string | ||
expression | DkmVisualizedExpression | |
return | string |
void IDkmCustomVisualizer.EvaluateVisualizedExpression(DkmVisualizedExpression expression, out DkmEvaluationResult resultObject) { Debug.Print("UE4PV: EvaluateVisualizedExpression('{0}'/'{1}', [{2}])", Utility.GetExpressionFullName(expression), Utility.GetExpressionName(expression), expression.TagValue ); // Sanity check to confirm this is only being invoked for UObject types. @TODO: Remove eventually. // Believe this method is only invoked on DkmRootVisualizedExpression instances, not children. Debug.Assert(expression.VisualizerId == Guids.Visualizer.UObject); UE4Visualizer visualizer = null; bool result = UE4VisualizerRegistrar.TryCreateVisualizer(expression, out visualizer); if (!result) { OnVisualizerMatchFailed(expression, out resultObject); return; } // Evaluate the visualization result DkmEvaluationResult eval = visualizer.EvaluationResult; resultObject = eval; // Associate the visualizer with the expression expression.SetDataItem <ExpressionDataItem>( DkmDataCreationDisposition.CreateAlways, new ExpressionDataItem(visualizer) ); }
void OnVisualizerMatchFailed(DkmVisualizedExpression expression, out DkmEvaluationResult result) { result = DkmFailedEvaluationResult.Create( expression.InspectionContext, expression.StackFrame, Utility.GetExpressionName(expression), Utility.GetExpressionFullName(expression), String.Format("UE4PropVis: No visualizer is registered for VisualizerId {0}", expression.VisualizerId), DkmEvaluationResultFlags.Invalid, null ); }
void IDkmCustomVisualizer.GetChildren(DkmVisualizedExpression expression, int initialRequestSize, DkmInspectionContext inspectionContext, out DkmChildVisualizedExpression[] initialChildren, out DkmEvaluationResultEnumContext enumContext) { Debug.Print("UE4PV: GetChildren('{0}'/'{1}', [{2}, {3}])", Utility.GetExpressionFullName(expression), Utility.GetExpressionName(expression), expression.TagValue, expression.VisualizerId ); var data_item = expression.GetDataItem <ExpressionDataItem>(); var visualizer = data_item.Visualizer; Debug.Assert(visualizer != null); visualizer.PrepareExpansion(out enumContext); initialChildren = new DkmChildVisualizedExpression[0]; }
void IDkmCustomVisualizer.UseDefaultEvaluationBehavior(DkmVisualizedExpression expression, out bool useDefaultEvaluationBehavior, out DkmEvaluationResult defaultEvaluationResult) { Debug.Print("UE4PV: UseDefaultEvaluationBehavior('{0}'/'{1}', [{2}, {3}])", Utility.GetExpressionFullName(expression), Utility.GetExpressionName(expression), expression.TagValue, expression.VisualizerId ); if (KUE4VS.ExtContext.Instance.ExtensionOptions.EnablePropVis) { var data_item = expression.GetDataItem <ExpressionDataItem>(); if (data_item != null) { Debug.Assert(data_item.Visualizer != null); if (data_item.Visualizer.WantsCustomExpansion) { useDefaultEvaluationBehavior = false; defaultEvaluationResult = null; return; } } } // Don't need any special expansion, just delegate back to the default EE useDefaultEvaluationBehavior = true; /* @NOTE: * Not sure where exactly the problem is, but UObject properties don't expand in VS 2013. * When we try, there is an initial call to this method with the property's child expr, * so we come here, and do a default eval, which, if the prop is a UObject, will invoke * EvaluateVisualizedExpression above with a new root expr. In 2015, that is followed by * another call to this method for the root expr, which has an attached visualizer and we * do the custom expansion. In 2013, it seems the second call into this method does not * occur for some reason. */ defaultEvaluationResult = DefaultEE.DefaultEval(expression, false); /* * Doing this will crash VS! * DkmSuccessEvaluationResult.Create(null, null, "", "", DkmEvaluationResultFlags.None, * "", "", "", DkmEvaluationResultCategory.Other, DkmEvaluationResultAccessType.None, * DkmEvaluationResultStorageType.None, DkmEvaluationResultTypeModifierFlags.None, * null, null, null, null); */ }
void IDkmCustomVisualizer.EvaluateVisualizedExpression(DkmVisualizedExpression expression, out DkmEvaluationResult resultObject) { if (KUE4VS.ExtContext.Instance.ExtensionOptions.EnablePropVis == false) { /* var LangExpr = DkmLanguageExpression.Create(DefaultEE.CppLanguage, DkmEvaluationFlags.None, Utility.GetExpressionFullName(expression), null); * expression.EvaluateExpressionCallback(expression.InspectionContext, LangExpr, expression.StackFrame, out resultObject); * return; */ resultObject = null; return; } Debug.Print("UE4PV: EvaluateVisualizedExpression('{0}'/'{1}', [{2}])", Utility.GetExpressionFullName(expression), Utility.GetExpressionName(expression), expression.TagValue ); // Sanity check to confirm this is only being invoked for UObject types. @TODO: Remove eventually. // Believe this method is only invoked on DkmRootVisualizedExpression instances, not children. Debug.Assert(expression.VisualizerId == Guids.Visualizer.UObject); UE4Visualizer visualizer = null; bool result = UE4VisualizerRegistrar.TryCreateVisualizer(expression, out visualizer); if (!result) { OnVisualizerMatchFailed(expression, out resultObject); return; } // Evaluate the visualization result DkmEvaluationResult eval = visualizer.EvaluationResult; resultObject = eval; // Associate the visualizer with the expression expression.SetDataItem <ExpressionDataItem>( DkmDataCreationDisposition.CreateAlways, new ExpressionDataItem(visualizer) ); }
void IDkmCustomVisualizer.UseDefaultEvaluationBehavior(DkmVisualizedExpression expression, out bool useDefaultEvaluationBehavior, out DkmEvaluationResult defaultEvaluationResult) { Debug.Print("UE4PV: UseDefaultEvaluationBehavior('{0}'/'{1}', [{2}, {3}])", Utility.GetExpressionFullName(expression), Utility.GetExpressionName(expression), expression.TagValue, expression.VisualizerId ); var data_item = expression.GetDataItem <ExpressionDataItem>(); if (data_item != null) { Debug.Assert(data_item.Visualizer != null); if (data_item.Visualizer.WantsCustomExpansion) { useDefaultEvaluationBehavior = false; defaultEvaluationResult = null; return; } } // Don't need any special expansion, just delegate back to the default EE useDefaultEvaluationBehavior = true; /* @NOTE: * Not sure where exactly the problem is, but UObject properties don't expand in VS 2013. * When we try, there is an initial call to this method with the property's child expr, * so we come here, and do a default eval, which, if the prop is a UObject, will invoke * EvaluateVisualizedExpression above with a new root expr. In 2014, that is followed by * another call to this method for the root expr, which has an attached visualizer and we * do the custom expansion. In 2013, it seems the second call into this method does not * occur for some reason. */ defaultEvaluationResult = DefaultEE.DefaultEval(expression, false); }
protected void EvaluateExpressionResult() { // We're going to customize the unexpanded display string, as well as the expanded // view (if requested later). // @TODO: Really don't understand why, but when we invoke the default eval below, and we get // reentrant calls for child member UObjects, they are coming back as root expressions // with an empty FullName. This subsequently fails to evaluate if we pass it through to // default eval again. Perhaps this is somehow related to breaking the potential infinite // recursion of visualizing children in order to visualize the parent, but don't follow how it // it supposed to be dealt with. if (expression_.TagValue == DkmVisualizedExpression.Tag.RootVisualizedExpression) { var as_root = expression_ as DkmRootVisualizedExpression; if (as_root.FullName.Length == 0) { string display_str = "{...}"; eval_ = DkmSuccessEvaluationResult.Create( expression_.InspectionContext, expression_.StackFrame, as_root.Name, as_root.Name, DkmEvaluationResultFlags.ReadOnly, display_str, "", #if !VS2013 as_root.Type, #else "Unknown", #endif DkmEvaluationResultCategory.Other, DkmEvaluationResultAccessType.None, DkmEvaluationResultStorageType.None, DkmEvaluationResultTypeModifierFlags.None, null, null, null, null ); state_ = EvaluationState.MinimalEvaluation; return; } } // string custom_display_str = Resources.UE4PropVis.IDS_DISP_CONDENSED; DkmSuccessEvaluationResult proto_eval = null; bool is_pointer; bool is_null; string address_str = ""; // @NOTE: Initially here we were executing the full default evaluation of our expression. // Problem is that this will call back into us for all UObject children of the expression, // because it needs to generate a visualization for them in order to construct its {member vals...} display string. // And then, we just ignore that anyway and display our own... // The following attempts to avoid that by casting our expression to void* and then evaluating that. // If it fails, we assume we are non-pointer. If it succeeds, we can determine from the result whether we are null or not. // @WARNING: This may not be so safe, since we can't determine whether evaluation failed because we tried to cast a non-pointer // to void*, or because the passed in expression was not valid in the first place. Believe we should be okay, since we should // only be receiving expressions that have already been determined to be suitable for our custom visualizer. // Ideally though, we'd be able to get a raw expression evaluation, without any visualization taking place. // Seems there must be a way to do this, but looks like it requires using a different API... const bool UseVoidCastOptimization = true; string default_expr_str = Utility.GetExpressionFullName(expression_); if (UseVoidCastOptimization) { default_expr_str = ExpressionManipulator.FromExpression(default_expr_str).PtrCast(Cpp.Void).Expression; } DkmEvaluationResult eval = DefaultEE.DefaultEval(default_expr_str, expression_, true); if (!UseVoidCastOptimization) { if (eval.TagValue != DkmEvaluationResult.Tag.SuccessResult) { // Genuine failure to evaluate the passed in expression eval_ = eval; state_ = EvaluationState.Failed; return; } else { proto_eval = (DkmSuccessEvaluationResult)eval; custom_display_str = proto_eval.Value; is_pointer = IsPointer(proto_eval); is_null = is_pointer && IsPointerNull(proto_eval); // @TODO: need to extract address string } } else { DkmDataAddress address = null; if (eval.TagValue != DkmEvaluationResult.Tag.SuccessResult) { // Assume the failure just implies the expression was non-pointer (thereby assuming that it was itself valid!) // @TODO: Could actually fall back onto standard evaluation here, in order to determine for sure // that the original expression is valid. Failure wouldn't be common since most of the time we are // dealing with pointer expressions, so any potential optimization should still be gained. is_pointer = false; is_null = false; } else { var success = (DkmSuccessEvaluationResult)eval; Debug.Assert(IsPointer(success)); is_pointer = true; is_null = is_pointer && IsPointerNull(success); address = success.Address; address_str = success.Value; } proto_eval = DkmSuccessEvaluationResult.Create( expression_.InspectionContext, expression_.StackFrame, "", "", DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable, "", "", #if !VS2013 Utility.GetExpressionType(expression_), #else is_pointer ? "UObject *" : "UObject", #endif DkmEvaluationResultCategory.Other, DkmEvaluationResultAccessType.None, DkmEvaluationResultStorageType.None, DkmEvaluationResultTypeModifierFlags.None, address, null, null, null ); } string obj_expression_str = Utility.GetExpressionFullName(expression_); var obj_em = ExpressionManipulator.FromExpression(obj_expression_str); // Store pointer flags on the expression expression_.SetDataItem( DkmDataCreationDisposition.CreateAlways, new UObjectDataItem(is_pointer, is_null) ); if (!is_pointer) { // All subsequent manipulations of the expression assume it starts as a pointer to a // UObject-derived class, so if our expression is to a dereferenced UObject, just // prefix an 'address of' to the expression string. obj_em = obj_em.AddressOf(); } // Generate the condensed display string. if (is_null) { if (Config.CustomNullObjectPreview) { custom_display_str = "<NULL> UObject"; } else { var null_eval = DefaultEE.DefaultEval("(void*)0", expression_, true) as DkmSuccessEvaluationResult; custom_display_str = null_eval.Value + " <NULL>"; } } else if (Config.DisplayUObjectPreview) { // Prefix the address, if this is a pointer expression string address_prefix_str = ""; if (is_pointer) { address_prefix_str = address_str + " "; } // Specialized display for UClass? bool uclass_specialized = false; if (Config.DisplaySpecializedUClassPreview) { var uclass_em = obj_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjClass); var _uclass_fname_expr_str = uclass_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjName).Expression; string _obj_uclass_name_str = UE4Utility.GetFNameAsString(_uclass_fname_expr_str, expression_); // @TODO: To simplify and for performance reasons, just hard coding known UClass variants if (_obj_uclass_name_str == "Class" || _obj_uclass_name_str == "BlueprintGeneratedClass" || _obj_uclass_name_str == "WidgetBlueprintGeneratedClass") { var fname_expr_str = obj_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjName).Expression; string obj_name_str = UE4Utility.GetFNameAsString(fname_expr_str, expression_); var parent_uclass_fname_expr_str = obj_em.PtrCast(Typ.UStruct).PtrMember(Memb.SuperStruct).PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjName).Expression; // This will return null if lookup failed for any reason. // We'll assume this meant no super class exists (ie. we're dealing with UClass itself) string parent_uclass_name_str = UE4Utility.GetFNameAsString(parent_uclass_fname_expr_str, expression_); if (parent_uclass_name_str == null) { parent_uclass_name_str = "None"; } custom_display_str = String.Format( "{0}{{ClassName='{1}', Parent='{2}'}}", address_prefix_str, obj_name_str, parent_uclass_name_str ); uclass_specialized = true; } } if (!uclass_specialized) { // For standard UObject condensed display string, show the object FName and its UClass. // @TODO: The evaluations required for this may be a performance issue, since they'll be done for all UObject children of any default visualized // aggregate type, even when it is not expanded (the default behaviour is to create a {...} display list of child member visualizations). var fname_expr_str = obj_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjName).Expression; string obj_name_str = UE4Utility.GetFNameAsString(fname_expr_str, expression_); var uclass_fname_expr_str = obj_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjClass).PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjName).Expression; string obj_uclass_name_str = UE4Utility.GetFNameAsString(uclass_fname_expr_str, expression_); custom_display_str = String.Format( "{0}{{Name='{1}', Class='{2}'}}", address_prefix_str, obj_name_str, obj_uclass_name_str ); } } eval_ = DkmSuccessEvaluationResult.Create( proto_eval.InspectionContext, proto_eval.StackFrame, // Override the eval name with the original expression name, since it will // have inherited the ",!" suffix. Utility.GetExpressionName(expression_), Utility.GetExpressionFullName(expression_), proto_eval.Flags, custom_display_str, //success_eval.Value, proto_eval.EditableValue, proto_eval.Type, proto_eval.Category, proto_eval.Access, proto_eval.StorageType, proto_eval.TypeModifierFlags, proto_eval.Address, proto_eval.CustomUIVisualizers, proto_eval.ExternalModules, null ); state_ = EvaluationState.Evaluated; }