Überprüfen Sie, ob der Typ generisch ist

8

Ich versuche, einen Code-Analysator zu implementieren, der eine andere Java-Datei als Eingabe verwendet. Für jede Variablendeklaration möchte ich prüfen, ob der Typ, zu dem die Variable gehört, generisch ist oder nicht. Gibt es eine einfache Möglichkeit, das zu tun?

Zum Beispiel möchte ich dafür:

%Vor%

Ich kann möglicherweise eine Registrierung erstellen, die alle generischen Typen enthält, aber das Problem damit wäre, wenn ich einen benutzerdefinierten generischen Typ implementiere, dann müsste ich die Registrierung jedes Mal aktualisieren. Gibt es dafür eine einfache Lösung?

    
akhiljain 16.06.2015, 20:31
quelle

4 Antworten

6

Auch wenn HashSet generisch sein kann, ist der Typ HashSet selbst (ohne <T> ) ein roher Typ . Daher würde ich mit dem Ansatz gehen, den tatsächlichen Typ der deklarierten Variablen zu scannen, vielleicht eine Regex auf den Typ anzuwenden, um zu sehen, ob die spitzen Klammern existieren:

%Vor%

Wenn Sie einen gültigen Bezeichner strikt berücksichtigen möchten, können Sie dessen Definition im Java-Sprachspezifikation :

  

Bezeichner:

     
    

IdentifierChars, aber kein Schlüsselwort oder BooleanLiteral oder NullLiteral

  
     

IdentifierChars:

     
    

JavaLetter {JavaLetterOrDigit}

  
     

JavaLetter:

     
    

jedes Unicode-Zeichen, das ein "Java-Buchstabe" ist

  
     

JavaLetterOrDigit:

     
    

jedes Unicode-Zeichen, das ein "Java Buchstabe oder Ziffer" ist

  
     

Ein "Java-Buchstabe" ist ein Zeichen, für das die Methode Character.isJavaIdentifierStart(int) true zurückgibt.

     

Ein "Java letter or digit" ist ein Zeichen, für das die Methode Character.isJavaIdentifierPart(int) true zurückgibt.

    
manouti 16.06.2015 20:33
quelle
5

Ich denke, das ist ähnlich wie Sie suchen:

Es druckt true für java.util.HashSet .

Aber false für java.lang.Object .

%Vor%     
eugenioy 16.06.2015 20:45
quelle
4

Dies wird nach Objekt, Klasse oder Klassennamen getestet.

Update: Mehrere Überarbeitungen dieses Codes auf Basis hilfreicher Kommentare haben einige interessante Testfälle ergeben. Letztendlich hängt jedoch eine angemessene Lösung des Problems davon ab, wie genau die Frage definiert ist. Beziehen Sie sich auf frühere Überarbeitungen und Kommentare.

%Vor%

Die Ergebnisse der Ausführung des obigen Codes:

%Vor%     
vallismortis 16.06.2015 21:03
quelle
3

Die anderen Antworten scheinen sich auf die Verwendung eines regulären Ausdrucks oder einer regulären Reflexion zu konzentrieren, aber dies scheint ein Parser zu sein. Das ist es, was ich dir empfehle.

Als Beispiel hat Eclipse sein JDT-Plug-in (Java Development Tools), das Ihnen alle Analyse-Tools zur Verfügung stellt, die Sie für dieses Recht benötigen. Alles, was Sie tun müssen, ist die JDT bitten, Ihnen einen Abstract Syntax Tree (AST) mit aktivierten Bindungen zu geben. Wenn eine Variable deklariert wird, erhalten Sie eine ITypeBinding für den deklarierten Typ der Variablen und eine weitere für den instanziierten Typ (wenn die Variable in der Deklaration instanziiert wird).

Und ITypeBinding hat Methoden, die Ihnen sagen, ob es generische, parametrisierte, etc.

ist

Sie erhalten auch die Typparameter, falls Sie diese benötigen.

Es gibt noch andere Java-Parser-Optionen, aber das ist die, mit der ich vertraut bin.

==============================================

Spezifische Ergebnisse mit dem Eclipse JDT

Fall 1: HashSet<String> h1 = new HashSet();

Fall 2: HashSet<String> h2 = new HashSet<>();

Fall 3: HashSet<String> h3 = new HashSet<String>();

Ziel dieser Übung ist es, wie bisher verstanden, Fall 1 als nicht generisch (roh) und Fälle 2 und 3 als generisch (sie haben Typparameter, obwohl in Fall 2 der Typparameter impliziert ist) zu erkennen.

Betrachte nur die Knoten, die aus new HashSet...

erzeugt wurden

Alle drei Fälle erzeugen eine ClassInstanceCreation-Instanz.

Fall 1 und Fall 2 haben Argumente vom Typ 0, während Fall 3 ein Argument vom Typ hat.

Die ITypeBinding für Fall 1 ist als roh gekennzeichnet, während für die Fälle 2 und 3 sie als parametrisiert markiert sind. Dies ist ein Erfolg , da wir zwischen Fall 1 einerseits und den Fällen 2 und 3 andererseits unterscheiden können.

Die ITypeBinding für Fall 1 hat 0 Typargumente, während Fall 2 und 3 beide 1 Typargument in der ITypeBinding haben. Beachten Sie, dass Fall 2 im AST selbst 0-Typ-Argumente hat, aber die Bindung ein Argument vom Typ hat. Dies erlaubt es, zwischen einem expliziten Typargument und der Verwendung des Diamantoperators zu unterscheiden.

Alle für die Ausführung dieser Aufgabe erforderlichen Informationen sind im AST und in den Bindungen verfügbar.

Hier sind die schlechten Nachrichten: Die Bindungen sind nur verfügbar, wenn der Byte-Code verfügbar ist, d. h. dies ist keine einfache Textanalyse.

    
Erick G. Hagstrom 16.06.2015 21:37
quelle

Tags und Links