1 16 package com.google.gwt.dev.jjs.impl; 17 18 import com.google.gwt.dev.jjs.InternalCompilerException; 19 import com.google.gwt.dev.jjs.SourceInfo; 20 import com.google.gwt.dev.jjs.ast.JClassType; 21 import com.google.gwt.dev.jjs.ast.JField; 22 import com.google.gwt.dev.jjs.ast.JInterfaceType; 23 import com.google.gwt.dev.jjs.ast.JLocal; 24 import com.google.gwt.dev.jjs.ast.JMethod; 25 import com.google.gwt.dev.jjs.ast.JParameter; 26 import com.google.gwt.dev.jjs.ast.JProgram; 27 import com.google.gwt.dev.jjs.ast.JReferenceType; 28 import com.google.gwt.dev.jjs.ast.JType; 29 import com.google.gwt.dev.jjs.ast.js.JsniMethod; 30 import com.google.gwt.dev.js.JsParser; 31 import com.google.gwt.dev.js.JsParserException; 32 import com.google.gwt.dev.js.JsParserException.SourceDetail; 33 import com.google.gwt.dev.js.ast.JsExprStmt; 34 import com.google.gwt.dev.js.ast.JsFunction; 35 import com.google.gwt.dev.js.ast.JsProgram; 36 import com.google.gwt.dev.js.ast.JsStatements; 37 38 import org.eclipse.jdt.internal.compiler.ASTVisitor; 39 import org.eclipse.jdt.internal.compiler.CompilationResult; 40 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; 41 import org.eclipse.jdt.internal.compiler.ast.Argument; 42 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; 43 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; 44 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; 45 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; 46 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; 47 import org.eclipse.jdt.internal.compiler.ast.Statement; 48 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; 49 import org.eclipse.jdt.internal.compiler.env.IGenericType; 50 import org.eclipse.jdt.internal.compiler.lookup.BlockScope; 51 import org.eclipse.jdt.internal.compiler.lookup.ClassScope; 52 import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; 53 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; 54 import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; 55 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; 56 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; 57 import org.eclipse.jdt.internal.compiler.lookup.MethodScope; 58 import org.eclipse.jdt.internal.compiler.lookup.NestedTypeBinding; 59 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; 60 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; 61 import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding; 62 import org.eclipse.jdt.internal.compiler.problem.ProblemHandler; 63 64 import java.io.IOException ; 65 import java.io.StringReader ; 66 import java.util.ArrayList ; 67 import java.util.HashSet ; 68 import java.util.Set ; 69 70 78 public class BuildTypeMap { 79 80 95 private static class BuildDeclMapVisitor extends ASTVisitor { 96 97 private static SourceInfo makeSourceInfo( 98 AbstractMethodDeclaration methodDecl) { 99 CompilationResult compResult = methodDecl.compilationResult; 100 int[] indexes = compResult.lineSeparatorPositions; 101 String fileName = String.valueOf(compResult.fileName); 102 int startLine = ProblemHandler.searchLineNumber(indexes, 103 methodDecl.sourceStart); 104 return new SourceInfo(methodDecl.sourceStart, methodDecl.bodyEnd, 105 startLine, fileName); 106 } 107 108 private static InternalCompilerException translateException( 109 AbstractMethodDeclaration amd, Throwable e) { 110 InternalCompilerException ice; 111 if (e instanceof InternalCompilerException) { 112 ice = (InternalCompilerException) e; 113 } else { 114 ice = new InternalCompilerException("Error building type map", e); 115 } 116 ice.addNode(amd.getClass().getName(), amd.toString(), makeSourceInfo(amd)); 117 return ice; 118 } 119 120 private String currentFileName; 121 private int[] currentSeparatorPositions; 122 private final JsParser jsParser = new JsParser(); 123 private final JsProgram jsProgram; 124 private JProgram program; 125 private ArrayList typeDecls = new ArrayList (); 126 127 private final TypeMap typeMap; 128 129 public BuildDeclMapVisitor(TypeMap typeMap, JsProgram jsProgram) { 130 this.typeMap = typeMap; 131 program = this.typeMap.getProgram(); 132 this.jsProgram = jsProgram; 133 } 134 135 public TypeDeclaration[] getTypeDeclarataions() { 136 return (TypeDeclaration[]) typeDecls.toArray(new TypeDeclaration[typeDecls.size()]); 137 } 138 139 public boolean visit(Argument argument, BlockScope scope) { 140 try { 141 if (scope == scope.methodScope()) { 142 return true; 143 } 144 145 SourceInfo info = makeSourceInfo(argument); 146 LocalVariableBinding b = argument.binding; 147 JType localType = (JType) typeMap.get(b.type); 148 JMethod enclosingMethod = findEnclosingMethod(scope); 149 JLocal newLocal = program.createLocal(info, argument.name, localType, 150 b.isFinal(), enclosingMethod); 151 typeMap.put(b, newLocal); 152 return true; 153 } catch (Throwable e) { 154 throw translateException(argument, e); 155 } 156 } 157 158 165 public boolean visit(ConstructorDeclaration ctorDecl, ClassScope scope) { 166 try { 167 MethodBinding b = ctorDecl.binding; 168 JClassType enclosingType = (JClassType) typeMap.get(scope.enclosingSourceType()); 169 String name = enclosingType.getShortName(); 170 SourceInfo info = makeSourceInfo(ctorDecl); 171 JMethod newMethod = program.createMethod(info, name.toCharArray(), 172 enclosingType, enclosingType, false, false, true, b.isPrivate(), 173 false); 174 mapThrownExceptions(newMethod, ctorDecl); 175 176 mapParameters(newMethod, ctorDecl); 178 180 int syntheticParamCount = 0; 181 ReferenceBinding declaringClass = b.declaringClass; 182 if (declaringClass.isNestedType() && !declaringClass.isStatic()) { 183 NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass; 185 Set alreadyNamedVariables = new HashSet (); 186 if (nestedBinding.enclosingInstances != null) { 187 for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) { 188 SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i]; 189 String argName = String.valueOf(arg.name); 190 if (alreadyNamedVariables.contains(argName)) { 191 argName += "_" + i; 192 } 193 createParameter(arg, argName, newMethod); 194 ++syntheticParamCount; 195 alreadyNamedVariables.add(argName); 196 } 197 } 198 199 if (nestedBinding.outerLocalVariables != null) { 200 for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) { 201 SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i]; 202 String argName = String.valueOf(arg.name); 203 if (alreadyNamedVariables.contains(argName)) { 204 argName += "_" + i; 205 } 206 createParameter(arg, argName, newMethod); 207 ++syntheticParamCount; 208 alreadyNamedVariables.add(argName); 209 } 210 } 211 } 212 213 typeMap.put(b, newMethod); 214 return true; 215 } catch (Throwable e) { 216 throw translateException(ctorDecl, e); 217 } 218 } 219 220 public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) { 221 try { 222 FieldBinding b = fieldDeclaration.binding; 223 SourceInfo info = makeSourceInfo(fieldDeclaration); 224 JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType()); 225 createField(info, b, enclosingType, 226 fieldDeclaration.initialization != null); 227 return true; 228 } catch (Throwable e) { 229 throw translateException(fieldDeclaration, e); 230 } 231 } 232 233 public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) { 234 try { 235 LocalVariableBinding b = localDeclaration.binding; 236 JType localType = (JType) typeMap.get(localDeclaration.type.resolvedType); 237 JMethod enclosingMethod = findEnclosingMethod(scope); 238 SourceInfo info = makeSourceInfo(localDeclaration); 239 JLocal newLocal = program.createLocal(info, localDeclaration.name, 240 localType, b.isFinal(), enclosingMethod); 241 typeMap.put(b, newLocal); 242 return true; 243 } catch (Throwable e) { 244 throw translateException(localDeclaration, e); 245 } 246 } 247 248 public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { 249 try { 250 MethodBinding b = methodDeclaration.binding; 251 SourceInfo info = makeSourceInfo(methodDeclaration); 252 JType returnType = (JType) typeMap.get(methodDeclaration.returnType.resolvedType); 253 JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType()); 254 JMethod newMethod = program.createMethod(info, 255 methodDeclaration.selector, enclosingType, returnType, 256 b.isAbstract(), b.isStatic(), b.isFinal(), b.isPrivate(), 257 b.isNative()); 258 259 mapThrownExceptions(newMethod, methodDeclaration); 260 mapParameters(newMethod, methodDeclaration); 261 typeMap.put(b, newMethod); 262 263 if (newMethod.isNative()) { 264 char[] source = methodDeclaration.compilationResult().getCompilationUnit().getContents(); 266 String jsniCode = String.valueOf(source, methodDeclaration.bodyStart, 267 methodDeclaration.bodyEnd - methodDeclaration.bodyStart + 1); 268 int startPos = jsniCode.indexOf("/*-{"); 269 int endPos = jsniCode.lastIndexOf("}-*/"); 270 if (startPos < 0 && endPos < 0) { 271 GenerateJavaAST.reportJsniError( 272 info, 273 methodDeclaration, 274 "Native methods require a JavaScript implementation enclosed with /*-{ and }-*/"); 275 return true; 276 } 277 if (startPos < 0) { 278 GenerateJavaAST.reportJsniError(info, methodDeclaration, 279 "Unable to find start of native block; begin your JavaScript block with: /*-{"); 280 return true; 281 } 282 if (endPos < 0) { 283 GenerateJavaAST.reportJsniError( 284 info, 285 methodDeclaration, 286 "Unable to find end of native block; terminate your JavaScript block with: }-*/"); 287 return true; 288 } 289 290 startPos += 3; endPos += 1; 293 jsniCode = jsniCode.substring(startPos, endPos); 294 295 String syntheticFnHeader = "function ("; 299 boolean first = true; 300 for (int i = 0; i < newMethod.params.size(); ++i) { 301 JParameter param = (JParameter) newMethod.params.get(i); 302 if (first) { 303 first = false; 304 } else { 305 syntheticFnHeader += ','; 306 } 307 syntheticFnHeader += param.getName(); 308 } 309 syntheticFnHeader += ')'; 310 StringReader sr = new StringReader (syntheticFnHeader + '\n' 311 + jsniCode); 312 try { 313 JsStatements result = jsParser.parse(jsProgram.getScope(), sr, -1); 316 JsExprStmt jsExprStmt = (JsExprStmt) result.get(0); 317 JsFunction jsFunction = (JsFunction) jsExprStmt.getExpression(); 318 ((JsniMethod) newMethod).setFunc(jsFunction); 319 } catch (IOException e) { 320 throw new InternalCompilerException( 321 "Internal error parsing JSNI in method '" + newMethod 322 + "' in type '" + enclosingType.getName() + "'", e); 323 } catch (JsParserException e) { 324 328 SourceDetail detail = e.getSourceDetail(); 329 int line = detail.getLine(); 330 char[] chars = jsniCode.toCharArray(); 331 int i = 0, n = chars.length; 332 while (line > 0) { 333 switch (chars[i]) { 335 case '\r': 336 if (i + 1 < n && chars[i + 1] == '\n') { 338 ++i; 339 } 340 case '\n': 342 --line; 343 default: 345 ++i; 346 } 347 } 349 350 i += startPos + detail.getLineOffset(); 353 info = new SourceInfo(i, i, 354 info.getStartLine() + detail.getLine(), info.getFileName()); 355 GenerateJavaAST.reportJsniError(info, methodDeclaration, 356 e.getMessage()); 357 } 358 } 359 360 return true; 361 } catch (Throwable e) { 362 throw translateException(methodDeclaration, e); 363 } 364 } 365 366 public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) { 367 return process(localTypeDeclaration); 368 } 369 370 public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) { 371 return process(memberTypeDeclaration); 372 } 373 374 public boolean visit(TypeDeclaration typeDeclaration, 375 CompilationUnitScope scope) { 376 return process(typeDeclaration); 377 } 378 379 private JField createField(SourceInfo info, FieldBinding binding, 380 JReferenceType enclosingType, boolean hasInitializer) { 381 JType type = (JType) typeMap.get(binding.type); 382 JField field = program.createField(info, binding.name, enclosingType, 383 type, binding.isStatic(), binding.isFinal(), hasInitializer); 384 typeMap.put(binding, field); 385 return field; 386 } 387 388 private JField createField(SyntheticArgumentBinding binding, 389 JReferenceType enclosingType) { 390 JType type = (JType) typeMap.get(binding.type); 391 JField field = program.createField(null, binding.name, enclosingType, 392 type, false, true, true); 393 if (binding.matchingField != null) { 394 typeMap.put(binding.matchingField, field); 395 } 396 typeMap.put(binding, field); 397 return field; 398 } 399 400 private JParameter createParameter(LocalVariableBinding binding, 401 JMethod enclosingMethod) { 402 JType type = (JType) typeMap.get(binding.type); 403 SourceInfo info = makeSourceInfo(binding.declaration); 404 JParameter param = program.createParameter(info, binding.name, type, 405 binding.isFinal(), enclosingMethod); 406 typeMap.put(binding, param); 407 return param; 408 } 409 410 private JParameter createParameter(SyntheticArgumentBinding arg, 411 String argName, JMethod enclosingMethod) { 412 JType type = (JType) typeMap.get(arg.type); 413 JParameter param = program.createParameter(null, argName.toCharArray(), 414 type, true, enclosingMethod); 415 return param; 416 } 417 418 private JMethod findEnclosingMethod(BlockScope scope) { 419 MethodScope methodScope = scope.methodScope(); 420 if (methodScope.isInsideInitializer()) { 421 JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.classScope().referenceContext.binding); 422 if (methodScope.isStatic) { 423 return (JMethod) enclosingType.methods.get(0); 425 } else { 426 assert (enclosingType instanceof JClassType); 428 return (JMethod) enclosingType.methods.get(1); 429 } 430 } 431 432 AbstractMethodDeclaration referenceMethod = methodScope.referenceMethod(); 433 return (JMethod) typeMap.get(referenceMethod.binding); 434 } 435 436 private SourceInfo makeSourceInfo(Statement stmt) { 437 int startLine = ProblemHandler.searchLineNumber( 438 currentSeparatorPositions, stmt.sourceStart); 439 return new SourceInfo(stmt.sourceStart, stmt.sourceEnd, startLine, 440 currentFileName); 441 } 442 443 private void mapParameters(JMethod method, AbstractMethodDeclaration x) { 444 MethodBinding b = x.binding; 445 int paramCount = (b.parameters != null ? b.parameters.length : 0); 446 if (paramCount > 0) { 447 for (int i = 0, n = x.arguments.length; i < n; ++i) { 448 createParameter(x.arguments[i].binding, method); 449 } 450 } 451 method.freezeParamTypes(); 452 } 453 454 private void mapThrownExceptions(JMethod method, AbstractMethodDeclaration x) { 455 MethodBinding b = x.binding; 456 if (b.thrownExceptions != null) { 457 for (int i = 0; i < b.thrownExceptions.length; ++i) { 458 ReferenceBinding refBinding = b.thrownExceptions[i]; 459 JClassType thrownException = (JClassType) typeMap.get(refBinding); 460 method.thrownExceptions.add(thrownException); 461 } 462 } 463 } 464 465 475 private boolean process(TypeDeclaration typeDeclaration) { 476 CompilationResult compResult = typeDeclaration.compilationResult; 477 currentSeparatorPositions = compResult.lineSeparatorPositions; 478 currentFileName = String.valueOf(compResult.fileName); 479 SourceTypeBinding binding = typeDeclaration.binding; 480 if (binding.constantPoolName() == null) { 481 485 return false; 486 } 487 JReferenceType type = (JReferenceType) typeMap.get(binding); 488 try { 489 if (binding.isNestedType() && !binding.isStatic()) { 490 assert (type instanceof JClassType); 492 NestedTypeBinding nestedBinding = (NestedTypeBinding) binding; 493 if (nestedBinding.enclosingInstances != null) { 494 for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) { 495 SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i]; 496 if (arg.matchingField != null) { 497 createField(arg, type); 498 } 499 } 500 } 501 502 if (nestedBinding.outerLocalVariables != null) { 503 for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) { 504 SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i]; 505 createField(arg, type); 506 } 507 } 508 } 509 510 ReferenceBinding superClassBinding = binding.superclass(); 511 if (superClassBinding != null) { 512 assert (binding.superclass().isClass()); 513 JClassType superClass = (JClassType) typeMap.get(superClassBinding); 514 type.extnds = superClass; 515 } 516 517 ReferenceBinding[] superInterfaces = binding.superInterfaces(); 518 for (int i = 0; i < superInterfaces.length; ++i) { 519 ReferenceBinding superInterfaceBinding = superInterfaces[i]; 520 assert (superInterfaceBinding.isInterface()); 521 JInterfaceType superInterface = (JInterfaceType) typeMap.get(superInterfaceBinding); 522 type.implments.add(superInterface); 523 } 524 typeDecls.add(typeDeclaration); 525 return true; 526 } catch (InternalCompilerException ice) { 527 ice.addNode(type); 528 throw ice; 529 } catch (Throwable e) { 530 throw new InternalCompilerException(type, "Error building type map", e); 531 } 532 } 533 534 private InternalCompilerException translateException(Statement stmt, 535 Throwable e) { 536 InternalCompilerException ice; 537 if (e instanceof InternalCompilerException) { 538 ice = (InternalCompilerException) e; 539 } else { 540 ice = new InternalCompilerException("Error building type map", e); 541 } 542 ice.addNode(stmt.getClass().getName(), stmt.toString(), 543 makeSourceInfo(stmt)); 544 return ice; 545 } 546 } 547 548 554 private static class BuildTypeMapVisitor extends ASTVisitor { 555 556 private static SourceInfo makeSourceInfo(TypeDeclaration typeDecl) { 557 CompilationResult compResult = typeDecl.compilationResult; 558 int[] indexes = compResult.lineSeparatorPositions; 559 String fileName = String.valueOf(compResult.fileName); 560 int startLine = ProblemHandler.searchLineNumber(indexes, 561 typeDecl.sourceStart); 562 return new SourceInfo(typeDecl.sourceStart, typeDecl.bodyEnd, startLine, 563 fileName); 564 } 565 566 private static InternalCompilerException translateException( 567 TypeDeclaration typeDecl, Throwable e) { 568 InternalCompilerException ice; 569 if (e instanceof InternalCompilerException) { 570 ice = (InternalCompilerException) e; 571 } else { 572 ice = new InternalCompilerException("Error building type map", e); 573 } 574 ice.addNode(typeDecl.getClass().getName(), typeDecl.toString(), 575 makeSourceInfo(typeDecl)); 576 return ice; 577 } 578 579 private final JProgram program; 580 private final TypeMap typeMap; 581 582 public BuildTypeMapVisitor(TypeMap typeMap) { 583 this.typeMap = typeMap; 584 program = this.typeMap.getProgram(); 585 } 586 587 public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) { 588 assert (localTypeDeclaration.kind() != IGenericType.INTERFACE_DECL); 589 return process(localTypeDeclaration); 590 } 591 592 public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) { 593 return process(memberTypeDeclaration); 594 } 595 596 public boolean visit(TypeDeclaration typeDeclaration, 597 CompilationUnitScope scope) { 598 return process(typeDeclaration); 599 } 600 601 private boolean process(TypeDeclaration typeDeclaration) { 602 try { 603 char[][] name = typeDeclaration.binding.compoundName; 604 SourceTypeBinding binding = typeDeclaration.binding; 605 if (binding instanceof LocalTypeBinding) { 606 char[] localName = binding.constantPoolName(); 607 if (localName == null) { 608 612 return false; 613 } 614 615 for (int i = 0, c = localName.length; i < c; ++i) { 616 if (localName[i] == '/') { 617 localName[i] = '.'; 618 } 619 } 620 name = new char[1][0]; 621 name[0] = localName; 622 } 623 624 SourceInfo info = makeSourceInfo(typeDeclaration); 625 JReferenceType newType; 626 if (binding.isClass()) { 627 newType = program.createClass(info, name, binding.isAbstract(), 628 binding.isFinal()); 629 } else if (binding.isInterface()) { 630 newType = program.createInterface(info, name); 631 } else { 632 assert (false); 633 return false; 634 } 635 636 642 JMethod clinit = program.createMethod(null, "$clinit".toCharArray(), 643 newType, program.getTypeVoid(), false, true, true, true, false); 644 clinit.freezeParamTypes(); 645 646 if (newType instanceof JClassType) { 647 JMethod init = program.createMethod(null, "$init".toCharArray(), 648 newType, program.getTypeVoid(), false, false, true, true, false); 649 init.freezeParamTypes(); 650 } 651 652 typeMap.put(binding, newType); 653 return true; 654 } catch (Throwable e) { 655 throw translateException(typeDeclaration, e); 656 } 657 } 658 } 659 660 public static TypeDeclaration[] exec(TypeMap typeMap, 661 CompilationUnitDeclaration[] unitDecls, JsProgram jsProgram) { 662 createPeersForTypes(unitDecls, typeMap); 663 return createPeersForNonTypeDecls(unitDecls, typeMap, jsProgram); 664 } 665 666 private static TypeDeclaration[] createPeersForNonTypeDecls( 667 CompilationUnitDeclaration[] unitDecls, TypeMap typeMap, 668 JsProgram jsProgram) { 669 BuildDeclMapVisitor v2 = new BuildDeclMapVisitor(typeMap, jsProgram); 672 for (int i = 0; i < unitDecls.length; ++i) { 673 unitDecls[i].traverse(v2, unitDecls[i].scope); 674 } 675 return v2.getTypeDeclarataions(); 676 } 677 678 private static void createPeersForTypes( 679 CompilationUnitDeclaration[] unitDecls, TypeMap typeMap) { 680 BuildTypeMapVisitor v1 = new BuildTypeMapVisitor(typeMap); 682 for (int i = 0; i < unitDecls.length; ++i) { 683 unitDecls[i].traverse(v1, unitDecls[i].scope); 684 } 685 } 686 687 } 688 | Popular Tags |