| /****************************************************************************  | 
| **  | 
| ** Copyright (C) 2018 The Qt Company Ltd.  | 
| ** Contact: https://www.qt.io/licensing/  | 
| **  | 
| ** This file is part of the Qt VS Tools.  | 
| **  | 
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$  | 
| ** Commercial License Usage  | 
| ** Licensees holding valid commercial Qt licenses may use this file in  | 
| ** accordance with the commercial license agreement provided with the  | 
| ** Software or, alternatively, in accordance with the terms contained in  | 
| ** a written agreement between you and The Qt Company. For licensing terms  | 
| ** and conditions see https://www.qt.io/terms-conditions. For further  | 
| ** information use the contact form at https://www.qt.io/contact-us.  | 
| **  | 
| ** GNU General Public License Usage  | 
| ** Alternatively, this file may be used under the terms of the GNU  | 
| ** General Public License version 3 as published by the Free Software  | 
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT  | 
| ** included in the packaging of this file. Please review the following  | 
| ** information to ensure the GNU General Public License requirements will  | 
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html.  | 
| **  | 
| ** $QT_END_LICENSE$  | 
| **  | 
| ****************************************************************************/  | 
|   | 
| using System;  | 
| using System.Collections.Generic;  | 
| using System.Linq;  | 
| using System.Threading.Tasks;  | 
| using Microsoft.VisualStudio;  | 
| using Microsoft.VisualStudio.Debugger.Interop;  | 
|   | 
| namespace QtVsTools.Qml.Debug.AD7  | 
| {  | 
|     sealed partial class StackFrame : Concurrent,  | 
|   | 
|         IDebugStackFrame2,        // "This interface represents a single stack frame in a call  | 
|                                   //  stack in a particular thread."  | 
|   | 
|         IDebugExpressionContext2, // "This interface represents a context for expression evaluation"  | 
|   | 
|         IDebugProperty2           // "This interface represents a stack frame property, a program  | 
|                                   //  document property, or some other property. The property is  | 
|                                   //  usually the result of an expression evaluation."  | 
|     {  | 
|         public QmlDebugger Debugger { get; private set; }  | 
|   | 
|         public QmlEngine Engine { get; private set; }  | 
|         public Program Program { get; private set; }  | 
|   | 
|         public CodeContext Context { get; private set; }  | 
|         public Dictionary<int, Dictionary<string, Property>> Properties { get; private set; }  | 
|   | 
|         public string Name { get; private set; }  | 
|         public int FrameNumber { get; private set; }  | 
|         public IEnumerable<int> Scopes { get; private set; }  | 
|         public Task InitThread { get; private set; }  | 
|   | 
|         static public StackFrame Create(  | 
|             string name,  | 
|             int number,  | 
|             IEnumerable<int> scopes,  | 
|             CodeContext context)  | 
|         {  | 
|             var _this = new StackFrame();  | 
|             return _this.Initialize(name, number, scopes, context) ? _this : null;  | 
|         }  | 
|   | 
|         private StackFrame()  | 
|         { }  | 
|   | 
|         private bool Initialize(  | 
|             string name,  | 
|             int number,  | 
|             IEnumerable<int> scopes,  | 
|             CodeContext context)  | 
|         {  | 
|             Context = context;  | 
|             Engine = context.Engine;  | 
|             Program = context.Program;  | 
|             Debugger = Program.Debugger;  | 
|             Name = string.Format("{0}@{1}:{2}", name, context.FilePath, context.FileLine + 1);  | 
|             FrameNumber = number;  | 
|             Scopes = scopes;  | 
|             InitThread = Task.Run(() => InitializeProperties());  | 
|             return true;  | 
|         }  | 
|   | 
|         private void InitializeProperties(bool forceScope = false)  | 
|         {  | 
|             Properties = Scopes.ToDictionary(x => x, x => new Dictionary<string, Property>());  | 
|             foreach (var scopeNumber in Scopes) {  | 
|                 var scopeVars = Debugger.RefreshScope(FrameNumber, scopeNumber, forceScope);  | 
|                 foreach (var scopeVar in scopeVars) {  | 
|                     Properties[scopeNumber]  | 
|                         .Add(scopeVar.Name, Property.Create(this, scopeNumber, scopeVar));  | 
|                 }  | 
|             }  | 
|         }  | 
|   | 
|         public void Refresh()  | 
|         {  | 
|             InitializeProperties(true);  | 
|         }  | 
|   | 
|         int IDebugExpressionContext2.ParseText(  | 
|             string pszCode,  | 
|             enum_PARSEFLAGS dwFlags,  | 
|             uint nRadix,  | 
|             out IDebugExpression2 ppExpr,  | 
|             out string pbstrError,  | 
|             out uint pichError)  | 
|         {  | 
|             pbstrError = "";  | 
|             pichError = 0;  | 
|             ppExpr = Expression.Create(this, pszCode);  | 
|             return VSConstants.S_OK;  | 
|         }  | 
|   | 
|         int IDebugStackFrame2.EnumProperties(  | 
|             enum_DEBUGPROP_INFO_FLAGS dwFields,  | 
|             uint nRadix,  | 
|             ref Guid guidFilter,  | 
|             uint dwTimeout,  | 
|             out uint pcelt,  | 
|             out IEnumDebugPropertyInfo2 ppEnum)  | 
|         {  | 
|             pcelt = 0;  | 
|             ppEnum = null;  | 
|   | 
|             if (guidFilter != Guid.Empty && !Property.Filter.LocalsSelected(ref guidFilter))  | 
|                 return VSConstants.S_OK;  | 
|   | 
|             InitThread.Wait();  | 
|             pcelt = 0;  | 
|             ppEnum = PropertyEnum.Create(Properties  | 
|                 .SelectMany(x => x.Value  | 
|                     .Select(y => y.Value.GetInfo(dwFields))));  | 
|   | 
|             return VSConstants.S_OK;  | 
|         }  | 
|   | 
|         int IDebugProperty2.EnumChildren(  | 
|             enum_DEBUGPROP_INFO_FLAGS dwFields,  | 
|             uint dwRadix,  | 
|             ref Guid guidFilter,  | 
|             enum_DBG_ATTRIB_FLAGS dwAttribFilter,  | 
|             string pszNameFilter,  | 
|             uint dwTimeout,  | 
|             out IEnumDebugPropertyInfo2 ppEnum)  | 
|         {  | 
|             uint pcelt;  | 
|             return ((IDebugStackFrame2)this)  | 
|                 .EnumProperties(dwFields, dwRadix, guidFilter, dwTimeout, out pcelt, out ppEnum);  | 
|         }  | 
|   | 
|         #region //////////////////// Info /////////////////////////////////////////////////////////  | 
|   | 
|         class StackFrameInfo : InfoHelper<StackFrameInfo>  | 
|         {  | 
|             public string FunctionName { get; set; }  | 
|             public string ReturnType { get; set; }  | 
|             public string Arguments { get; set; }  | 
|             public string Language { get; set; }  | 
|             public string ModuleName { get; set; }  | 
|             public ulong? MinAddress { get; set; }  | 
|             public ulong? MaxAddress { get; set; }  | 
|             public IDebugStackFrame2 Frame { get; set; }  | 
|             public IDebugModule2 Module { get; set; }  | 
|             public int? HasDebugInfo { get; set; }  | 
|             public int? StaleCode { get; set; }  | 
|         }  | 
|   | 
|         StackFrameInfo Info  | 
|         {  | 
|             get  | 
|             {  | 
|                 return new StackFrameInfo  | 
|                 {  | 
|                     FunctionName = Name,  | 
|                     ReturnType = "",  | 
|                     Arguments = "",  | 
|                     Language = Context.FileType.ToString(),  | 
|                     ModuleName = "",  | 
|                     MinAddress = 0,  | 
|                     MaxAddress = 9999,  | 
|                     Frame = this,  | 
|                     Module = Program,  | 
|                     HasDebugInfo = 1,  | 
|                     StaleCode = 0,  | 
|                 };  | 
|             }  | 
|         }  | 
|   | 
|         static readonly StackFrameInfo.Mapping MappingToFRAMEINFO =  | 
|   | 
|         #region //////////////////// FRAMEINFO <-- StackFrameInfo /////////////////////////////////  | 
|             // r: Ref<FRAMEINFO>  | 
|             // f: enum_FRAMEINFO_FLAGS  | 
|             // i: StackFrameInfo  | 
|             // v: value of i.<<property>>  | 
|   | 
|             new StackFrameInfo.Mapping<FRAMEINFO, enum_FRAMEINFO_FLAGS>  | 
|                 ((r, bit) => r.s.m_dwValidFields |= bit)  | 
|             {  | 
|                 { enum_FRAMEINFO_FLAGS.FIF_FUNCNAME,  | 
|                     (r, v) => r.s.m_bstrFuncName = v, i => i.FunctionName },  | 
|   | 
|                 { enum_FRAMEINFO_FLAGS.FIF_RETURNTYPE,  | 
|                     (r, v) => r.s.m_bstrReturnType = v, i => i.ReturnType },  | 
|   | 
|                 { enum_FRAMEINFO_FLAGS.FIF_ARGS,  | 
|                     (r, v) => r.s.m_bstrArgs = v, i => i.Arguments },  | 
|   | 
|                 { enum_FRAMEINFO_FLAGS.FIF_LANGUAGE,  | 
|                     (r, v) => r.s.m_bstrLanguage = v, i => i.Language },  | 
|   | 
|                 { enum_FRAMEINFO_FLAGS.FIF_MODULE,  | 
|                     (r, v) => r.s.m_bstrModule = v, i => i.ModuleName },  | 
|   | 
|                 { enum_FRAMEINFO_FLAGS.FIF_STACKRANGE,  | 
|                     (r, v) => r.s.m_addrMin = v, i => i.MinAddress },  | 
|   | 
|                 { enum_FRAMEINFO_FLAGS.FIF_STACKRANGE,  | 
|                     (r, v) => r.s.m_addrMax = v, i => i.MaxAddress },  | 
|   | 
|                 { enum_FRAMEINFO_FLAGS.FIF_FRAME,  | 
|                     (r, v) => r.s.m_pFrame = v, i => i.Frame },  | 
|   | 
|                 { enum_FRAMEINFO_FLAGS.FIF_DEBUG_MODULEP,  | 
|                     (r, v) => r.s.m_pModule = v, i => i.Module },  | 
|   | 
|                 { enum_FRAMEINFO_FLAGS.FIF_DEBUGINFO,  | 
|                     (r, v) => r.s.m_fHasDebugInfo = v, i => i.HasDebugInfo },  | 
|   | 
|                 { enum_FRAMEINFO_FLAGS.FIF_STALECODE,  | 
|                     (r, v) => r.s.m_fStaleCode = v, i => i.StaleCode },  | 
|             };  | 
|   | 
|         #endregion //////////////////// FRAMEINFO <-- StackFrameInfo //////////////////////////////  | 
|   | 
|   | 
|         int IDebugStackFrame2.GetInfo(  | 
|             enum_FRAMEINFO_FLAGS dwFieldSpec,  | 
|             uint nRadix,  | 
|             FRAMEINFO[] pFrameInfo)  | 
|         {  | 
|             Info.Map(MappingToFRAMEINFO, dwFieldSpec, out pFrameInfo[0]);  | 
|             return VSConstants.S_OK;  | 
|         }  | 
|   | 
|         int IDebugStackFrame2.GetCodeContext(out IDebugCodeContext2 ppCodeCxt)  | 
|         {  | 
|             ppCodeCxt = Context;  | 
|             return VSConstants.S_OK;  | 
|         }  | 
|   | 
|         int IDebugStackFrame2.GetDocumentContext(out IDebugDocumentContext2 ppCxt)  | 
|         {  | 
|             ppCxt = Context;  | 
|             return VSConstants.S_OK;  | 
|         }  | 
|   | 
|         int IDebugStackFrame2.GetName(out string pbstrName)  | 
|         {  | 
|             pbstrName = Name;  | 
|             return VSConstants.S_OK;  | 
|         }  | 
|   | 
|         int IDebugStackFrame2.GetPhysicalStackRange(out ulong paddrMin, out ulong paddrMax)  | 
|         {  | 
|             paddrMin = ulong.MinValue;  | 
|             paddrMax = ulong.MaxValue;  | 
|             return VSConstants.S_OK;  | 
|         }  | 
|   | 
|         int IDebugStackFrame2.GetExpressionContext(out IDebugExpressionContext2 ppExprCxt)  | 
|         {  | 
|             ppExprCxt = this;  | 
|             return VSConstants.S_OK;  | 
|         }  | 
|   | 
|         int IDebugStackFrame2.GetLanguageInfo(ref string pbstrLanguage, ref Guid pguidLanguage)  | 
|         {  | 
|             pbstrLanguage = "C++";  | 
|             pguidLanguage = NativeEngine.IdLanguageCpp;  | 
|             return VSConstants.S_OK;  | 
|         }  | 
|   | 
|         int IDebugStackFrame2.GetThread(out IDebugThread2 ppThread)  | 
|         {  | 
|             ppThread = Program;  | 
|             return VSConstants.S_OK;  | 
|         }  | 
|   | 
|         int IDebugStackFrame2.GetDebugProperty(out IDebugProperty2 ppProperty)  | 
|         {  | 
|             ppProperty = this;  | 
|             return VSConstants.S_OK;  | 
|         }  | 
|   | 
|         #endregion //////////////////// Info //////////////////////////////////////////////////////  | 
|   | 
|     }  | 
| }  |