| File: Navigation\DiaSession.cs | Web Access |
| Project: src\vstest\src\Microsoft.TestPlatform.ObjectModel\Microsoft.TestPlatform.ObjectModel.csproj (Microsoft.VisualStudio.TestPlatform.ObjectModel) |
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Diagnostics.CodeAnalysis; using System.IO; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Navigation; using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers; namespace Microsoft.VisualStudio.TestPlatform.ObjectModel; /// <summary> /// The class that enables us to get debug information from both managed and native binaries. /// </summary> [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Justification = "Dia is a specific name.")] public class DiaSession : INavigationSession { /// <summary> /// Characters that should be stripped off the end of test names. /// </summary> private static readonly char[] TestNameStripChars = ['(', ')', ' ']; /// <summary> /// The symbol reader. /// </summary> private readonly ISymbolReader _symbolReader; private bool _isDisposed; /// <summary> /// Initializes a new instance of the <see cref="DiaSession"/> class. /// </summary> /// <param name="binaryPath"> /// The binary path. /// </param> public DiaSession(string binaryPath) : this(binaryPath, null) { } /// <summary> /// Initializes a new instance of the <see cref="DiaSession"/> class. /// </summary> /// <param name="binaryPath"> /// The binary path is assembly path Ex: \path\to\bin\Debug\simpleproject.dll /// </param> /// <param name="searchPath"> /// search path. /// </param> public DiaSession(string binaryPath, string? searchPath) : this(binaryPath, searchPath, GetSymbolReader(binaryPath)) { } internal DiaSession(string binaryPath, string? searchPath, ISymbolReader symbolReader) { _symbolReader = symbolReader; ValidateArg.NotNullOrEmpty(binaryPath, nameof(binaryPath)); _symbolReader.CacheSymbols(binaryPath, searchPath); } /// <summary> /// Dispose symbol reader /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_isDisposed) return; if (disposing) { _symbolReader.Dispose(); } _isDisposed = true; } /// <summary> /// Gets the navigation data for a method declared in a type. /// </summary> /// <param name="declaringTypeName"> The declaring type name. </param> /// <param name="methodName"> The method name. </param> /// <returns> The <see cref="INavigationData" /> for that method. </returns> /// <remarks> Leaving this method in place to preserve back compatibility. </remarks> public DiaNavigationData? GetNavigationData(string declaringTypeName, string methodName) { return (DiaNavigationData?)GetNavigationDataForMethod(declaringTypeName, methodName); } /// <summary> /// Gets the navigation data for a method declared in a type. /// </summary> /// <param name="declaringTypeName"> The declaring type name. </param> /// <param name="methodName"> The method name. </param> /// <returns> The <see cref="INavigationData" /> for that method. </returns> public INavigationData? GetNavigationDataForMethod(string declaringTypeName, string methodName) { ValidateArg.NotNullOrEmpty(declaringTypeName, nameof(declaringTypeName)); ValidateArg.NotNullOrEmpty(methodName, nameof(methodName)); methodName = methodName.TrimEnd(TestNameStripChars); return _symbolReader.GetNavigationData(declaringTypeName, methodName); } private static ISymbolReader GetSymbolReader(string? binaryPath) { var pdbFilePath = Path.ChangeExtension(binaryPath, ".pdb"); // For remote scenario, also look for pdb in current directory, (esp for UWP) // The alternate search path should be an input from Adapters, but since it is not so currently adding a HACK pdbFilePath = !File.Exists(pdbFilePath) ? Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileName(pdbFilePath)!) : pdbFilePath; if (File.Exists(pdbFilePath)) { using var stream = new FileHelper().GetStream(pdbFilePath!, FileMode.Open, FileAccess.Read); return PortablePdbReader.IsPortable(stream) ? new PortableSymbolReader() : new FullSymbolReader(); } else { // If we cannot find the pdb file, it might be embedded in the dll. return new PortableSymbolReader(); } } }