2016-04-03 6 views
0

Ich versuche ein IntelliJ-Plugin zu erstellen (hauptsächlich zu Lernzwecken). Mein Ziel ist es, dass das Plugin durch Drücken einer Tastenkombination einen entsprechenden PHP-Unit-Test-Methoden-Stub in der Testdatei generiert.Plugin: Wie fügt man eine neue Methode in die bestehende PHP-Klasse ein?

Also sagen wir, Db.php ist offen, das Drücken auf Ctrl+Shift+U das Plugin wird eine Einheit Teststub in DbTest.php erstellen.

Bisher habe ich herausgefunden, wie man den Methodennamen am Cursor bekommt und wie man die entsprechende Unit-Testdatei (d. H. Db =>DbTest) als PsiFile findet.

PsiFile[] search = FilenameIndex.getFilesByName(project, testFileName, scope); //scope is the test directory 
PsiFile testFile = search[0]; 

Was ich kann nicht herausfinden ist , wie die diese erzeugt neue Methode Stub einfügen in testFile und speichern Sie die Änderungen?

P.S. Ich sehe, es gibt eine createMethodFromText Funktion, aber wie bekomme ich die PsiClass von PsiFile? Wie speichere ich die Änderungen?

Antwort

1

Es sind nur ein paar einfache Schritte.

  1. Finden PhpClass Sie in eine neue Methode eingefügt werden soll. Wie Sie bereits PsiFile haben, können Sie entweder einen Baum manuell durchqueren oder PhpElementVisitor verwenden.

    1.1. Um einen Baum manuell zu durchlaufen, können Sie die Methode PsiTreeUtil#findChildOfType verwenden. In Ihrem Fall müssen Sie zuerst GroupStatement finden, dann die Klasse, die Sie benötigen.

    1.2. Rufen Sie PsiElement#accept Methode (PsiFile ist eine Instanz von PsiElement) mit PhpElementVisitor mit überschrieben #visitPhpGroupStatement und #visitPhpClass Methoden zur Verfügung gestellt.

  2. Verwenden Sie PhpPsiElementFactory#createMethod, um die neue Methode aus Text zu erstellen. Beachten Sie, dass diese Klasse kein Teil der öffentlichen API ist. Daher kann sie theoretisch in Zukunft einfach geändert/verschoben/entfernt werden/was auch immer.

  3. Verwenden Sie PsiElement#add (PhpClass ist auch eine Instanz von PsiElement), um die Methode in die Klasse einzufügen.

Das ist alles. Sie müssen die Änderungen nicht explizit speichern.

0

Hier ist, was am Ende für mich funktionierte. Danke allen für die Hilfe

for (int i = 0; i < found.getTextLength(); i++) { 
    PsiElement ele = found.findElementAt(i); 
    PhpClass phpClass = PsiTreeUtil.getParentOfType(ele, PhpClass.class); 

    if (phpClass != null) { 
     Method methodExists = findMethod(phpClass, methodName); 

     if (methodExists == null) { 
      new WriteCommandAction.Simple(phpClass.getProject(), phpClass.getContainingFile()) { 
       @Override 
       protected void run() throws Throwable { 
        PsiElement brace = phpClass.getLastChild(); 

        if (brace != null) { 
         Method method = PhpPsiElementFactory.createMethod(phpClass.getProject(), "public function " + methodName + "() {\n\n}"); 
         CodeStyleManager styleManager = CodeStyleManager.getInstance(getProject()); 
         styleManager.reformat(method); 
         PsiElement newMethod = phpClass.addBefore(method, brace); 
         PsiNavigateUtil.navigate(newMethod); 
        } 
       } 
      }.execute(); 
     } else { 
      PsiNavigateUtil.navigate(methodExists); 
     } 

     break; 
    } 
}