• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package signature.converter.dex;
18 
19 import static signature.converter.dex.DexUtil.getClassName;
20 import static signature.converter.dex.DexUtil.getPackageName;
21 import signature.model.IClassDefinition;
22 import signature.model.IClassReference;
23 import signature.model.IConstructor;
24 import signature.model.IGenericDeclaration;
25 import signature.model.IMethod;
26 import signature.model.ITypeReference;
27 import signature.model.ITypeVariableDefinition;
28 import signature.model.ITypeVariableReference;
29 import signature.model.impl.SigArrayType;
30 import signature.model.impl.SigParameterizedType;
31 import signature.model.impl.SigPrimitiveType;
32 import signature.model.impl.SigTypeVariableDefinition;
33 import signature.model.impl.SigWildcardType;
34 import signature.model.impl.Uninitialized;
35 import signature.model.util.ITypeFactory;
36 
37 import java.lang.reflect.GenericSignatureFormatError;
38 import java.util.ArrayList;
39 import java.util.List;
40 
41 /**
42  * Implements a parser for the generics signature attribute. Uses a top-down,
43  * recursive descent parsing approach for the following grammar:
44  *
45  * <pre>
46  * ClassSignature ::=
47  *     OptFormalTypeParams SuperclassSignature {SuperinterfaceSignature}.
48  * SuperclassSignature ::= ClassTypeSignature.
49  * SuperinterfaceSignature ::= ClassTypeSignature.
50  *
51  * OptFormalTypeParams ::=
52  *     ["<" FormalTypeParameter {FormalTypeParameter} ">"].
53  *
54  * FormalTypeParameter ::= Ident ClassBound {InterfaceBound}.
55  * ClassBound ::= ":" [FieldTypeSignature].
56  * InterfaceBound ::= ":" FieldTypeSignature.
57  *
58  * FieldTypeSignature ::=
59  *     ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature.
60  * ArrayTypeSignature ::= "[" TypSignature.
61  *
62  * ClassTypeSignature ::=
63  *     "L" {Ident "/"} Ident OptTypeArguments {"." Ident OptTypeArguments} ";".
64  *
65  * OptTypeArguments ::= "<" TypeArgument {TypeArgument} ">".
66  *
67  * TypeArgument ::= ([WildcardIndicator] FieldTypeSignature) | "*".
68  * WildcardIndicator ::= "+" | "-".
69  *
70  * TypeVariableSignature ::= "T" Ident ";".
71  *
72  * TypSignature ::= FieldTypeSignature | BaseType.
73  * BaseType ::= "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z".
74  *
75  * MethodTypeSignature ::=
76  *     OptFormalTypeParams "(" {TypeSignature} ")" ReturnType {ThrowsSignature}.
77  * ThrowsSignature ::= ("^" ClassTypeSignature) | ("^" TypeVariableSignature).
78  *
79  * ReturnType ::= TypSignature | VoidDescriptor.
80  * VoidDescriptor ::= "V".
81  * </pre>
82  */
83 public class GenericSignatureParser {
84 
85     public List<ITypeReference> exceptionTypes;
86     public List<ITypeReference> parameterTypes;
87     public List<ITypeVariableDefinition> formalTypeParameters;
88     public ITypeReference returnType;
89     public ITypeReference fieldType;
90     public List<ITypeReference> interfaceTypes;
91     public ITypeReference superclassType;
92 
93     private IGenericDeclaration genericDecl;
94 
95     /*
96      * Parser:
97      */
98     private char symbol; // 0: eof; else valid term symbol or first char of
99     // identifier.
100     private String identifier;
101 
102 
103     /*
104      * Scanner: eof is private to the scan methods and it's set only when a scan
105      * is issued at the end of the buffer.
106      */
107     private boolean eof;
108 
109     private char[] buffer;
110     private int pos;
111 
112     private final ITypeFactory factory;
113     private final IClassInitializer classFinder;
114     private boolean parseForField;
115 
116 
GenericSignatureParser(ITypeFactory factory, IClassInitializer classFinder)117     public GenericSignatureParser(ITypeFactory factory,
118             IClassInitializer classFinder) {
119         this.factory = factory;
120         this.classFinder = classFinder;
121     }
122 
setInput(IGenericDeclaration genericDecl, String input)123     private void setInput(IGenericDeclaration genericDecl, String input) {
124         if (input != null) {
125             this.genericDecl = genericDecl;
126             this.buffer = input.toCharArray();
127             this.eof = false;
128             scanSymbol();
129         } else {
130             this.eof = true;
131         }
132     }
133 
parseNonGenericType(String typeSignature)134     public ITypeReference parseNonGenericType(String typeSignature) {
135         setInput(null, typeSignature);
136         ITypeReference type = parsePrimitiveType();
137         if (type == null) {
138             type = parseFieldTypeSignature();
139         }
140         return type;
141     }
142 
parseNonGenericReturnType(String typeSignature)143     public ITypeReference parseNonGenericReturnType(String typeSignature) {
144         setInput(null, typeSignature);
145         ITypeReference returnType = parsePrimitiveType();
146         if (returnType == null) {
147             returnType = parseReturnType();
148         }
149         return returnType;
150     }
151 
parsePrimitiveType()152     private ITypeReference parsePrimitiveType() {
153         switch (symbol) {
154         case 'B':
155             scanSymbol();
156             return SigPrimitiveType.BYTE_TYPE;
157         case 'C':
158             scanSymbol();
159             return SigPrimitiveType.CHAR_TYPE;
160         case 'D':
161             scanSymbol();
162             return SigPrimitiveType.DOUBLE_TYPE;
163         case 'F':
164             scanSymbol();
165             return SigPrimitiveType.FLOAT_TYPE;
166         case 'I':
167             scanSymbol();
168             return SigPrimitiveType.INT_TYPE;
169         case 'J':
170             scanSymbol();
171             return SigPrimitiveType.LONG_TYPE;
172         case 'S':
173             scanSymbol();
174             return SigPrimitiveType.SHORT_TYPE;
175         case 'Z':
176             scanSymbol();
177             return SigPrimitiveType.BOOLEAN_TYPE;
178         default:
179             return null;
180         }
181     }
182 
183     /**
184      * Parses the generic signature of a class and creates the data structure
185      * representing the signature.
186      *
187      * @param classToProcess
188      *            the GenericDeclaration calling this method
189      * @param signature
190      *            the generic signature of the class
191      */
parseForClass(IClassDefinition classToProcess, String signature)192     public void parseForClass(IClassDefinition classToProcess,
193             String signature) {
194         setInput(classToProcess, signature);
195         if (!eof) {
196             parseClassSignature();
197         } else {
198             throw new IllegalStateException("Generic signature is invalid!");
199         }
200     }
201 
202     /**
203      * Parses the generic signature of a method and creates the data structure
204      * representing the signature.
205      *
206      * @param genericDecl
207      *            the GenericDeclaration calling this method
208      * @param signature
209      *            the generic signature of the class
210      */
parseForMethod(IMethod genericDecl, String signature)211     public void parseForMethod(IMethod genericDecl, String signature) {
212         setInput(genericDecl, signature);
213         if (!eof) {
214             parseMethodTypeSignature();
215         } else {
216             throw new IllegalStateException("Generic signature is invalid!");
217         }
218     }
219 
220     /**
221      * Parses the generic signature of a constructor and creates the data
222      * structure representing the signature.
223      *
224      * @param genericDecl
225      *            the GenericDeclaration calling this method
226      * @param signature
227      *            the generic signature of the class
228      */
parseForConstructor(IConstructor genericDecl, String signature)229     public void parseForConstructor(IConstructor genericDecl,
230             String signature) {
231         setInput(genericDecl, signature);
232         if (!eof) {
233             parseMethodTypeSignature();
234         } else {
235             throw new IllegalStateException("Generic signature is invalid!");
236         }
237     }
238 
239     /**
240      * Parses the generic signature of a field and creates the data structure
241      * representing the signature.
242      *
243      * @param genericDecl
244      *            the GenericDeclaration calling this method
245      * @param signature
246      *            the generic signature of the class
247      */
parseForField(IClassDefinition genericDecl, String signature)248     public void parseForField(IClassDefinition genericDecl, String signature) {
249         parseForField = true;
250         setInput(genericDecl, signature);
251         try {
252             if (!eof) {
253                 this.fieldType = parseFieldTypeSignature();
254             } else {
255                 throw new IllegalStateException(
256                         "Generic signature is invalid!");
257             }
258         } finally {
259             parseForField = false;
260         }
261     }
262 
parseClassSignature()263     private void parseClassSignature() {
264         // ClassSignature ::=
265         // OptFormalTypeParameters SuperclassSignature
266         // {SuperinterfaceSignature}.
267 
268         parseOptFormalTypeParameters();
269 
270         // SuperclassSignature ::= ClassTypeSignature.
271         this.superclassType = parseClassTypeSignature();
272 
273         interfaceTypes = new ArrayList<ITypeReference>(16);
274         while (symbol > 0) {
275             // SuperinterfaceSignature ::= ClassTypeSignature.
276             interfaceTypes.add(parseClassTypeSignature());
277         }
278     }
279 
parseOptFormalTypeParameters()280     private void parseOptFormalTypeParameters() {
281         // OptFormalTypeParameters ::=
282         // ["<" FormalTypeParameter {FormalTypeParameter} ">"].
283 
284         List<ITypeVariableDefinition> typeParameters =
285                 new ArrayList<ITypeVariableDefinition>();
286 
287         if (symbol == '<') {
288             scanSymbol();
289             typeParameters.add(parseFormalTypeParameter());
290             while ((symbol != '>') && (symbol > 0)) {
291                 typeParameters.add(parseFormalTypeParameter());
292             }
293             expect('>');
294         }
295 
296         formalTypeParameters = typeParameters;
297     }
298 
parseFormalTypeParameter()299     private SigTypeVariableDefinition parseFormalTypeParameter() {
300         // FormalTypeParameter ::= Ident ClassBound {InterfaceBound}.
301 
302         scanIdentifier();
303         String name = identifier.intern();
304         SigTypeVariableDefinition typeVariable = factory.getTypeVariable(name,
305                 genericDecl);
306 
307         List<ITypeReference> bounds = new ArrayList<ITypeReference>();
308 
309         // ClassBound ::= ":" [FieldTypeSignature].
310         expect(':');
311         if (symbol == 'L' || symbol == '[' || symbol == 'T') {
312             bounds.add(parseFieldTypeSignature());
313         }
314 
315         while (symbol == ':') {
316             // InterfaceBound ::= ":" FieldTypeSignature.
317             scanSymbol();
318             bounds.add(parseFieldTypeSignature());
319         }
320         typeVariable.setUpperBounds(bounds);
321         return typeVariable;
322     }
323 
324     /**
325      * Returns the generic declaration for the type variable with the specified
326      * name.
327      *
328      * @param variableName
329      *            the name of the type variable
330      * @param declaration
331      *            the declaration to start searching
332      * @return the declaration which defines the specified type variable
333      */
getDeclarationOfTypeVariable( String variableName, IClassDefinition declaration)334     private IGenericDeclaration getDeclarationOfTypeVariable(
335             String variableName, IClassDefinition declaration) {
336         assert variableName != null;
337         assert declaration != null;
338 
339         if (!Uninitialized.isInitialized(declaration.getTypeParameters())) {
340             declaration = classFinder.initializeClass(declaration
341                     .getPackageName(), declaration.getName());
342         }
343 
344         for (ITypeVariableDefinition typeVariable : declaration
345                 .getTypeParameters()) {
346             if (variableName.equals(typeVariable.getName())) {
347                 return declaration;
348             }
349         }
350         return getDeclarationOfTypeVariable(variableName, declaration
351                 .getDeclaringClass());
352     }
353 
parseFieldTypeSignature()354     private ITypeReference parseFieldTypeSignature() {
355         // FieldTypeSignature ::= ClassTypeSignature | ArrayTypeSignature
356         // | TypeVariableSignature.
357 
358         switch (symbol) {
359         case 'L':
360             return parseClassTypeSignature();
361         case '[':
362             // ArrayTypeSignature ::= "[" TypSignature.
363             scanSymbol();
364             SigArrayType arrayType = factory.getArrayType(parseTypeSignature());
365             return arrayType;
366         case 'T':
367             return parseTypeVariableSignature();
368         default:
369             throw new GenericSignatureFormatError();
370         }
371     }
372 
parseClassTypeSignature()373     private ITypeReference parseClassTypeSignature() {
374         // ClassTypeSignature ::= "L" {Ident "/"} Ident
375         // OptTypeArguments {"." Ident OptTypeArguments} ";".
376 
377         expect('L');
378 
379         StringBuilder qualIdent = new StringBuilder("L");
380         scanIdentifier();
381         while (symbol == '/') {
382             scanSymbol();
383             qualIdent.append(identifier).append("/");
384             scanIdentifier();
385         }
386 
387         qualIdent.append(this.identifier);
388 
389 
390         List<ITypeReference> typeArgs = parseOptTypeArguments();
391 
392         ITypeReference parentType = null;
393 
394         String packageName = getPackageName(qualIdent.toString() + ";");
395         String className = getClassName(qualIdent.toString() + ";");
396 
397         if (typeArgs.isEmpty()) {
398             parentType = factory.getClassReference(packageName, className);
399         } else {
400             IClassReference rawType = factory.getClassReference(packageName,
401                     className);
402             SigParameterizedType parameterizedType = factory
403                     .getParameterizedType(null, rawType, typeArgs);
404             parentType = parameterizedType;
405         }
406 
407         ITypeReference typeToReturn = parentType;
408 
409 
410         // if owner type is a parameterized type, the types are separated by '.'
411         while (symbol == '.') {
412             // Deal with Member Classes:
413             scanSymbol();
414             scanIdentifier();
415             qualIdent.append("$").append(identifier);
416             typeArgs = parseOptTypeArguments();
417             ITypeReference memberType = null;
418 
419             packageName = getPackageName(qualIdent.toString() + ";");
420             className = getClassName(qualIdent.toString() + ";");
421 
422             if (typeArgs.isEmpty()) {
423                 memberType = factory.getClassReference(packageName, className);
424             } else {
425                 IClassReference rawType = factory.getClassReference(
426                         packageName, className);
427                 SigParameterizedType parameterizedType = factory
428                         .getParameterizedType(parentType, rawType, typeArgs);
429                 memberType = parameterizedType;
430             }
431             typeToReturn = memberType;
432         }
433 
434         expect(';');
435 
436         return typeToReturn;
437     }
438 
parseOptTypeArguments()439     private List<ITypeReference> parseOptTypeArguments() {
440         // OptTypeArguments ::= "<" TypeArgument {TypeArgument} ">".
441 
442         List<ITypeReference> typeArgs = new ArrayList<ITypeReference>(8);
443         if (symbol == '<') {
444             scanSymbol();
445 
446             typeArgs.add(parseTypeArgument());
447             while ((symbol != '>') && (symbol > 0)) {
448                 typeArgs.add(parseTypeArgument());
449             }
450             expect('>');
451         }
452         return typeArgs;
453     }
454 
parseTypeArgument()455     private ITypeReference parseTypeArgument() {
456         // TypeArgument ::= (["+" | "-"] FieldTypeSignature) | "*".
457         List<ITypeReference> extendsBound = new ArrayList<ITypeReference>(1);
458         ITypeReference superBound = null;
459         if (symbol == '*') {
460             scanSymbol();
461             extendsBound.add(factory.getClassReference("java.lang", "Object"));
462             SigWildcardType wildcardType = factory.getWildcardType(superBound,
463                     extendsBound);
464             return wildcardType;
465         } else if (symbol == '+') {
466             scanSymbol();
467             extendsBound.add(parseFieldTypeSignature());
468             SigWildcardType wildcardType = factory.getWildcardType(superBound,
469                     extendsBound);
470             return wildcardType;
471         } else if (symbol == '-') {
472             scanSymbol();
473             superBound = parseFieldTypeSignature();
474             extendsBound.add(factory.getClassReference("java.lang", "Object"));
475             SigWildcardType wildcardType = factory.getWildcardType(superBound,
476                     extendsBound);
477             return wildcardType;
478         } else {
479             return parseFieldTypeSignature();
480         }
481     }
482 
parseTypeVariableSignature()483     private ITypeVariableReference parseTypeVariableSignature() {
484         // TypeVariableSignature ::= "T" Ident ";".
485         expect('T');
486         scanIdentifier();
487         expect(';');
488 
489         IGenericDeclaration declaration = genericDecl;
490 
491         if (!factory.containsTypeVariableDefinition(identifier, declaration)) {
492             // since a field is not a generic declaration, i need to treat it
493             // differently.
494             // the generic declaration
495             if (parseForField) {
496                 declaration = getDeclarationOfTypeVariable(identifier,
497                         (IClassDefinition) genericDecl);
498             } else {
499                 declaration = getDeclarationOfTypeVariable(identifier,
500                         genericDecl.getDeclaringClass());
501             }
502             // just create type variable
503             factory.getTypeVariable(identifier, declaration);
504         }
505 
506         return factory.getTypeVariableReference(identifier, declaration);
507     }
508 
parseTypeSignature()509     private ITypeReference parseTypeSignature() {
510         switch (symbol) {
511         case 'B':
512             scanSymbol();
513             return SigPrimitiveType.BYTE_TYPE;
514         case 'C':
515             scanSymbol();
516             return SigPrimitiveType.CHAR_TYPE;
517         case 'D':
518             scanSymbol();
519             return SigPrimitiveType.DOUBLE_TYPE;
520         case 'F':
521             scanSymbol();
522             return SigPrimitiveType.FLOAT_TYPE;
523         case 'I':
524             scanSymbol();
525             return SigPrimitiveType.INT_TYPE;
526         case 'J':
527             scanSymbol();
528             return SigPrimitiveType.LONG_TYPE;
529         case 'S':
530             scanSymbol();
531             return SigPrimitiveType.SHORT_TYPE;
532         case 'Z':
533             scanSymbol();
534             return SigPrimitiveType.BOOLEAN_TYPE;
535         default:
536             // Not an elementary type, but a FieldTypeSignature.
537             return parseFieldTypeSignature();
538         }
539     }
540 
parseMethodTypeSignature()541     private void parseMethodTypeSignature() {
542         // MethodTypeSignature ::= [FormalTypeParameters]
543         // "(" {TypeSignature} ")" ReturnType {ThrowsSignature}.
544 
545         parseOptFormalTypeParameters();
546 
547         parameterTypes = new ArrayList<ITypeReference>(16);
548         expect('(');
549         while (symbol != ')' && (symbol > 0)) {
550             parameterTypes.add(parseTypeSignature());
551         }
552         expect(')');
553 
554         returnType = parseReturnType();
555 
556         exceptionTypes = new ArrayList<ITypeReference>(8);
557         while (symbol == '^') {
558             scanSymbol();
559 
560             // ThrowsSignature ::= ("^" ClassTypeSignature) |
561             // ("^" TypeVariableSignature).
562             if (symbol == 'T') {
563                 exceptionTypes.add(parseTypeVariableSignature());
564             } else {
565                 exceptionTypes.add(parseClassTypeSignature());
566             }
567         }
568     }
569 
parseReturnType()570     private ITypeReference parseReturnType() {
571         // ReturnType ::= TypeSignature | "V".
572         if (symbol != 'V') {
573             return parseTypeSignature();
574         } else {
575             scanSymbol();
576             return SigPrimitiveType.VOID_TYPE;
577         }
578     }
579 
580 
581     //
582     // Scanner:
583     //
584 
scanSymbol()585     private void scanSymbol() {
586         if (!eof) {
587             if (pos < buffer.length) {
588                 symbol = buffer[pos];
589                 pos++;
590             } else {
591                 symbol = 0;
592                 eof = true;
593             }
594         } else {
595             throw new GenericSignatureFormatError();
596         }
597     }
598 
expect(char c)599     private void expect(char c) {
600         if (symbol == c) {
601             scanSymbol();
602         } else {
603             throw new GenericSignatureFormatError();
604         }
605     }
606 
isStopSymbol(char ch)607     private boolean isStopSymbol(char ch) {
608         switch (ch) {
609         case ':':
610         case '/':
611         case ';':
612         case '<':
613         case '.':
614             return true;
615         }
616         return false;
617     }
618 
619     // PRE: symbol is the first char of the identifier.
620     // POST: symbol = the next symbol AFTER the identifier.
scanIdentifier()621     private void scanIdentifier() {
622         if (!eof) {
623             StringBuilder identBuf = new StringBuilder(32);
624             if (!isStopSymbol(symbol)) {
625                 identBuf.append(symbol);
626                 do {
627                     char ch = buffer[pos];
628                     if ((ch >= 'a') && (ch <= 'z') || (ch >= 'A')
629                             && (ch <= 'Z') || !isStopSymbol(ch)) {
630                         identBuf.append(buffer[pos]);
631                         pos++;
632                     } else {
633                         identifier = identBuf.toString();
634                         scanSymbol();
635                         return;
636                     }
637                 } while (pos != buffer.length);
638                 identifier = identBuf.toString();
639                 symbol = 0;
640                 eof = true;
641             } else {
642                 // Ident starts with incorrect char.
643                 symbol = 0;
644                 eof = true;
645                 throw new GenericSignatureFormatError();
646             }
647         } else {
648             throw new GenericSignatureFormatError();
649         }
650     }
651 }
652