Was ist, wenn es keinen statischen Analysator für Ihre Lieblingssprache gibt?

Nun, wenn Ihre Lieblingssprache Russisch, Englisch usw. bedeutet, dann ist dies in einem anderen Hub . Und wenn die Programmier- oder Auszeichnungssprache, dann schreiben Sie den Analysator natürlich selbst! Auf den ersten Blick ist es sehr schwierig, aber zum Glück gibt es fertige mehrsprachige Tools, mit denen sich die Unterstützung für eine neue Sprache relativ einfach hinzufügen lässt. Heute werde ich zeigen, wie man mit relativ wenig Zeit die Modelica- Sprachunterstützung zum PMD-Analyser hinzufügt.


Wissen Sie übrigens, was die Qualität der Codebasis, die aus einer Folge von idealen Pull-Anforderungen erhalten wird, beeinträchtigen kann? Die Tatsache, dass Programmierer von Drittanbietern anstelle einer kompetenten Abstraktion Teile des vorhandenen Projektcodes in ihre Patches kopierten. Sie müssen zugeben, dass es bis zu einem gewissen Grad noch schwieriger ist, einen solchen banalen Code zu finden als einen Code mit schlechter Qualität. Er ist von hoher Qualität und wird bereits sorgfältig getestet. Daher reicht die lokale Überprüfung hier nicht aus. Sie müssen die gesamte Codebasis im Auge behalten, aber dies ist für eine Person nicht einfach Das Hinzufügen der vollständigen Unterstützung von Modelica (ohne das Erstellen spezifischer Regeln) zum Status "Primitive Überprüfungen ausführen können" dauerte ungefähr eine Woche. Dann kann an einem Tag häufig nur die Unterstützung für Copy-Paste-Detektoren hinzugefügt werden!


Was ist Modelica noch?


Modelica ist, wie der Name schon sagt, eine Sprache zum Schreiben von Modellen physikalischer Systeme. Tatsächlich nicht nur physikalisch: Es ist möglich, chemische Prozesse, das quantitative Verhalten von Tierpopulationen usw. zu beschreiben - das wird durch Differentialgleichungssysteme der Form der(X) = f(X) , wobei X der Vektor von Unbekannten ist. Imperative Codeteile werden ebenfalls unterstützt. Partielle Differentialgleichungen werden nicht ausdrücklich unterstützt, aber es ist möglich, den Untersuchungsbereich in Teile zu unterteilen (wie wir es wahrscheinlich in einer allgemeinen Sprache getan hätten) und dann die Gleichungen für jedes Element aufzuschreiben, wodurch das Problem auf das vorherige reduziert wird. Der Trick von Modelka ist, dass die Lösung für diesen der(X) = f(X) beim Compiler liegt: Sie können einfach den Löser in den Einstellungen ändern, die Gleichung muss nicht linear sein usw. Kurz gesagt, es gibt einige Pluspunkte (ich schrieb die Formel aus dem Lehrbuch - und es hat funktioniert) und die Nachteile (mit mehr Abstraktion bekommen wir weniger Kontrolle). Eine Einführung in Modelika ist das Thema eines separaten Artikels (der bereits mehrmals auf Habré erschienen ist) und sogar eines ganzen Zyklus. Heute interessiert es mich als offenen und mit mehreren Implementierungen, aber leider immer noch ein feuchter Standard.


Darüber hinaus verfügt Modelika einerseits über eine statische Typisierung (mit deren Hilfe wir einige aussagekräftige Analysen schneller erstellen können), andererseits muss der Compiler beim Instanziieren eines Modells nicht die gesamte Bibliothek vollständig überprüfen (daher ist ein statischer Analysator sehr nützlich, um "Sleeping" zu erfassen). Bugs). Schließlich gibt es im Gegensatz zu einigen C ++, für die es eine Wolke von statischen Analysatoren und Compilern mit schönen, und was am wichtigsten ist, siehe C ++ - Vorlagen Fehlerdiagnose, Compiler Modelle generieren immer noch regelmäßig einen internen Compilerfehler, was bedeutet, dass der Benutzer auch mit einem relativ einfachen Analysegerät noch genügend Platz hat, um zu helfen.


Was ist PMD?


Ich werde antworten Lied mit dem Fahrrad. Einmal wollte ich eine kleine Pull-Anfrage in die Entwicklungsumgebung für OpenModelica stellen. Als ich sah, wie das Speichern des Modells in einem anderen Teil des Codes verarbeitet wird, bemerkte ich ein kleines und nicht sehr klares Stück aus vier Codezeilen, das eine Art Invariante unterstützte. Ich verstehe nicht, mit welchen Editor-Interna er interagiert, erkenne aber, dass meine Aufgabe aus der Sicht dieses Code-Teils völlig identisch ist. Ich habe sie einfach in eine Funktion umgewandelt, damit ich sie wiederverwenden und nicht zerstören kann. Menteiner meinte, es ist wunderbar, diesen Code erst dann durch einen Funktionsaufruf an den verbleibenden zwanzig Stellen zu ersetzen. Ich habe beschlossen, mich noch nicht einzumischen, und habe nur eine weitere Kopie angefertigt mit dem aktuellen Patch. Googeln fand ich Copy-Paste Detector (CPD) - Teil des statischen PMD-Analysators - der noch mehr Sprachen als der Analysator selbst unterstützt. Nachdem ich es auf die OMEdit-Codebasis gesetzt hatte, erwartete ich, diese zwei Dutzend Stücke von vier Zeilen zu sehen. Ich habe sie nur nicht gesehen (jeder von ihnen hat die Schwelle für die Anzahl der Token einfach nicht überschritten), aber ich habe zum Beispiel die Wiederholung von fast fünfzig Zeilen C ++ - Code gesehen. Wie ich bereits sagte, ist es unwahrscheinlich, dass der Menter einfach ein riesiges Stück aus einer anderen Akte kopiert hat. In der PR konnte er dies jedoch leicht übersehen - denn der Code erfüllte per Definition bereits alle Standards des Projekts! Als ich die Beobachtung mit dem Menter teilte, stimmte er zu, dass es notwendig sein würde, im Rahmen einer separaten Aufgabe aufzuräumen.


Dementsprechend ist der Program Mistake Detector (PMD) ein leicht erweiterbarer statischer Analysator. Vielleicht berechnet er nicht die Menge der Werte, die eine Variable annehmen kann (obwohl wer weiß ...), aber um Regeln hinzuzufügen, müssen Sie nicht einmal Java kennen und den Code irgendwie ändern! Tatsache ist, dass er als erstes AST-Dateien mit Quellcodes erstellt, was nicht überraschend ist. Und wie sieht der Quell-Parsing-Baum aus? Zum XML-Parsing-Baum! Sie können die Regeln also einfach als XPath-Anforderungen beschreiben - für die sie zutreffen, geben wir eine Warnung aus. Sie haben sogar einen grafischen Debugger für die Regeln! Natürlich können komplexere Regeln als Besucher des AST direkt in Java geschrieben werden.


Konsequenz : PMD kann nicht nur für die strengen und universellen Regeln verwendet werden, die strenge Java-Programmierer für den Code des Analysators festgelegt haben, sondern auch für den lokalen Codierungsstil - selbst wenn Sie Ihre eigene lokale ruleset.xml in jedes Repository übertragen!


Stufe 1: Kopieren-Einfügen automatisch finden


Im Prinzip ist das Hinzufügen einer Unterstützung für eine neue Sprache in CPD oft sehr einfach. Ich sehe keinen Sinn darin, die Dokumentation noch einmal „wie es geht“ zu erzählen - sie ist sehr klar, strukturiert und schrittweise. Um so etwas noch einmal zu erzählen - spielen Sie nur in einem beschädigten Telefon. Ich beschreibe besser, was dich erwartet (TLDR: ist okay) :


  • Der Analysator (sowohl PMD als auch CPD) wird auf dem Github im PMD / PMD- Repository entwickelt
  • Der Visual Rule Debugger wurde in ein separates PMD / PMD-Designer- Repository verschoben. Bitte beachten Sie, dass der fertige jar-Spitzname automatisch in die PMD-Binärdistribution eingebettet wird, die Gradle im vorherigen Repository für Sie sammelt. Sie müssen hierfür nicht speziell pmd-designer klonen.
  • Das Projekt hat eine Entwicklerdokumentation . Der, den ich las, war sehr detailliert. Stimmt, ein bisschen veraltet, aber das wird von der zweiten Pull-Anfrage behandelt :)

Ich warne Sie, dass ich auf Ubuntu entwickle. Unter Windows sollte es auch einwandfrei funktionieren - sowohl in Bezug auf die Qualität als auch im Sinne einer etwas anderen Art, Tools zu starten.


Um CPD eine neue Sprache hinzuzufügen, müssen Sie nur ...


  • ACHTUNG: Wenn Sie die vollständige Unterstützung für PMD vor der Veröffentlichung von PMD 7 wünschen, sollten Sie direkt zu Level 2 übergehen, da die normale Unterstützung für den einfachen Weg durch die fertige Antlr-Grammatik Gerüchten zufolge in Version 7 angezeigt wird und ein bisschen ...)
  • Gabeln Sie das PMD / PMD-Repository .
  • Suchen Sie in antlr / grammars-v4 eine fertige Grammatik für Ihre Sprache - natürlich müssen Sie sie selbst schreiben, wenn die Sprache intern ist, aber für Modelika wurde sie beispielsweise gefunden. Hier müssen Sie natürlich die Formalitäten mit Lizenzen einhalten - ich bin kein Anwalt, aber ich muss zumindest die Quelle angeben, von der ich kopiert habe.
  • Danach müssen Sie das Modul pmd-<your language name> erstellen, es zu Gradle hinzufügen und die Grammatikdatei dort pmd-<your language name> . Nachdem Sie zwei Seiten der stressfreien Dokumentation gelesen haben, wiederholen Sie das Assembler-Skript aus dem Modul für Go, ein paar Klassen zum Laden des Moduls durch Reflektion. Nun, es gibt noch eine Kleinigkeit ...
  • Korrigieren Sie die Referenzausgabe in einem der Tests, da CPD jetzt eine weitere Sprache unterstützt! Wie findest du diesen Test? Ganz einfach: Er möchte den Build abbrechen .
  • GEWINN! Es ist ganz einfach, vorausgesetzt, es gibt eine fertige Grammatik

Jetzt können Sie im Stammverzeichnis des pmd-Repositorys ./mvnw clean verify , während Sie in pmd-dist/target unter anderem die Binärdistribution in Form eines Zip-Archivs erhalten, das Sie mit ./bin/run entpacken und ausführen ./bin/run.sh cpd --minimum-tokens 100 --files /path/to/source/dir --language <your language name> aus dem entpackten Verzeichnis. Grundsätzlich können Sie ../mvnw clean verify in Ihrem neuen Modul ../mvnw clean verify , was die Assemblierung drastisch beschleunigt. Anschließend müssen Sie jedoch den zusammengesetzten JAR-Kurznamen korrekt in die entpackte ../mvnw clean verify (z. B. einmal zusammengesetzt, nachdem Sie ein neues Modul registriert haben).


Stufe 2: Auffinden von Fehlern und Verstößen gegen den Styleguide


Wie gesagt, in PMD 7 wird volle Unterstützung für Antlr versprochen . Wenn Sie, wie ich, nicht auf die Veröffentlichung des Meeres warten möchten, müssen Sie irgendwo eine Beschreibung der Grammatik der Sprache im JJTree-Format abrufen. Vielleicht können Sie die Unterstützung eines beliebigen Parsers selbst modelica.g4 - die Dokumentation besagt, dass dies möglich ist, aber sie sagen nicht, wie genau ... Ich habe nur modelica.g4 aus demselben Repository mit Grammatiken für Anltr als Basis genommen und es manuell in JJTree neu erstellt. Wenn sich herausstellt, dass die Grammatik eine Verarbeitung der vorhandenen ist, geben Sie die Quelle an, überprüfen Sie die Einhaltung der Lizenzen und. etc.


Übrigens ist es unwahrscheinlich, dass eine Person, die sich mit Parsergeneratoren aller Art auskennt, überrascht. Vorher habe ich es ernsthaft benutzt, es sei denn, ich habe selbst Stammkunden und Parser-Kombinatoren auf Scala geschrieben. Daher hat mich das Offensichtliche anfangs tatsächlich traurig gemacht: AST kommt natürlich von modelica.g4 , aber es sieht nicht sehr klar und „brauchbar“ aus: Es gibt Wolken von zusätzlichen Knoten darin, und wenn Sie nicht auf die Token schauen, sondern nur auf Knoten ist nicht immer klar, wo zum Beispiel der Zweig then endet und else beginnt.


Auch hier werde ich die Dokumentation zu JJTree und ein gutes Tutorial nicht nacherzählen - diesmal jedoch nicht, weil das Original mit Details und Klarheit glänzt, sondern weil ich es selbst nicht vollständig herausgefunden habe, sondern weil die Dokumentation falsch, aber mit Zuversicht erneut übertragen wurde. offensichtlich schlimmer als kein Nacherzählen. Ich hinterlasse lieber einen kleinen Hinweis, den ich auf dem Weg herausgefunden habe:


  • Erstens setzt der JavaCC-Parser-Beschreibungscode Java-Einfügungen voraus, die in den generierten Parser eingeschrieben werden
  • Seien Sie nicht durch die Tatsache verwirrt, dass beim Erstellen eines AST Syntax wie [ Expression() ] optional bedeutet und im Kontext der Beschreibung von Tokens ein Zeichen ausgewählt wird, wie in einem regulären Ausdruck. Soweit ich die Erklärung der PMD-Entwickler verstehe, sind dies ähnliche Konstruktionen, die eine so unterschiedliche Bedeutung haben - Vermächtnis, Sir ...
  • Für den StoredDefinition (in meinem Fall StoredDefinition ) müssen Sie den Typ anstelle von void angeben (d. H. ASTStoredDefiniton ).
  • Wenn Sie die Syntax #void nach dem Knotennamen verwenden, können Sie sie vor dem analysierten Baum verbergen (das heißt, es #void sich nur darauf aus, welche Quelle die richtige ist und welche nicht und wie die anderen Knoten verschachtelt werden).
  • Mit einer Konstruktion des Formulars void SimpleExpression() #SimpleExpression(>1) wir sagen, dass der Knoten im resultierenden AST angezeigt werden muss, wenn er mehr als einen Nachkommen hat. Dies ist sehr praktisch, wenn Ausdrücke mit vielen Operatoren mit unterschiedlichen Prioritäten beschrieben werden: Das heißt, aus Sicht des Parsers ist die einsame Konstante 1 so etwas wie LogicExpression(AdditiveExpression(MultiplicativeExperssion(Constant(1)))) - geben Sie alle n Ebenen der Operationsprioritäten ein - aber Der Code des Analysators erhält nur die Constant(1)
  • Der Knoten verfügt über ein Standardvariablen- image (siehe getImage , setImage ), das normalerweise das "Wesentliche" dieses Knotens setImage : Für einen Knoten, der dem Namen einer lokalen Variablen entspricht, ist es logisch, das übereinstimmende Token mit dem Bezeichner in image zu kopieren (standardmäßig alle Token von Bäume werden weggeworfen, daher lohnt es sich, die darin enthaltene Bedeutung zu kopieren, wenn es sich um eine Variable handelt und nicht nur um Stichwörter.)
  • LOOKAHEAD - nun, dies ist ein separates Lied, dem sogar ein separates Kapitel in der Dokumentation gewidmet ist
    • Grob gesagt können Sie in JavaCC einen Knoten nicht zurückwerfen und versuchen, ihn anders zu analysieren. Sie können jedoch im Voraus nach vorne schauen und entscheiden, ob Sie ihn verwenden möchten oder nicht
    • im einfachsten Fall, wenn eine JavaCC-Warnung angezeigt wird, Sie sagen nur in der Kopfzeile LOOKAHEAD = n und es treten mysteriöse Parsing-Fehler auf, da im Allgemeinen anscheinend nicht alle Probleme gelöst werden können (abgesehen davon, dass Sie durch das Setzen einiger Milliarden Token eine Vorschau von allem erhalten, aber nicht die Tatsache, dass dies so funktioniert). .)
    • Vor dem Namen des eingebetteten Knotens können Sie explizit angeben, anhand wie vieler Token Sie hier definitiv die endgültige Entscheidung treffen können
    • Wenn es im allgemeinen Fall keine feste Anzahl von Token gibt, können Sie sagen: "Gehen Sie hierher, wenn es uns zuvor gelungen ist, ab diesem Punkt ein solches Präfix zu finden - und dann die übliche Beschreibung des Teilbaums."
    • Vorsicht: Im Allgemeinen kann JavaCC die Korrektheit der LOOKAHEAD Direktiven nicht überprüfen - es vertraut Ihnen, also finden Sie zumindest den mathematischen Beweis heraus, warum ein solcher Lookahead ausreicht ...

Nachdem Sie nun eine Beschreibung der Grammatik der Sprache im JJTree-Format haben, können Sie mit diesen einfachen 14 Schritten die Sprachunterstützung hinzufügen. Die meisten von ihnen haben die Form "Eine Klasse ähnlich der Implementierung für Java oder VM erstellen, aber angepasst". Ich stelle nur typische Funktionen fest. Einige davon werden in der Hauptdokumentation angezeigt, wenn sie meine Anforderung zum Abrufen der Dokumentation akzeptieren:


  • Wenn Sie das Entfernen aller generierten Dateien im Assemblerskript alljavacc.xml (das sich in Ihrem neuen Modul befindet) alljavacc.xml , können Sie diese von target/generated-sources in den alljavacc.xml übertragen. Aber besser nicht. Höchstwahrscheinlich wird nur ein kleiner Teil geändert, daher sollten Sie sich besser nur um das Löschen einiger weniger kümmern: Sie mussten die Standardimplementierung ändern, in den Quellbaum kopieren, der Liste der gelöschten Dateien hinzufügen, diese Datei neu erstellen - und jetzt verwalten Sie die Datei - speziell diese Datei . Andernfalls wird es schwierig sein, herauszufinden, was genau geändert wurde, und die Unterstützung kann kaum als angenehm bezeichnet werden.
  • Nachdem Sie den PMD-Hauptmodus implementiert haben, können Sie Ihrem JJTree-Parser auf einfache Weise auch eine Bindung für CPD anhängen, ähnlich wie bei Java oder einer anderen verfügbaren Implementierung
  • Denken Sie daran, eine Methode zu implementieren, die den Hostnamen für XPath-Abfragen zurückgibt. In der Standardimplementierung wird entweder eine unendliche Rekursion erhalten (der Name des Knotens steht über toString und umgekehrt) oder es ist im Allgemeinen auch nicht möglich, den Baum in PMD Designer zu betrachten und die Grammatik ohne diesen zu debuggen
  • Ein Teil der Komponentenregistrierungen erfolgt durch Hinzufügen von Textdateien von vollständig qualifizierten Eintrittspunkten für Klassennamen zu META-INF/services
  • Was in den Regeln deklarativ beschrieben werden kann (z. B. eine detaillierte Beschreibung der Prüfung und Beispiele für Fehler), wird nicht im Code, sondern in der category/<language name>/<ruleset>.xml In jedem Fall müssen Sie Ihre Regeln dort registrieren
  • ... aber bei der Implementierung der Tests wird anscheinend ein gewisser, möglicherweise selbst entwickelter Mechanismus zur automatischen Erkennung aktiv verwendet
    • Wenn Ihnen gesagt wird, dass Sie "für jede Version der Sprache einen einfachen Test hinzufügen" - besser gesagt, nicht streiten, sagen sie "Ich brauche es nicht, es funktioniert so" - ist dies möglicherweise der automatische Erkennungsmechanismus
    • Wenn Sie einen Test für eine bestimmte Regel mit einem Klassenkörper sehen, der nur einen Kommentar enthält, // no additional unit tests , dann sind dies keine Tests, sie liegen einfach in den Ressourcen in Form einer XML-Beschreibung der Eingabedaten und der erwarteten Analysereaktionen, und zwar sofort: einige richtige und einige falsche Beispiele.

Eine kleine, aber wichtige Aufgabe: Beende den PMD Designer


Vielleicht können Sie alles ohne Visualizer debuggen. Aber warum? Erstens ist es sehr einfach zu beenden. Zweitens wird es Ihren Benutzern, die mit Java nicht vertraut sind, sehr helfen: Sie sind einfach und unkompliziert (wenn dies überhaupt für XPath gilt) oder zumindest ohne Neukompilierung können PMD einfache Muster beschreiben, die ihnen nicht gefallen (im einfachsten Fall) - Ein Styleguide wie „Der Name eines Modellpakets beginnt immer mit einem Kleinbuchstaben p“).


Im Gegensatz zu anderen Fehlern, die sofort sichtbar sind, sind Probleme mit PMD Designer ziemlich heimtückisch: Es scheint, dass Sie bereits verstanden haben, dass die Java-Inschrift auf der rechten Seite des Menüs keine Schaltfläche ist, sondern eine Dropdown-Liste der O_o-Sprachauswahl, in der sie bereits angezeigt wurde Modelica, weil im Klassenpfad ein neues Modul mit der Registrierung von Einstiegspunkten erschienen ist. Aber hier wählen Sie Ihre Sprache, laden eine Testdatei herunter und sehen AST. Und es scheint ein Sieg zu sein, aber es ist irgendwie schwarz und weiß, und der hervorgehobene Teilbaum könnte im Text hervorgehoben werden - obwohl nein, das Highlight ist da, aber es wird schief aktualisiert - und doch, wie haben sie nicht geraten, die gefundenen Übereinstimmungen mit XPath hervorzuheben ... Sie schätzen den Arbeitsaufwand bereits ein und überlegen sich, ob Sie die nächste Pull-Anforderung durchführen möchten. Dann entscheiden Sie sich jedoch versehentlich, die Sprache auf Java umzustellen und den Quellcode des PMD selbst herunterzuladen ... Oh! Es ist farbig! .. Und das Teilbaum-Highlight funktioniert! Äh ... und es stellt sich heraus, dass es normalerweise die gefundenen Übereinstimmungen hervorhebt und Textteile in das Feld rechts von der Anforderung schreibt ... Wenn beim Rendern der Benutzeroberfläche eine Ausnahme im JavaFX-Code auftritt, wird das Rendern unterbrochen, aber nicht an die Konsole gedruckt ...


Im Allgemeinen müssen Sie nur eine ma-a-scarlet-Klasse hinzufügen, um die auf regulären Ausdrücken basierende Syntax hervorzuheben. In meinem Fall war es net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.ModelicaSyntaxHighlighter , das in der AvailableSyntaxHighlighters Klasse registriert werden muss. Beachten Sie, dass beide Änderungen im pmd-designer Repository vorgenommen werden, dessen Assembly-Artefakt in Ihre Binärdistribution eingefügt werden muss.


Am Ende sieht es ungefähr so ​​aus (GIF aus README im PMD Designer-Repository):


PMD Designer bei der Arbeit


Zwischensumme


Wenn Sie alle diese Levels abgeschlossen haben, haben Sie jetzt:


  • Kopier- und Einfügedetektor
  • Regeln-Engine
  • Visualizer zum Debuggen und Analysieren von AST (wie wir bereits gesehen haben, sind nicht alle Grammatiken einer Sprache gleich nützlich!)
  • Derselbe Visualizer zum Debuggen von XPath-Regeln, den Ihre Benutzer schreiben können, ohne PMD neu zu kompilieren, und mit allgemeinen Java-Kenntnissen (XPath ist natürlich auch nicht BASIC, aber es ist mindestens eine Standard- und keine lokale Abfragesprache).

Ich hoffe, Sie haben auch Verständnis dafür, dass die Grammatik jetzt eine stabile API für Ihre Implementierung der Sprachunterstützung ist - ändern Sie sie nicht (oder vielmehr die darin beschriebene Funktion der Konvertierung der Quelle in AST), es sei denn, dies ist absolut notwendig, und wenn Sie sie geändert haben, benachrichtigen Sie sie als brechende Änderung. und dann werden die Benutzer verärgert sein: Höchstwahrscheinlich werden nicht alle Tests für ihre Regeln schreiben, aber es ist sehr traurig, wenn die Regeln den Code überprüft und dann ohne Vorwarnung gestoppt haben - fast wie ein Backup, das plötzlich kaputt gegangen ist und vor einem Jahr ...


Die Geschichte endet nicht dort: Zumindest müssen einige nützliche Regeln geschrieben werden.


Das ist aber noch nicht alles: PMD unterstützt nativ Gültigkeitsbereiche und Deklarationen. Jedem AST-Knoten ist ein Bereich zugeordnet: der Körper der Klasse, die Funktion, die Schleife ... Im schlimmsten Fall die gesamte Datei! Und in jedem Bereich gibt es eine Liste von Definitionen (Deklarationen), die direkt enthalten sind. Wie in anderen Fällen wird vorgeschlagen, Modellika analog zu anderen Sprachen zu implementieren (aber zum Zeitpunkt des Schreibens ist die Logik in meiner Pull-Anfrage, ganz offen gesagt, roh). scopes declarations visitor, - ScopeAndDeclarationFinder , — , , , - , read-only AST. , .


 public class ModelicaHandler extends AbstractLanguageVersionHandler { // ... @Override public VisitorStarter getSymbolFacade() { return new VisitorStarter() { @Override public void start(Node rootNode) { new SymbolFacade().initializeWith((ASTStoredDefinition) rootNode); } }; } } 


PMD . , «» Clang Static Analyzer , . , CPD ( ), .

Source: https://habr.com/ru/post/de474920/


All Articles