2013-04-08 12 views
9

Ich versuche zu verstehen, wie Code-Vervollständigung mit libclang zu tun. Ich habe beobachtet, „jenseits den Compiler Denken“ und ich habe über c-Index-Test sehe, und ich fand ein einfaches Beispielprogramm hereWarum gibt libclang keine sinnvollen Vervollständigungsergebnisse zurück?

ich zusammengestellt, dass Programm und lief es auf dieser Beispieldatei, die ich aufgepeitscht zu ähnlich die in dem Video:

struct List { 
    int Data; 
    struct List *Next; 
}; 

int sumListNode(struct List *Node) { 
    int result = 0; 
    for (; Node; Node = Node->Next) 
     result = result + Node-> 
} 

void test() { 
    sumLi 
} 

Wenn ich das Programms an dem ersten unvollständigen Raum nach Knoten- Punkt>, es spuckt ein paar C Schlüsselwörter, aber es nicht ausspucken Next oder Daten wie das Video Sagt es sollte.

Wenn ich auf das Leerzeichen nach sumLi zeige, werden dieselben C-Schlüsselwörter ausgegeben. Ich kann es bekommen, sumListNode auszudrucken, wenn ich es auf die Spalte zeige, die das 's' in sumLi hat, aber selbst dann weist es den gleichen Prioritätswert wie die anderen Schlüsselwörter zu, so dass es wirklich nur alles ausdruckt, was ich könnte dort setzen statt zu lesen, was unter dem Cursor ist und versuchen, eine intelligente Vermutung zu machen. Ich griff nur nach Strohhalmen und hoffte, dass es helfen würde, den Cursor an den Anfang des Fragments anstatt an das Ende zu setzen.

Ich habe eine Menge über die Art der Daten gelernt, die mir libclang geben kann und wie man damit aus dem doxygen herausarbeitet und im C-Index-Test herumstochert, aber ich habe einfach nicht gelernt, wie man macht es gibt mir relevante Daten, damit ich etwas zum arbeiten habe.

Antwort

9

Zuerst sollten Sie versuchen, eine CXDiagnostic Ausgabe von der Übersetzungseinheit zu drucken, da jeder Fehler dazu führen kann, dass der Klang in Ihrem Code verloren geht (dies ist in dem sehr einfachen Fall sehr unwahrscheinlich). Beachten Sie, dass libclang die Zeilen- und Spaltennummer möglicherweise anders definiert als Sie es gewohnt sind (wenn Sie z. B. Zeilen-/Spalteninformationen aus Ihrem Texteditor erhalten, müssen Sie möglicherweise 1 zur Spalte hinzufügen) Nummer, die mit der Definition von clang synchron ist).

Drittens könnten Sie den Clang-Compiler selbst verwenden, um die Gültigkeit der Kompilierungsoptionen und Zeilen-/Spalteninformationen zu testen. Auf diese Weise eliminieren Sie die Unsicherheit, die von Ihrem libclang-basierten Code herrührt. Sie können z.B. Verwenden Sie die folgende Befehlszeile:

clang++ -cc1 -fsyntax-only -code-completion-at FILENAME:LINE:COL CLANG_ARGS 

Beachten Sie auch, dass clang_codeCompleteAt erst am Anfang eines Tokens aufgerufen werden soll und erzeugt eine Liste aller möglichen Token, wobei der Kunde verantwortlich für das Filtern der Ergebnisse mit dem potenziellen Teil-Token, das bereits im Texteditor eingegeben wurde.

Aus der Dokumentation (Schwerpunkt ist von mir):

an einer bestimmten Stelle in einer Übersetzungseinheit durchführen Code-Vervollständigung.

Diese Funktion führt die Codevervollständigung für eine bestimmte Datei, Zeile und Spalte im Quellcode durch und liefert Ergebnisse, die auf mögliche Codefragmente basierend auf dem Kontext der Vervollständigung hinweisen. Das grundlegende Modell für die Code-Vervollständigung besteht darin, dass Clang eine vollständige Quelldatei analysiert und eine Syntaxprüfung bis zu dem Ort durchführt, an dem die Codevervollständigung angefordert wurde. An diesem Punkt wird ein spezielles Code-Vervollständigungstoken an den Parser übergeben, der dieses Token erkennt und basierend auf dem aktuellen Ort in der C/Objective-C/C++ - Grammatik und dem Zustand der semantischen Analyse bestimmt, welche Vervollständigungen bereitzustellen sind. Diese Komplettierungen werden über eine neue CXCodeCompleteResults-Struktur zurückgegeben.

Die Codevervollständigung selbst wird vom Client ausgelöst, wenn der Benutzer Interpunktionszeichen oder Leerzeichen eingibt. Zu diesem Zeitpunkt wird der Ort der Codevervollständigung mit dem Cursor übereinstimmen. Zum Beispiel, wenn p ein Zeiger ist, kann Code-Vervollständigung nach dem "-" und dann nach dem ">" in p-> ausgelöst werden. Wenn der Code-Vervollständigungsort nach dem ">" liegt, liefern die Vervollständigungsergebnisse z. B. die Mitglieder der Struktur, auf die "p" zeigt. Der Client ist verantwortlich für das Platzieren des Cursors an dem Anfang des Tokens, das gerade eingegeben wird, und das Filtern der Ergebnisse, die auf dem Inhalt des Tokens basieren. Wenn zum Beispiel der Code für den Ausdruck p-> get vervollständigt wird, sollte der Client den Ort unmittelbar nach dem ">" (z. B. auf das "g" zeigend) diesem Code-Vervollständigungs-Hook bereitstellen. Dann kann der Client die Ergebnisse basierend auf dem aktuellen Token-Text ("get") filtern, wobei nur die Ergebnisse angezeigt werden, die mit "get" beginnen. Die Absicht dieser Schnittstelle besteht darin, die relativ hohe Latenzzeit für die Erfassung der Ergebnisse der Codevervollständigung von der Filterung der Ergebnisse pro Zeichen zu trennen, die eine geringere Latenz haben muss.

Aufnehmen der modifizierten zweites Beispiel:

int main (int argc, char **argv) { 
    int i = sumLi 
    // ^
} 

Code-Vervollständigung sollte an der markierten Stelle (das heißt zu Beginn des Tokens) aufgerufen werden. Clang könnte dann eine lange Liste von Ergebnissen führt zum Beispiel einschließlich:

  • argc
  • sumListNode(<# struct List *Node #>)

Es ist dann an Sie, diese Liste zu filtern, basierend auf den teilweise eingegeben sumLi Token und hält die nur relevante Vervollständigung: sumListNode.

Wenn Sie elisp verstehen, Klirren der Quellen enthalten eine automatische Vervollständigung Bibliothek für Emacs, die ein gutes Beispiel für diese Zwei-Ebenen-Implementierung ist:

trunk/utils/clang-completion-mode.el

+0

Thank you! Das hat mein Problem ziemlich gelöst. Mein Texteditor sagt, dass Node -> (hier) Spalte 33 ist. Wenn Sie clang selbst ausführen, wird in Spalte 27 der Fehler angezeigt, dass dort nichts vorhanden ist. Es sieht so aus, als würden Tabs als einzelne Spalte gezählt. Für das zweite Beispiel werden immer noch viele Schlüsselwörter ausgegeben, anstatt nur die erwarteten 'sumListNodes'. Ohne einen Zwischenraum dazwischen würden Clangs Vorschläge nicht kompiliert. Ich habe das über die ganze Kolumne ausprobiert, um sicher zu gehen. Ich denke, es ist für mich, die tatsächlichen Möglichkeiten zu sortieren? – John

+0

Hoppla, ich sollte hinzufügen, dass ich die test.c so bearbeitet habe, dass zu diesem Zeitpunkt ein ganzzahliger Wert erwartet würde und dass eine struct List im Bereich deklariert wurde. Nur um sicher zu gehen, dass es einen realen Kontext gab, den Klänge verstehen konnten. Es gab aber immer noch nicht das, was ich erwartet hatte. Zum Beispiel würde int i = sumLilong nicht kompilieren, aber es gab 'long' als Vorschlag mit gleicher Priorität wie sumListNodes. – John

+0

Ich habe meine Antwort bearbeitet, um diese Fragen zu beantworten. – Francesco