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 117 public GenericSignatureParser(ITypeFactory factory, 118 IClassInitializer classFinder) { 119 this.factory = factory; 120 this.classFinder = classFinder; 121 } 122 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 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 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 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 */ 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 */ 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 */ 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 */ 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 599 private void expect(char c) { 600 if (symbol == c) { 601 scanSymbol(); 602 } else { 603 throw new GenericSignatureFormatError(); 604 } 605 } 606 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. 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