Guest Post: Introduzione a .NET Compiler Platform – Project “Roslyn”

Questo post è stato scritto da Alessandro Del Sole, Microsoft MVP e Solutions Developer Expert presso Brain-Sys.

 

Cos’è .NET Compiler Platform

 

Con il rilascio di Visual Studio 2015 e dell’ecosistema .NET 2015, Microsoft ha anche rilasciato la v. 1.0 di .NET Compiler Platform, nota anche col nome di Project “Roslyn” (in questo post utilizzerò entrambi i nomi senza distinzione). Di che si tratta? I compilatori C# e Visual Basic sono stati completamente riscritti in codice .NET e sono stati rilasciati come progetto open source, ospitato su GitHub. Questo porta due enormi benefici: da un lato Microsoft può condividere con la comunità di sviluppatori le proprie attività e soprattutto può accettare contributi community per migliorare i prodotti; dall’altro lato, i compilatori non sono più delle cosiddette black box che generano binari a partire da codice sorgente, ma ora, essendo scritti in .NET, espongono API per l’analisi del codice e possono essere invocati da altri tool in un’ottica compiler-as-a-service. Lo stesso Visual Studio 2015 fa un uso massiccio delle API esposte dai compilatori per dare vita a un editor di codice fortemente rinnovato, almeno dal punto di vista strutturale, per rilevare errori e fornire suggerimenti mentre si digita. Analisi del codice non vuol dire solamente andare alla ricerca di errori nel codice sorgente, significa piuttosto poter avere, in qualunque momento e in tempo reale, informazioni sul codice sorgente mediante invocazioni alle API del compilatore. In questo primo post vedremo come Visual Studio 2015 usa le API di Roslyn, come Roslyn interpreta il codice sorgente e cosa ci serve per lavorare con le API dei compilatori. Nel post successivo faremo invece un esempio di utilizzo pratico.

 

Cosa posso fare con .NET Compiler Platform

 

Indubbiamente l’utilizzo delle API dei compilatori riguarda tipicamente lo sviluppo di strumenti per sviluppatori. Gli scenari principali di utilizzo possono essere riassunti come nel seguente elenco, che non deve però essere inteso in senso restrittivo:

· Scrittura di regole di analisi personalizzate del codice (c.d. custom domain analysis rules) da integrare nell’editor di codice, per rilevare errori o warning e fornire suggerimenti mentre si digita, magari per specifici pattern o proprie librerie;

· Metaprogramming;

· Code generation per generare e compilare codice all’interno di un’applicazione;

· Strumenti e applicazioni per sviluppatori che debbono elaborare codice sorgente.

Un esempio di utilizzo al di fuori di Visual Studio 2015 è un tool chiamato Code Snippet Studio, che ho pubblicato come progetto open source, e che usa le API di Roslyn per analizzare in tempo reale frammenti di codice VB e C# prima di esportarli nel formato .snippet, utilizzato dall’IntelliSense di Visual Studio, riportando gli errori mentre si digita.

 

Quattro chiacchiere sull’architettura

 

Non entrerò nei dettagli dell’architettura di .NET Compiler Platform, per la quale vi rimando alla documentazione[EB1] , ma farò un’overview introducendo i concetti fondamentali. In Roslyn, ogni fase della compilazione tradizionale, a partire dal parsing del codice fino alla fase di Emit, ha una controparte costituita da classi .NET. La seguente figura, tratta dalla documentazione open source di Roslyn, mostra questo approccio:

 

clip_image002

 

Le Compiler API, quindi, sono la macroarea che si occupa di analizzare il sorgente attraverso tutte le fasi. Uno strato superiore è costituito dai language services, attraverso i quali applicazioni come Visual Studio 2015 riescono a porre in essere tutta una serie di attività sul codice, come la formattazione e l’IntelliSense:

 

clip_image004

 

Le Compiler API sono il primo livello nell’architettura di Roslyn, che in realtà ha ulteriori layer, visibili nella seguente figura (sempre tratta da GitHub):

 

clip_image006

 

L’altro layer importante è quello delle Workspaces API, che espongono oggetti .NET per gestire solution di MSBuild, quindi soluzion .sln ma anche progetti .vbproj e .csproj, i loro riferimenti e i file di codice che li compongono. Le Feature API sono in realtà un sotto-layer e consentono di riscrivere una porzione di codice con nuovi nodi sintattici. Le Compiler API hanno un sotto-layer chiamato Diagnostic API, che è quello che probabilmente utilizzeremo di più in quanto danno la possibilità di eseguire l’analisi del codice per come la intendiamo normalmente, quindi analisi e report di errori/warning.

 

Come Visual Studio 2015 usa Roslyn

 

Come detto in precedenza, Visual Studio 2015 usa in modo massiccio le API di Roslyn per dare vita a molte delle sue funzionalità, come ad esempio l’editor di codice, la finestra Find all References, e molto altro. Per capire come Visual Studio 2015 usi Roslyn, prendiamo in considerazione l’editor di codice che è una delle aree maggiormente rinnovate nell’ultima edizione. Considerate questa definizione di classe, che vuole implementare l’interfaccia IDisposable ma mancano due cose: la direttiva using appropriata e l’implementazione dell’interfaccia:

 

clip_image008

 

Quando digitiamo, l’editor rileva automaticamente problemi o errori, attivando il cosiddetto Light Bulb, un’icona a forma di lampadina. Cliccando sul Light Bulb, vengono offerte possibili soluzioni al problema riscontrato, ognuna delle quali nota come Quick Action:

 

clip_image010

 

In questo caso l’editor propone, tra l’altro, di aggiungere la necessaria direttiva using. Fatto questo, il problema non è ancora risolto perché manca l’implementazione dell’interfaccia. Guardate come Visual Studio consente di implementarla:

 

clip_image012

 

E’ davvero interessante il fatto che l’editor possa proporre delle soluzioni sulla base del contesto in cui stiamo lavorando, in questo caso offrendo quattro possibili diverse opzioni di implementazione. L’anteprima del codice viene mostrata in una cosiddetta Live Preview, che mostra in verde il codice che viene aggiunto ed in rosso eventuale codice rimosso. Cliccando su Preview changes si potrà accedere ad una finestra di dialogo più dettagliata e si può decidere se applicare il fix a livello di file, progetto o solution. Un altro esempio di come l’editor usi Roslyn è costituito dai refactoring, finalmente introdotti anche in Visual Basic e già noti a chi sviluppa in C#, ma completamente ristrutturati. Per esempio, nella seguente figura si vede come sia possibile rimuovere le direttive using non necessarie:

 

clip_image014

 

Altri due piccoli esempi sono costituiti dall’Inline-Rename, per rinominare identificatori, e il rilevamento di codice ridondante il cui colore viene schiarito. Nella seguente figura si vede l’Inline-Rename in azione più la parola chiave this schiarita, in quanto ritenuta non necessaria:

 

clip_image016

 

Ovviamente questi sono solo alcuni piccoli esempi di come Visual Studio 2015 utilizzi le API dei compilatori per porre in essere quella che è la cosiddetta code focused experience, ossia produttività ai massimi livelli quando si scrive codice, senza togliere lo sguardo dalla finestra attiva. Per vedere altri esempi d’uso, vi basta simulare degli errori di digitazione o di implementazione di regole sintattiche oppure attivare il Light Bulb facendo click destro su un elemento e poi scegliendo Quick Actions dal menu contestuale.

 

Cosa mi serve per lavorare con Roslyn

 

Se volessimo sviluppare applicazioni che utilizzano le API dei compilatori, abbiamo bisogno primariamente di un assembly chiamato Microsoft.CodeAnalysis.dll e degli assembly specializzati Microsoft.CodeAnalysis.Csharp.dll e Microsoft.CodeAnalysis.VisualBasic.dll. In realtà ci sono anche altri assembly, ad esempio per lavorare con le Workspace API, ma non li tratteremo in questi post. Gli assembly citati sono scaricabili da NuGet, cosa che faremo se vogliamo sviluppare applicazioni svincolate da Visual Studio 2015. Se invece vogliamo scrivere delle regole di analisi del codice che vadano ad integrarsi con l’editor, è conveniente scaricare il .NET Compiler Platform SDK dalla Visual Studio Gallery. Questo mette a disposizione una serie di template già predisposti per quel tipo di progetti. In realtà, l’SDK è fondamentale per un altro motivo: mette a disposizione una nuova finestra chiamata Syntax Visualizer, che utilizzeremo in pratica nel prossimo post, ma che diventerà la nostra migliore amica quando dobbiamo lavorare con Roslyn. Questa finestra, infatti, ci permette di capire come i compilatori rappresentano il codice sorgente e con quali oggetti .NET. Ecco un esempio:

 

clip_image018

 

La parte superiore rappresenta il Syntax Tree, ovvero l’elemento radice della rappresentazione sintattica del codice. Come vedete, per ogni singolo elemento del codice, spazi bianchi e commenti inclusi, c’è una classe a rappresentarlo. Nella parte sottostante, invece, ci sono le proprietà dell’elemento selezionato nel codice. Poiché con Roslyn vi troverete spesso ad elaborare blocchi e costrutti sintattici, dovete capire come il compilatore li comprende e la finestra Syntax Visualizer vi aiuta proprio in questo.

 

Nel prossimo post vedremo meglio come utilizzarla in pratica.