async Task <IVariableInformation> EvaluateLldbExpressionWithMetricsAsync( VsExpression expression, IVariableInformation variable, NatvisScope natvisScope, string displayName, ExpressionEvaluationStrategy strategy, ExpressionEvaluationRecorder.StepsRecorder stepsRecorder) { bool variableReplaced = false; expression = expression.MapValue( v => ReplaceScopedNames(v, natvisScope?.ScopedNames, out variableReplaced)); var lldbErrors = new List <string>(); // A helper lambda function to construct an exception given the list of lldb errors. Func <IList <string>, ExpressionEvaluationFailed> createExpressionEvaluationException = errors => { var exceptionMsg = $"Failed to evaluate expression, display name: {displayName}, " + $"expression: {expression}"; errors = errors.Where(error => !string.IsNullOrEmpty(error)).ToList(); if (errors.Any()) { exceptionMsg += $", info: {{{string.Join("; ", errors)}}}"; } return(new ExpressionEvaluationFailed(exceptionMsg)); }; if (strategy == ExpressionEvaluationStrategy.LLDB_EVAL || strategy == ExpressionEvaluationStrategy.LLDB_EVAL_WITH_FALLBACK) { IVariableInformation value; LldbEvalErrorCode errorCode; using (var step = stepsRecorder.NewStep(ExpressionEvaluationEngine.LLDB_EVAL)) { value = await variable.EvaluateExpressionLldbEvalAsync( displayName, expression, natvisScope.ContextVariables); errorCode = (LldbEvalErrorCode)Enum.ToObject(typeof(LldbEvalErrorCode), value.ErrorCode); step.Finalize(errorCode); } if (errorCode == LldbEvalErrorCode.Ok) { value.FallbackValueFormat = variable.FallbackValueFormat; return(value); } lldbErrors.Add(value?.ErrorMessage); if (errorCode == LldbEvalErrorCode.InvalidNumericLiteral || errorCode == LldbEvalErrorCode.InvalidOperandType || errorCode == LldbEvalErrorCode.UndeclaredIdentifier) { // In the case of a well-known error, there's no need to fallback to // LLDB, as it will fail with the same error. throw createExpressionEvaluationException(lldbErrors); } } if (strategy == ExpressionEvaluationStrategy.LLDB) { // If lldb-eval is not enabled, try to interpret the expression as member access // before using LLDB to evaluate the expression in the context of the variable. IVariableInformation value; LLDBErrorCode errorCode; using (var step = stepsRecorder.NewStep(ExpressionEvaluationEngine.LLDB_VARIABLE_PATH)) { value = GetValueForMemberAccessExpression(variable, expression, displayName); errorCode = value != null && !value.Error ? LLDBErrorCode.OK : LLDBErrorCode.ERROR; step.Finalize(errorCode); } if (errorCode == LLDBErrorCode.OK) { value.FallbackValueFormat = variable.FallbackValueFormat; return(value); } lldbErrors.Add(value?.ErrorMessage); } if (strategy == ExpressionEvaluationStrategy.LLDB || strategy == ExpressionEvaluationStrategy.LLDB_EVAL_WITH_FALLBACK) { IVariableInformation value; LLDBErrorCode errorCode; using (var step = stepsRecorder.NewStep(ExpressionEvaluationEngine.LLDB)) { value = await EvaluateExpressionInVariableScopeAsync( variable, expression, displayName); errorCode = value != null && !value.Error ? LLDBErrorCode.OK : LLDBErrorCode.ERROR; step.Finalize(errorCode); } if (errorCode == LLDBErrorCode.OK) { value.FallbackValueFormat = variable.FallbackValueFormat; return(value); } lldbErrors.Add(value?.ErrorMessage); } throw createExpressionEvaluationException(lldbErrors); }