GReQL Regeln

Aus JACK Wiki
Zur Navigation springen Zur Suche springen

Beispiele für statische Prüfregeln für Java-Code

Codestil

 <rule type="absence" points="0">
   <query>from x : V{MethodDeclaration}
          with
             x.name=capitalizeFirst(x.name) and
             x.constructor="false"
          report 0 end
   </query>
   <feedback prefix="Hinweis (ohne Punktabzug)">Du verwendest Methodennamen, die mit einem Großbuchstaben beginnen. Das ist möglich, aber es entspricht nicht dem üblichen Programmierstil für Java.</feedback>
 </rule>

Diese Regel sucht nach groß geschriebenen Methodennamen.

 <rule type="absence" points="0">
   <query>from x : V{TypeDeclaration}
          with
             not (x.name=capitalizeFirst(x.name))
          report 0 end
   </query>
   <feedback prefix="Hinweis (ohne Punktabzug)">Du verwendest Klassennamen, die nicht mit einem Großbuchstaben beginnen. Das ist möglich, aber es entspricht nicht dem üblichen Programmierstil für Java.</feedback>
 </rule>

Diese Regel sucht nach klein geschriebenen Klassennamen.

 <rule type="absence" points="0">
   <query>from x : V{VariableDeclarationFragment}
          with
             x.name=capitalizeFirst(x.name) and
             isEmpty(from m : V{Modifier} with x &lt;--&amp;{FieldDeclaration} --> m and m.name="final" report m end)
          report 0 end
   </query>
 <feedback prefix="Hinweis (ohne Punktabzug)">Du verwendest Variablennamen, die mit einem Großbuchstaben beginnen. Das ist möglich, aber es entspricht nicht dem üblichen Programmierstil für Java.</feedback>
 </rule>

Diese Regel sucht nach groß geschriebenen Variablennamen, wobei als "final" deklarierte Klassenvariablen ausgelassen werden.

Einfache Inhalte

 <rule type="presence" points="2">
   <query>from m : V{MethodDeclaration}, s : V{StringLiteral}
          with
             m.name="m" and
             m -->{Child}* s and
             s.content = "\"Zeichenkette\""
          report 0 end
   </query>
   <feedback>Deine Lösung verwendet nicht den String "Zeichenkette".</feedback>
 </rule>

Diese Regel sucht in der Methode m nach einem String-Literal mit einem vorgegebenen Inhalt.

 <rule type="absence" points="2">
   <query>from m : V{MethodDeclaration}, s : V{StringLiteral}
          with
             m.name="m" and
             m -->{Child}* s and
             stringLength(s.content) > 4
          report s.line as "line" end
   </query>
   <feedback>Du verwendest in Zeile {line} ein festes String-Literal. Ist deine Lösung allgemeingültig?</feedback>
 </rule>

Diese Regel sucht in der Methode m nach einem String-Literal der Länge 4 oder länger (inklusive Anführungszeichen) und meldet es mit Angabe der Zeilennummer als Fehler.

 <rule type="absence" points="0">
   <query>from p : V{PackageDeclaration}
          report 0 end
   </query>
   <feedback prefix="Paketdefinition">Deine Lösung beinhaltet eine package-Angabe. Bitte entferne diese.</feedback>
 </rule>

Diese Regel sucht nach Paketdefinitionen und meldet diese als Fehler.

 <rule type="absence" points="1">
   <query> from p : V{ImportDeclaration}
          report 0 end
  </query>
  <feedback prefix="Importdefinition"> Deine Lösung beinhaltet eine import-Angabe. Bitte entferne diese.</feedback>
 </rule>

Diese Regel sucht nach Importdefinitionen und meldet diese als Fehler.

 <rule type="absence" points="1">
    <query>from u : V{CompilationUnit}, x : V{MethodInvocation}, y : V{SimpleName}
           with
              u -->* x -->{ElementExpression} y and
              x.name="exit" and
              y.name="System"
           report u.name as "name", x.line as "line" end
   </query>
   <feedback>Der Aufruf von "System.exit()" in der Datei {name} in Zeile {line} ist nicht gestattet.</feedback>
 </rule>

Diese Regel sucht nach Aufrufen von System.exit() und melde diese unter Angabe von Klasse und Zeilennummer als Fehler.

  <rule type="absence" points="1">
    <query>from x : V{MethodInvocation}, y, z : V{SimpleName}
           with
              x -->{ElementExpression}&amp;{QualifiedName} -->{QualifiedNameName} y and
              x -->{ElementExpression}&amp;{QualifiedName} -->{QualifiedNameQualifier} z and
              (x.name="print" or x.name="println") and
              y.name="out" and z.name="System"
           report x.line as "line" end
   </query>
   <feedback>You have a print statement in line {line}. Are you sure you want to print to console instead of returning?</feedback>
  </rule>

Diese Regel sucht nach Aufrufen von System.out.print() oder System.out.println() und melde diese unter Angabe von Klasse und Zeilennummer als Fehler.

Kontrollstrukturen

 <rule type="absence" points="4">
   <query>from m : V{MethodDeclaration}
          with
             m.name="m" and
             isEmpty(m -->{Child}*&amp;{WhileStatement}) and
             isEmpty(m -->{Child}*&amp;{DoStatement}) and
             isEmpty(m -->{Child}*&amp;{ForStatement}) and
             isEmpty(m -->{Child}*&amp;{EnhancedForStatement})
          report 0 end
   </query>
   <feedback>In der Methode "m()" wird kein Schleifenkonstrukt verwendet.</feedback>
 </rule>

Diese Regel überprüft, ob Methode m ein beliebiges Schleifenkonstrukt enthält.

 <rule type="absence" points="2">
   <query>from u : V{CompilationUnit}, x : V{IfStatement}
          with
             ( not isEmpty(u -->* x -->{IfStatementThenStatement}&amp;{EmptyStatement}) or
               (not isEmpty(u -->* x -->{IfStatementThenStatement}&amp;{Block}) and isEmpty(u -->* x -->{IfStatementThenStatement}&amp;{Block} -->{Child}))
             ) and
             ( not isEmpty(u -->* x -->{IfStatementElseStatement}&amp;{EmptyStatement}) or
               (not isEmpty(u -->* x -->{IfStatementElseStatement}&amp;{Block}) and isEmpty(u -->* x -->{IfStatementElseStatement}&amp;{Block} -->{Child}))
             )
          report u.name as "name", x.line as "line" end
   </query>
   <feedback>In der Datei {name} enthält das if-Statement in Zeile {line} in beiden Zweigen keinen Code und ist dadurch sinnlos.</feedback>
 </rule>

Diese Regel sucht nach einer if-Anweisung, die nur leere Zweige enthält und meldet eine solche Anweisung als Fehler.

 <rule type="absence" points="2">
   <query>from u : V{CompilationUnit}, x : V{IfStatement}
          with
             not isEmpty(u -->* x -->{IfStatementThenStatement}&amp;{EmptyStatement}) and
             isEmpty(x -->{IfStatementElseStatement}&amp;{Statement})
          report u.name as "name", x.line as "line" end
   </query>
   <feedback>In der Datei {name} endet das if-Statement in Zeile {line} hinter der Bedingung sofort mit einem Semikolon. Die Bedingung ist dadurch wirkungslos und die folgende Anweisung wird immer ausgeführt.</feedback>
 </rule>

Diese Regel sucht nach einer if-Anweisung, die keine Zweige enthält und meldet eine solche Anweisung als Fehler.

 <rule type="absence" points="2">
   <query>from u : V{CompilationUnit}, x : V{WhileStatement}
          with
             not isEmpty(u -->* x -->{WhileStatementBody}&amp;{EmptyStatement}) or
             (not isEmpty(u -->* x -->{WhileStatementBody}&amp;{Block}) and
             isEmpty(u -->* x -->{WhileStatementBody}&amp;{Block} -->{Child}))
          report u.name as "name", x.line as "line" end
   </query>
   <feedback>In der Datei {name} besteht die while-Schleife in Zeile {line} nur aus einer Abbruchbedingung und ist dadurch sinnlos.</feedback>
 </rule>

Diese Regel sucht nach einer while-Schleife, die nur aus einer Abbruchbedingung besteht und meldet eine solche Schleife als Fehler.

 <rule type="presence" points="1">
    <query>from m : V{MethodDeclaration}, n : V{MethodDeclaration}
           with
              m (-->{Child}*&amp;{MethodInvocation} -->{Access}&amp;{MethodDeclaration})* n and
              n -->{Child}*&amp;{MethodInvocation} -->{Access} m and
              m.name="m"
           report 0 end
   </query>
   <feedback prefix="Rekursionscheck"> Die Methode "m()" enthält nicht die geforderte Rekursion.</feedback>
 </rule>

Diese Regel überprüft, ob Methode m rekursiv arbeitet. Dabei ist es egal, ob sich die Methode direkt selber aufruft, oder über einen oder mehrere Zwischenschritte aufgerufen wird.

 <rule type="presence" points="5">
    <query>from m : V{MethodDeclaration}
           with
              m (-->{Child}*&amp;{MethodInvocation} -->{Access}&amp;{MethodDeclaration}) m and
              m.name="m"
           report 0 end
   </query>
   <feedback prefix="Rekursionscheck">Die Methode "m()" enthält nicht die geforderte Rekursion.</feedback>
 </rule>

Diese Regel überprüft, ob Methode m rekursiv arbeitet und sich insbesondere ohne Zwischenschritte über andere Methoden selber wieder aufruft.

Methoden

 <rule type="presence" points="4">
   <query>from t : V{TypeDeclaration}, m : V{MethodDeclaration}
          with
             t.name="A" and
             t -->{TypeDeclarationBodyDeclarations1} m and
             hasSignature(m, "public static String method(int)")
          report 0 end
   </query>
   <feedback prefix="Signaturcheck">Die Methode "public static String method(int param)" in der Klasse "A" fehlt. Hast du die vorgegebene Methodensignatur veraendert?</feedback>
 </rule>

Diese Regel überprüft, ob Klasse A eine Methode mit einer bestimmten Signatur enthält, wobei der Name des Methodenparameters unerheblich ist.

 <rule type="presence" points="4">
   <query>from t : V{TypeDeclaration}, m : V{MethodDeclaration}
          with
             t.name="A" and
             t -->{TypeDeclarationBodyDeclarations1} m and
             hasSignature(m, "int method()") and
             isEmpty(m -->{Child}&amp;{Modifier})
          report 0 end
   </query>
   <query>from t : V{TypeDeclaration}, m : V{MethodDeclaration}, mo : V{Modifier}
          with
             t.name="A" and
             t -->{TypeDeclarationBodyDeclarations1} m and
             hasSignature(m, "int method()") and
             m --> mo and not (mo.name="private")
         report 0 end
   </query>
   <feedback prefix="Signaturcheck">Die Methode "int method()" in der Klasse "A" fehlt oder ist mit dem Modifier "private" versehen. Hast du die vorgegebene Methodensignatur veraendert?</feedback>
 </rule>

Diese Regel überprüft, ob Klasse A eine Methode mit einer bestimmten Signatur enthält, die nicht mit dem Modifier private versehen ist.

 <rule type="presence" points="1">
    <query>from t : V{TypeDeclaration}, m : V{MethodDeclaration}, pt : V{ParameterizedType}, ptt : V{SimpleType}, pta : V{SimpleType}
           with
              t.name="A" and
              t -->{TypeDeclarationBodyDeclarations1} m and
              m.name="m" and
              m -->{MethodDeclarationReturnType} pt and
              pt -->{ParameterizedTypeType} ptt and
              ptt.name="B" and
              pt -->{ParameterizedTypeTypeArguments} pta and
              pta.name="C"
           report 0 end
   </query>
   <feedback prefix="Signatur">Der Methode "public B&lt;C&gt; m()" in der Klasse "A" fehlt. Hast du die vorgegebene Methodensignatur veraendert?</feedback>
 </rule>

Diese Regel überprüft, ob Klasse A eine Methode m mit parametrisierten Rückgabetyp B<C> enthält.

Vererbungshierarchie

 <rule type="presence" points="5">
   <query>from t : V{TypeDeclaration}, st : V{SimpleType}
          with
             t.name="A" and
             st.name="B" and
             t -->{TypeDeclarationSuperclassType} st
          report 0 end
   </query>
   <feedback prefix="Typhierarchie">A ist nicht als Unterklasse von B modelliert.</feedback>
 </rule>

Diese Regel überprüft, ob Klasse A direkte Unterklasse von Klasse B ist.

 <rule type="presence" points="1">
    <query>from t : V{TypeDeclaration}, st : V{SimpleType}
           with
              t.name="A" and
              t -->{TypeDeclarationSuperInterfaceTypes} st and
              st.name="B"
           report 0 end
   </query>
   <feedback prefix="Typhierarchie">A implementiert nicht das Interface B.</feedback>
 </rule>

Diese Regel überprüft, ob Klasse A das Interface B implementiert.

 <rule type="presence" points="1">
   <query>from t : V{TypeDeclaration}, pt : V{ParameterizedType}, ptt : V{SimpleType}, pta : V{SimpleType}
          with
             t.name="A" and
             t -->{TypeDeclarationSuperInterfaceTypes} pt and
             pt -->{ParameterizedTypeType} ptt and
             ptt.name="B" and
             pt -->{ParameterizedTypeTypeArguments} pta and
             pta.name="C"
          report 0 end
   </query>
   <feedback prefix="Typhierarchie">A implementiert nicht das Interface B&lt;C&gt;.</feedback>
 </rule>

Diese Regel überprüft, ob Klasse A das Interface B<C> implementiert.

 <rule type="presence" points="3">
   <query>from u : V{TypeDeclaration}, s : V{SimpleType}
          with
             ((u -->{TypeDeclarationSuperclassType} s and s.name="Thread") or
             (u -->{TypeDeclarationSuperInterfaceTypes} s and s.name="Runnable")) and
             u.name="A"
          report 0 end
   </query>
   <feedback>In der Klasse "A" sollte entweder das Interface "Runnable" implementieren oder von "Thread" erben.</feedback>
 </rule>

Diese Regel überprüft, ob Klasse A das Interface Runnable implementiert oder von Thread erbt.

Aufrufbeziehungen

 <rule type="presence" points="5">
   <query>from u : V{TypeDeclaration}, x : V{MethodInvocation}, y : V{SimpleName}
          with
             u -->* x -->{ElementExpression} y and
             u.name="A" and
             x.name="m" and
             y.name="B"
          report 0 end
   </query>
   <feedback>In der Klasse "A" sollte "B.m()" aufgerufen werden.</feedback>
 </rule>

Diese Regel überprüft, ob Klasse A eine Methode B.m aufruft.

 <rule type="presence" points="5">
   <query>from u : V{TypeDeclaration}, x : V{MethodInvocation}, y : V{SimpleName}, z : V{VariableDeclarationStatement}, f : V{VariableDeclarationFragment}, t : V{SimpleType}
          with
             u -->* x -->{ElementExpression} y and
             u -->* z -->{VariableDeclarationStatementType} t and
             u -->* z -->{VariableDeclarationStatementFragments} f and
             u.name="A" and
             x.name="m" and
             y.name=f.name and
             t.name="B"
          report 0 end
   </query>
   <feedback>In der Klasse "A" sollte "m()" auf einem Objekt vom Typ "B" aufgerufen werden.</feedback>
 </rule>

Diese Regel überprüft, ob Klasse A Methode m auf einem Objekt vom Typ B aufruft.

 <rule type="presence" points="4">
   <query>from u : V{TypeDeclaration}, m : V{MethodDeclaration}, x : V{ClassInstanceCreation}, t : V{SimpleType}
          with
             u -->{Child}* m -->* x -->{ClassInstanceCreationType} t and
             u.name="A" and
             m.name="m" and
             t.name="B"
          report 0 end
   </query>
   <feedback>In der Klasse "A" muss in Methode m() mindestens eine Instanz von "B" erzeugt werden.</feedback>
 </rule>

Diese Regel überprüft, ob Klasse A in Methode m eine Instanz von Klasse B erstellt.

Beispiele für statische Prüfregeln für UML-Modelle im XMI2-Format

Klassendiagramme

  <rule type="presence" points="11">
    <query>from x,y : V{Class}
           with
              x --> V{Property} --> V{Association} &lt;-- V{Property} &lt;-- y and
              isDefined(x.name) and x.name="A" and
              isDefined(y.name) and y.name="B"
           report 1 end
    </query>
    <feedback>Das Diagramm enthält keine Beziehung zwischen einem "A" und einem "B" oder keine Klassen mit diesen Namen.</feedback>
  </rule>

Diese Regel überprüft, ob das Modell zwei Klassen "A" und "B" enthält, die über eine Assoziation verbunden sind.

  <rule type="absence" points="0">
    <query>from x,y : V{Class}
           with
              x --> V{Property} --> V{Association} &lt;-- V{Property} &lt;-- y and
              isDefined(x.name) and x.name="A" and
              isDefined(y.name) and y.name="B"
           report 1 end
    </query>
    <feedback prefix="Hinweis">Im Diagramm sind die "B" eines "A" als eigene Klasse abgebildet. Das kannst du durch eine bessere Modellierung vermeiden.</feedback>
  </rule>

Diese Regel überprüft ebenfalls, ob das Modell zwei Klassen "A" und "B" enthält, die über eine Assoziation verbunden sind, definiert dies aber als unerwünschte Situation mit entsprechendem Feedback.

  <rule type="presence" points="11">
    <query>from x,y : V{Class}, z: V{Property}
           with
              x --> z and
              z --> V{Association} &lt;-- V{Property} &lt;-- y and
              isDefined(x.name) and x.name="A" and
              isDefined(y.name) and y.name="B" and
              isDefined(z.lower) and z.lower="1" and (not isDefined(z.upper) or z.upper="1")
           report 1 end
    </query>
    <feedback>Das Diagramm enthält keine Beziehung zwischen einem "A" und einem "B" mit der Kardinalität 1 oder keine Klassen mit diesen Namen.</feedback>
  </rule>

Diese Regel überprüft, ob das Modell zwei Klassen "A" und "B" enthält, die über eine Assoziation mit Kardinalität 1 (jedes A kennt genau ein B) verbunden sind.

  <rule type="presence" points="5">
    <query>from a,b : V{Class}, p: V{Property}
           with
              isEmpty(a -->&amp;{Property} -->&amp;{Association}) and
              b --> p and
              isDefined(p.aggregation) and p.aggregation="composite"
           report 1 end
    </query>
    <feedback>Es sollte im Diagramm zwei Klassen geben, bei denen die eine keine weiteren Bestandteile hat, während die andere weitere Bestandteile gemäß der Komposition hat.</feedback>
  </rule>

Diese Regel überprüft, ob es im Modell eine Klasse ohne ausgehende Assoziationen gibt und eine weitere, die mindestens eine ausgehende Komposition hat.

  <rule type="presence" points="5">
    <query>from x : V{Class}, y : V{Property}, z : V{PrimitiveType}
           with
              isDefined(x.name) and x.name="A" and
              x --> y and
              isDefined(y.name) and y.name="b" and
              y --> z and
              isDefined(z.name) and z.name="String"
           report 1 end
    </query>
    <feedback>Ein "A" soll ein Attribut für die Eigenschaft "b" bereitstellen.</feedback>
  </rule>

Diese Regel überprüft, ob es im Modell eine Klasse "A" mit dem Attribut "b" vom Typ "String" gibt.

  <rule type="presence" points="5">
    <query>from x : V{Class}, y : V{Operation}, z: V{Parameter}
           with
              isDefined(x.name) and x.name="A" and
              x --> y and
              isDefined(y.name) and stringLevenshteinDistance(y.name, "ausführen")&lt;3 and
              y --> z
           report 1 end
    </query>
    <feedback>Ein "A" soll eine Methode bereitstellen, mit der sie etwas ausführen kann.</feedback>
  </rule>

Diese Regel prüft, ob es im Modell eine Klasse "A" mit einer Operation gibt, deren Name "ausführen" oder ähnlich lautet.

  <rule type="absence" points="4">
    <query>let c := count(from y : V{Operation} with isDefined(y.name) report y end) in
              from x : set(1)
              with
                 c&lt;>7
              report c as "count" end
    </query>
    <feedback>Das Diagramm sollte genau 7 Methoden enthalten, enthält aber {count}.</feedback>
  </rule>

Diese Regel überprüft, ob das Modell genau 7 Methoden enthält und gibt im Falle einer anderen Anzahl diese im Feedback mit aus.

  <rule type="presence" points="5">
    <query>from x : V{Class}
           with
              isDefined(x.name) and x.name="A" and
              x.isAbstract and
              not isEmpty(x &lt;--&amp;{Generalization})
           report 1 end
    </query>
    <feedback>Das Diagramm sollte eine abstrakte Klasse "A" enthalten, von der mindestens eine Klasse erbt.</feedback>
  </rule>

Diese Regel überprüft, ob das Modell eine abstrakte Klasse "A" enthält, auf die in mindestens einer Generalisierung verwiesen wird.

  <rule type="presence" points="5">
    <query>from a,b,c,d : V{Class}
           with
              isDefined(a.name) and a.name="A" and
              isDefined(b.name) and b.name="B" and
              isDefined(c.name) and c.name="C" and
              isDefined(d.name) and d.name="D" and
              a --> V{Generalization} --> d and
              b --> V{Generalization} --> d and
              c --> V{Generalization} --> d
           report 1 end
    </query>
    <feedback>Das Diagramm sollte Klassen "A", "B" und "C" enthalten, die von einer gemeinsamen Oberklasse "D" erben.</feedback>
  </rule>

Diese Regel überprüft, ob das Modell eine Klasse "D" enthält, die drei direkte Unterklassen "A", "B" und "C" hat.

Beispiele für statische Prüfregeln für EPML

  <rule type="presence" points="5">
  	<query>from x: V{Event}
  	       with
  	          isEmpty(x &lt;--)
  	       report 0 end
  	</query>
  	<feedback prefix="Fehlerhafte Grundelemente">Es gibt kein Startevent.</feedback>
  </rule>

Diese Regel testet, ob der gegebene Graph kein Startevent hat.

  <rule type="absence" points="5">
  	<query> from x,y: V{Event}
  		with
  		   isEmpty(x &lt;--) and
  		   isEmpty(y &lt;--) and
  		   not (x=y)
  		report 0 end
  	</query>
  	<feedback prefix="Fehlerhafte Grundelemente">Es gibt mehr als ein Startevent.</feedback>
  </rule>

Diese Regel testet, ob der gegebene Graph mehr als ein Startevent hat.

  <rule type="absence" points="3">
  	<query> from x,y: V{Element, ^Connector}
  		with
  		   not (x.name="") and
  		   x.name = y.name and
  		   not (x = y)
  		report x.name as "name" end
  	</query>
  	<feedback prefix="Anmerkung zur Namensgebung">Es gibt mindestens zwei Elemente mit demselben Namen ("{name}").</feedback>
  </rule>

Diese Regel testet, ob es der Graph Elemente mit demselben Namen besitzt.

  <rule type="absence" points="4">
  	<query>from x: V{Element, ^Connector}, y1, y2 : V{Element}
  	       with
  	          x --> y1 and
  	          x --> y2 and
  	          not (y1=y2)
  	       report x.name as "xName", x.id as "xID" end
  	</query>
  	<feedback prefix="Fehlerhafte Grundstruktur">Das Element "{xName}" (ID {xID}) hat mehr als einen Ausgang.</feedback>
  </rule>

Diese Regel testet, ob ein Event oder Funktion mehr als einen Ausgang hat.

  <rule type="absence" points="4">
  	<query>from x: V{Connector}, y: V{Connector}
  	       with
  	          not (x.name="") and
  	          not (y.name="") and
  	          x --> y
  	       report x.name as "xName", y.name as "yName", x.id as "xID", y.id as "yID" end
  	</query>
  	<feedback prefix="Fehlerhafte Grundstruktur">Es dürfen keine zwei Konnektoren direkt aufeinander folgen. Es folgt jedoch "{yName}" (ID {yID}) direkt auf "{xName}" (ID {xID}).</feedback>
  </rule>

Diese Regel testet, ob 2 Konnektoren aufeinander folgen.

  <rule type="absence" points="1">
  	<query>from x: V{Element, ^Connector}
  	       with
  	          contains(x.name, " and ") or
  	          contains(x.name, "+") or
  	          contains(x.name, " und ")
  	       report x.name as "name" end
  	</query>
  	<feedback prefix="Anmerkung zur Namensgebung">Der Name "{name}" sieht danach aus, als wenn hier zwei Events bzw. Funktionen in einem Element zusammengefasst wurden.</feedback>
  </rule>

Diese Regel testet, ob der Graph möglicherweise Zeichen bzw. Wörter besitzt die mehrere Funktionen/Events in einem Element verbinden.