Una nuova e completa implementazione di Intellisense generico

Una nuova e completa implementazione di Intellisense generico

Io posso descrivilo a qualsiasi livello di dettaglio tu voglia nominare, ma non ho tempo per più di una breve spiegazione. Ti spiego come lo facciamo a Roslyn.

Innanzitutto, costruiamo un modello immutabile del flusso di token utilizzando una struttura di dati in grado di rappresentare in modo efficiente modifiche , dal momento che ovviamente le modifiche sono esattamente ciò di cui ci saranno molte.

L'intuizione chiave per renderlo efficiente per il riutilizzo persistente è rappresentare le lunghezze dei caratteri dei token ma non le loro posizioni dei caratteri nel buffer di modifica; ricorda, un token alla fine del file cambierà posizione ad ogni modifica ma la lunghezza del token non cambia. Devi a tutti i costi ridurre al minimo il numero di revisioni totali se vuoi essere efficiente su file estremamente grandi.

Una volta che hai un modello immutabile in grado di gestire inserimenti ed eliminazioni per creare un flusso di token immutabile senza rileggere l'intero file ogni volta, devi fare lo lo stesso cosa, ma per l'analisi grammaticale. Questo è in pratica un problema considerevolmente più difficile . Ti consiglio di ottenere una laurea o una laurea in informatica con un'enfasi sulla teoria del parser se non l'hai già fatto. Abbiamo ottenuto l'aiuto di persone con dottorato di ricerca che hanno svolto le loro tesi sulla teoria del parser per progettare questo particolare bit dell'algoritmo.

Quindi, ovviamente, costruisci un analizzatore grammaticale in grado di analizzare C#. Ricorda, deve analizzare rotto C#, non corretto C#; IntelliSense deve funzionare mentre il programma è in uno stato di non compilazione. Quindi inizia apportando modifiche alla grammatica che hanno buone caratteristiche di ripristino degli errori.

OK, quindi ora hai un parser in grado di eseguire in modo efficiente l'analisi grammaticale senza rileggere o analizzare di nuovo nient'altro che l'area modificata, il più delle volte, il che significa che puoi fare il lavoro tra le sequenze di tasti. Ho dimenticato di dirlo, ovviamente dovrai trovare un meccanismo per non bloccare il thread dell'interfaccia utente durante l'esecuzione di tutte queste analisi se l'analisi dovesse richiedere più tempo del tempo tra due sequenze di tasti. La nuova funzionalità "async/await" di C# 5 dovrebbe aiutare in questo. (Posso dirtelo per esperienza personale:fai attenzione alla proliferazione di attività e token di annullamento. Se sei negligente, è possibile entrare in uno stato in cui ci sono decine di migliaia di attività annullate in sospeso, e questo è non veloce .)

Ora che hai un'analisi grammaticale devi creare un analizzatore semantico . Poiché stai solo eseguendo IntelliSense, non è necessario che sia un analizzatore semantico particolarmente sofisticato. (Il nostro analizzatore semantico deve eseguire un'analisi adatta per generare codice da programmi corretti e correggere l'analisi degli errori da programmi errati.) Ma ovviamente, ancora una volta deve eseguire una buona analisi semantica su programmi rotti, il che aumenta considerevolmente la complessità.

Il mio consiglio è di iniziare costruendo un analizzatore semantico di "livello superiore", sempre utilizzando un modello immutabile che può persistere lo stato dei tipi dichiarati nel codice sorgente da una modifica all'altra. L'analizzatore di livello superiore si occupa di tutto ciò che non è un'istruzione o un'espressione:dichiarazioni di tipo, direttive, spazi dei nomi, dichiarazioni di metodi, costruttori, distruttori e così via. Il materiale che costituisce la "forma" del programma quando il compilatore genera i metadati.

Metadati! Ho dimenticato i metadati. Avrai bisogno di un lettore di metadati. È necessario essere in grado di produrre IntelliSense su espressioni che fanno riferimento a tipi nelle librerie, ovviamente. Consiglio di utilizzare le librerie CCI come lettore di metadati e non Reflection. Dato che stai solo facendo IntelliSense, ovviamente non hai bisogno di uno scrittore di metadati.

Ad ogni modo, una volta che hai un analizzatore semantico di primo livello, puoi scrivere un analizzatore semantico di istruzioni ed espressioni che analizzi i tipi delle espressioni in una determinata istruzione. Presta particolare attenzione alla ricerca del nome e risoluzione del sovraccarico algoritmi. L'inferenza del tipo di metodo sarà particolarmente complicata, soprattutto all'interno delle query LINQ .

Una volta che hai tutto questo, un motore IntelliSense dovrebbe essere facile; calcola semplicemente il tipo di espressione nella posizione corrente del cursore e visualizza un menu a discesa in modo appropriato.

Bene, abbiamo una squadra di, chiamatelo dieci persone, e probabilmente ci vorranno, chiamatelo cinque anni tutti insieme per portare a termine tutto dall'inizio alla fine. Ma abbiamo molto di più da fare oltre al motore IntelliSense. Forse è solo il 40% del lavoro. Oh, e metà di quelle persone lavora su VB, ora che ci penso. Ma quelle persone hanno in media probabilmente cinque o dieci anni di esperienza nello svolgere questo tipo di lavoro, quindi sono più veloci di te se non l'hai mai fatto prima.

Diciamo quindi che dovrebbero essere necessari dai dieci ai vent'anni di lavoro a tempo pieno, lavorando da soli, per creare un motore IntelliSense di qualità Roslyn per C# in grado di eseguire analisi accettabili quasi corrette di programmi di grandi dimensioni nel tempo tra le sequenze di tasti.

Più a lungo se devi prima fare quel dottorato, ovviamente.

Oppure potresti semplicemente usare Roslyn, poiché è a questo che serve . Probabilmente ci vorranno alcune ore, ma non ti diverti a farlo da solo. Ed è divertente!

Puoi scaricare la versione in anteprima qui:

http://www.microsoft.com/download/en/details.aspx?id=27746


Questa è un'area in cui Microsoft in genere produce ottimi risultati:gli strumenti per sviluppatori Microsoft sono davvero fantastici. E c'è un chiaro vantaggio commerciale per le vendite dei loro strumenti di sviluppo e per le vendite di Windows per avere il miglior intellisense, quindi ha senso che Microsoft dedichi il tipo di risorse che Eric descrive nella sua risposta meravigliosamente dettagliata. Tuttavia, penso che valga la pena sottolineare alcune cose:

  1. I tuoi clienti potrebbero non aver effettivamente bisogno di tutte le funzionalità fornite dall'implementazione di Microsoft. La soluzione Microsoft potrebbe essere incredibilmente sovradimensionata in termini di funzionalità che tu necessario fornire al tuo clienti/utenti. A meno che tu non stia effettivamente implementando un ambiente di codifica generico destinato a essere competitivo con Visual Studio, è probabile che ci siano aspetti dell'uso previsto che semplifichino il problema o che ti consentano di scendere a compromessi sulla soluzione che Microsoft ritiene non possono fare. È probabile che Microsoft spenderà risorse riducendo i tempi di risposta che sono già misurati in centinaia di millisecondi. Potrebbe non essere qualcosa che devi fare. Microsoft sta dedicando tempo alla fornitura di un'API che altri utenti possono utilizzare per l'analisi del codice. Probabilmente non fa parte del tuo piano. Dai la priorità alle tue funzionalità e decidi che aspetto ha "abbastanza buono" per te e i tuoi clienti, quindi stima il costo di implementazione.

  2. Oltre a sostenere gli ovvi costi di implementazione dei requisiti che potresti non avere in realtà, Microsoft sostiene anche alcuni costi che potrebbero non essere ovvi se non hai lavorato in un team. Ci sono enormi costi di comunicazione associati ai team. In realtà è incredibilmente facile che cinque persone intelligenti impieghino più tempo per produrre una soluzione rispetto a una singola persona intelligente per produrre la soluzione equivalente. Ci sono aspetti delle pratiche di assunzione e della struttura organizzativa di Microsoft che rendono più probabile questo scenario. Se assumi un gruppo di persone intelligenti con ego e poi autorizzi tutti loro a prendere decisioni, anche tu puoi ottenere una soluzione migliore del 5% al ​​500% del costo. Quella soluzione migliore del 5% potrebbe essere redditizia per Microsoft, ma potrebbe essere mortale per una piccola azienda.

  3. Passare da una soluzione per 1 persona a una soluzione per 5 persone aumenta i costi, ma sono solo i costi di sviluppo all'interno del team. Microsoft ha separato team che si dedicano (approssimativamente) alla progettazione, allo sviluppo e al test anche per una singola funzionalità. La comunicazione relativa al progetto tra pari attraverso questi confini ha un attrito maggiore che all'interno di ciascuna delle discipline. Ciò non solo aumenta i costi di comunicazione tra gli individui, ma si traduce anche in team di dimensioni maggiori. E più di questo:poiché non è un singolo team di 12 individui, ma è invece 3 team di 5 individui, il costo di comunicazione è 3 volte superiore. Altri costi che Microsoft ha scelto di sostenere che potrebbero non tradursi in costi simili per altre società.

Il mio punto qui non è descrivere Microsoft come un'azienda inefficiente. Il punto è che Microsoft prende un sacco di decisioni su qualsiasi cosa, dalle assunzioni, all'organizzazione del team, alla progettazione e all'implementazione che partono da presupposti sulla redditività e sul rischio che semplicemente non si applicano alle aziende che non sono Microsoft.

In termini di intellisense, ci sono vari modi di pensare al problema. Microsoft sta producendo una soluzione molto generica e riutilizzabile che non risolve solo intellisense, ma mira anche alla navigazione del codice, al refactoring e a vari altri usi per l'analisi del codice. Non è necessario fare le cose allo stesso modo se il tuo unico obiettivo è facilitare agli sviluppatori l'immissione del codice senza dover digitare molto. Il targeting di questa funzione non richiede anni di sforzi e ci sono tutti i tipi di cose creative che puoi fare se non fornisci solo un'API, ma controlli anche l'interfaccia utente.