¿Cómo se obtiene acceso a la ruta del archivo del proyecto/solución que se está compilando dentro de un analizador de código Roslyn? Necesito verificar el código con algunos archivos de especificaciones almacenados en relación con el código. Cosas que NO funcionan:
SyntaxTreeAnalysisContext.Tree.FilePath Assembly.GetExecutingAssembly().Location AppDomain.CurrentDomain.BaseDirectory Environment.CurrentDirectory Path.GetFullPath(relativePath)Los analizadores existen por debajo del nivel del espacio de trabajo (los ejecuta directamente el compilador), por lo que es posible que la solución no exista.
Por razones complicadas, no son creados por MEF, por lo que no hay una manera fácil de llegar a ellos, incluso si existen.
Desde dentro de VS, puede encontrar el proveedor de servicios global (p. ej., ServiceProvider.GlobalProvider ), luego obtener SComponentModel (la raíz del propio gráfico MEF de VS) y obtener el VisualStudioWorkspace de Roslyn. Tenga en cuenta que este es un enfoque algo frágil y no funcionará en absoluto fuera de VS.
Incluso dentro de VS, esto se interrumpirá de formas extrañas para los análisis en los paneles de vista previa, archivos varios y otros contextos que no forman parte de la solución global.
No es posible obtener una solución del analizador o del fijador sin reflexión.
Utilice archivos adicionales para almacenar la configuración.
En proyecto:
<ItemGroup> <AdditionalFiles Include="MyConfig.config" /> </ItemGroup>En analizador:
private const string ConfigFileName = "MyConfig.config"; private static string LoadConfig(ImmutableArray<AdditionalText> additionalFiles, CancellationToken cancellationToken) { var file = additionalFiles.SingleOrDefault(f => string.Compare(Path.GetFileName(f.Path), ConfigFileName, StringComparison.OrdinalIgnoreCase) == 0); if (file == null) { return null; } var fileText = file.GetText(cancellationToken); using (var stream = new MemoryStream()) { using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8, 1024, true)) { fileText.Write(writer, cancellationToken); } stream.Position = 0; using (var reader = new StreamReader(stream)) { return reader.ReadToEnd(); } } } private static void HandleCompilationStart(CompilationStartAnalysisContext context) { var config = LoadConfig(context.Options.AdditionalFiles, context.CancellationToken); }Descubrí una manera de hacer esto a través de la reflexión, solo lo probé en el entorno de Windows.
public static class RoslynExtensions { public static Solution GetSolution(this SyntaxNodeAnalysisContext context) { var workspace = context.Options.GetPrivatePropertyValue<object>("Workspace"); return workspace.GetPrivatePropertyValue<Solution>("CurrentSolution"); } public static T GetPrivatePropertyValue<T>(this object obj, string propName) { if (obj == null) { throw new ArgumentNullException(nameof(obj)); } var pi = obj.GetType().GetRuntimeProperty(propName); if (pi == null) { throw new ArgumentOutOfRangeException(nameof(propName), $"Property {propName} was not found in Type {obj.GetType().FullName}"); } return (T)pi.GetValue(obj, null); } }Llamado desde un analizador así:
public override void Initialize(AnalysisContext context) { context.RegisterSyntaxNodeAction(AnalyzeConstDeclaration, SyntaxKind.FieldDeclaration); } public static void AnalyzeConstDeclaration(SyntaxNodeAnalysisContext context) { var solution = context.GetSolution(); }