2015-08-03 8 views
7

Come si ottiene l'accesso al percorso del file al progetto/soluzione che viene compilato all'interno di un analizzatore di codice Roslyn? Ho bisogno di verificare il codice rispetto ad alcuni file spec memorizzati rispetto al codice.Come ottenere il percorso della soluzione nell'analizzatore di codice .NET

SyntaxTreeAnalysisContext.Tree.FilePath 
Assembly.GetExecutingAssembly().Location 
AppDomain.CurrentDomain.BaseDirectory 
Environment.CurrentDirectory 
Path.GetFullPath(relativePath) 
+0

Roslyn analizzatori esistono sotto lo strato di lavoro; la soluzione potrebbe non esistere realmente. – SLaks

+0

Quindi è impossibile per definizione? –

+0

Se ci provi, probabilmente puoi farlo funzionare solo in VS (Prova a ottenere SComponentModel da un ServiceProvider globale, quindi a prendere il Roslyn VisualStudioWorkspace). Tuttavia, ciò sarà fragile e non funzionerà affatto al di fuori di VS. – SLaks

risposta

3

analizzatori esistono al di sotto del livello di lavoro (sono gestiti direttamente dal compilatore), per cui la soluzione non possono esistere: le cose che non funzionano.

Per motivi complicati, non vengono creati da MEF, quindi non esiste un modo semplice per raggiungerlo anche se esiste.

Dall'interno di VS, è possibile trovare il fornitore di servizi globale (ad esempio, ServiceProvider.GlobalProvider), quindi ottenere SComponentModel (la radice del proprio grafico MEF del VS) e afferrare VisualStudioWorkspace di Roslyn da questo. Fai attenzione che questo è un approccio un po 'fragile e non funzionerà affatto al di fuori di VS.

Anche all'interno di VS, questo si interrompe in modo strano per analisi nei riquadri di anteprima, file vari e altri contesti che non fanno parte della soluzione globale.

0

Ecco un altro approccio che funziona senza VS; anche fragile ma per ragioni diverse. :)

Trova il csproj a livello di file cercando la gerarchia di cartelle verso l'alto a partire dal percorso del file di origine dell'albero di sintassi corrente.

Naturalmente non funzionerà in determinate circostanze (se il file sorgente è esterno alla sottostruttura della cartella csproj, ad esempio file collegati, oppure ci sono altri file csproj stantii in giro, ecc.) L'unica sicurezza la rete che potrei pensare è di verificare se il file csproj trovato è in realtà per lo stesso nome assembly a cui si riferisce l'attuale SemanticModel.Compilation.AssemblyName, quindi non si finisce con un csproj di qualche altro progetto casuale.

Ecco il codice, vedere il metodo chiamato FindProjectFile: https://nsdepcop.codeplex.com/SourceControl/changeset/view/75896#VS2015/source/NsDepCop.VisualStudioIntegration/ProjectAnalyzerRepository.cs

2

Non è possibile ottenere la soluzione da analizzatore o fissatore senza riflessione.

Utilizzare additional files per memorizzare le impostazioni.

In progetto:

<ItemGroup> 
    <AdditionalFiles Include="MyConfig.config" /> 
</ItemGroup> 

In analizzatore:

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); 
} 
+1

WorkspaceAnalyzerOptions è interno come puoi farlo –

+0

Hai ragione, non è possibile. Ho modificato la risposta. –

+0

Grazie per aver risposto in quel modo in origine ho trovato un modo per farlo con la caccia. Invierò una risposta tra –

0

ho trovato un modo per fare questo attraverso la riflessione, ho provato solo questo in ambiente 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); 
    } 
} 

chiamato da un analizzatore modo:

public override void Initialize(AnalysisContext context) 
{ 
    context.RegisterSyntaxNodeAction(AnalyzeConstDeclaration, SyntaxKind.FieldDeclaration); 
} 

public static void AnalyzeConstDeclaration(SyntaxNodeAnalysisContext context) 
{ 
    var solution = context.GetSolution(); 
} 
+0

Qualcuno vuole spiegare il downvote –