| 1 11 package org.eclipse.jdt.internal.debug.eval.ast.engine; 12 13 14 import java.util.HashSet ; 15 import java.util.Iterator ; 16 import java.util.List ; 17 import java.util.Set ; 18 19 import org.eclipse.jdt.core.Flags; 20 import org.eclipse.jdt.core.Signature; 21 import org.eclipse.jdt.core.dom.ASTNode; 22 import org.eclipse.jdt.core.dom.ASTVisitor; 23 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 24 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; 25 import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; 26 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; 27 import org.eclipse.jdt.core.dom.ArrayAccess; 28 import org.eclipse.jdt.core.dom.ArrayCreation; 29 import org.eclipse.jdt.core.dom.ArrayInitializer; 30 import org.eclipse.jdt.core.dom.ArrayType; 31 import org.eclipse.jdt.core.dom.AssertStatement; 32 import org.eclipse.jdt.core.dom.Assignment; 33 import org.eclipse.jdt.core.dom.Block; 34 import org.eclipse.jdt.core.dom.BlockComment; 35 import org.eclipse.jdt.core.dom.BodyDeclaration; 36 import org.eclipse.jdt.core.dom.BooleanLiteral; 37 import org.eclipse.jdt.core.dom.BreakStatement; 38 import org.eclipse.jdt.core.dom.CastExpression; 39 import org.eclipse.jdt.core.dom.CatchClause; 40 import org.eclipse.jdt.core.dom.CharacterLiteral; 41 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 42 import org.eclipse.jdt.core.dom.CompilationUnit; 43 import org.eclipse.jdt.core.dom.ConditionalExpression; 44 import org.eclipse.jdt.core.dom.ConstructorInvocation; 45 import org.eclipse.jdt.core.dom.ContinueStatement; 46 import org.eclipse.jdt.core.dom.DoStatement; 47 import org.eclipse.jdt.core.dom.EmptyStatement; 48 import org.eclipse.jdt.core.dom.EnhancedForStatement; 49 import org.eclipse.jdt.core.dom.EnumConstantDeclaration; 50 import org.eclipse.jdt.core.dom.EnumDeclaration; 51 import org.eclipse.jdt.core.dom.ExpressionStatement; 52 import org.eclipse.jdt.core.dom.FieldAccess; 53 import org.eclipse.jdt.core.dom.FieldDeclaration; 54 import org.eclipse.jdt.core.dom.ForStatement; 55 import org.eclipse.jdt.core.dom.IfStatement; 56 import org.eclipse.jdt.core.dom.ImportDeclaration; 57 import org.eclipse.jdt.core.dom.InfixExpression; 58 import org.eclipse.jdt.core.dom.Initializer; 59 import org.eclipse.jdt.core.dom.InstanceofExpression; 60 import org.eclipse.jdt.core.dom.Javadoc; 61 import org.eclipse.jdt.core.dom.LabeledStatement; 62 import org.eclipse.jdt.core.dom.LineComment; 63 import org.eclipse.jdt.core.dom.MarkerAnnotation; 64 import org.eclipse.jdt.core.dom.MemberRef; 65 import org.eclipse.jdt.core.dom.MemberValuePair; 66 import org.eclipse.jdt.core.dom.MethodDeclaration; 67 import org.eclipse.jdt.core.dom.MethodInvocation; 68 import org.eclipse.jdt.core.dom.MethodRef; 69 import org.eclipse.jdt.core.dom.MethodRefParameter; 70 import org.eclipse.jdt.core.dom.Modifier; 71 import org.eclipse.jdt.core.dom.Name; 72 import org.eclipse.jdt.core.dom.NormalAnnotation; 73 import org.eclipse.jdt.core.dom.NullLiteral; 74 import org.eclipse.jdt.core.dom.NumberLiteral; 75 import org.eclipse.jdt.core.dom.PackageDeclaration; 76 import org.eclipse.jdt.core.dom.ParameterizedType; 77 import org.eclipse.jdt.core.dom.ParenthesizedExpression; 78 import org.eclipse.jdt.core.dom.PostfixExpression; 79 import org.eclipse.jdt.core.dom.PrefixExpression; 80 import org.eclipse.jdt.core.dom.PrimitiveType; 81 import org.eclipse.jdt.core.dom.QualifiedName; 82 import org.eclipse.jdt.core.dom.QualifiedType; 83 import org.eclipse.jdt.core.dom.ReturnStatement; 84 import org.eclipse.jdt.core.dom.SimpleName; 85 import org.eclipse.jdt.core.dom.SimpleType; 86 import org.eclipse.jdt.core.dom.SingleMemberAnnotation; 87 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 88 import org.eclipse.jdt.core.dom.StringLiteral; 89 import org.eclipse.jdt.core.dom.SuperConstructorInvocation; 90 import org.eclipse.jdt.core.dom.SuperFieldAccess; 91 import org.eclipse.jdt.core.dom.SuperMethodInvocation; 92 import org.eclipse.jdt.core.dom.SwitchCase; 93 import org.eclipse.jdt.core.dom.SwitchStatement; 94 import org.eclipse.jdt.core.dom.SynchronizedStatement; 95 import org.eclipse.jdt.core.dom.TagElement; 96 import org.eclipse.jdt.core.dom.TextElement; 97 import org.eclipse.jdt.core.dom.ThisExpression; 98 import org.eclipse.jdt.core.dom.ThrowStatement; 99 import org.eclipse.jdt.core.dom.TryStatement; 100 import org.eclipse.jdt.core.dom.Type; 101 import org.eclipse.jdt.core.dom.TypeDeclaration; 102 import org.eclipse.jdt.core.dom.TypeDeclarationStatement; 103 import org.eclipse.jdt.core.dom.TypeLiteral; 104 import org.eclipse.jdt.core.dom.TypeParameter; 105 import org.eclipse.jdt.core.dom.VariableDeclarationExpression; 106 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 107 import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 108 import org.eclipse.jdt.core.dom.WhileStatement; 109 import org.eclipse.jdt.core.dom.WildcardType; 110 111 112 public class SourceBasedSourceGenerator extends ASTVisitor { 113 114 private static final String RUN_METHOD_NAME= "___run"; private static final String EVAL_METHOD_NAME= "___eval"; private static final String EVAL_FIELD_NAME= "___field"; 118 private String [] fLocalVariableTypeNames; 119 private String [] fLocalVariableNames; 120 private String fCodeSnippet; 121 122 private boolean fRightTypeFound; 123 124 private boolean fCreateInAStaticMethod; 125 126 private boolean fEvaluateNextEndTypeDeclaration; 127 128 private String fError; 129 130 private CompilationUnit fUnit; 131 132 private String fTypeName; 133 134 private int fPosition; 135 136 private StringBuffer fSource; 137 138 private String fLastTypeName; 139 140 private String fCompilationUnitName; 141 142 private int fSnippetStartPosition; 143 private int fRunMethodStartOffset; 144 private int fRunMethodLength; 145 146 150 private int fSourceMajorLevel; 151 private int fSourceMinorLevel; 152 153 private Set fTypeParameters = new HashSet (); 154 155 160 public SourceBasedSourceGenerator(CompilationUnit unit, String typeName, int position, boolean createInAStaticMethod, String [] localTypesNames, String [] localVariables, String codeSnippet, String sourceLevel) { 161 fRightTypeFound= false; 162 fUnit= unit; 163 fTypeName= typeName; 164 fPosition= position; 165 fLocalVariableTypeNames= localTypesNames; 166 fLocalVariableNames= localVariables; 167 fCodeSnippet= codeSnippet; 168 fCreateInAStaticMethod= createInAStaticMethod; 169 int index = sourceLevel.indexOf('.'); 170 String num = sourceLevel.substring(0, index); 171 fSourceMajorLevel = Integer.valueOf(num).intValue(); 172 num = sourceLevel.substring(index + 1); 173 fSourceMinorLevel = Integer.valueOf(num).intValue(); 174 } 175 176 179 public String getSource() { 180 if (fSource == null) { 181 return null; 182 } 183 return fSource.toString(); 184 } 185 186 private CompilationUnit getCompilationUnit() { 187 return fUnit; 188 } 189 190 public String getCompilationUnitName() { 191 return fCompilationUnitName; 192 } 193 194 public int getSnippetStart() { 195 return fSnippetStartPosition; 196 } 197 public int getRunMethodStart() { 198 return fSnippetStartPosition - fRunMethodStartOffset; 199 } 200 public int getRunMethodLength() { 201 return fRunMethodLength; 202 } 203 204 private int getPosition() { 205 return fPosition; 206 } 207 208 private int getCorrespondingLineNumber(int charOffset) { 209 int lineNumber = getCompilationUnit().getLineNumber(charOffset); 210 return lineNumber < 1 ? 1 : lineNumber; 211 } 212 213 private boolean rightTypeFound() { 214 return fRightTypeFound; 215 } 216 217 private void setRightTypeFound(boolean value) { 218 fRightTypeFound= value; 219 } 220 221 public boolean hasError() { 222 return fError != null; 223 } 224 225 public void setError(String errorDesc) { 226 fError= errorDesc; 227 } 228 229 public String getError() { 230 return fError; 231 } 232 233 private StringBuffer buildRunMethod(List bodyDeclarations) { 234 StringBuffer buffer = new StringBuffer (); 235 236 if (fCreateInAStaticMethod) { 237 buffer.append("static "); if (isSourceLevelGreaterOrEqual(1, 5)) { 240 if (!fTypeParameters.isEmpty()) { 241 Iterator iterator = fTypeParameters.iterator(); 242 buffer.append(Signature.C_GENERIC_START); 243 while (iterator.hasNext()) { 244 String name = (String ) iterator.next(); 245 buffer.append(name); 246 if (iterator.hasNext()) { 247 buffer.append(", "); } 249 } 250 buffer.append(Signature.C_GENERIC_END); 251 } 252 } 253 } 254 255 buffer.append("void "); buffer.append(getUniqueMethodName(RUN_METHOD_NAME, bodyDeclarations)); 257 buffer.append('('); 258 for(int i= 0, length= fLocalVariableNames.length; i < length; i++) { 259 buffer.append(getDotName(fLocalVariableTypeNames[i])); 260 buffer.append(' '); 261 buffer.append(fLocalVariableNames[i]); 262 if (i + 1 < length) 263 buffer.append(", "); } 265 buffer.append(") throws Throwable {"); buffer.append('\n'); 267 fSnippetStartPosition= buffer.length() - 2; 268 fRunMethodStartOffset= fSnippetStartPosition; 269 String codeSnippet= new String (fCodeSnippet).trim(); 270 271 buffer.append(codeSnippet); 272 273 buffer.append('\n'); 274 buffer.append('}').append('\n'); 275 fRunMethodLength= buffer.length(); 276 return buffer; 277 } 278 279 private String getDotName(String typeName) { 280 return typeName.replace('$', '.'); 281 } 282 283 private boolean isRightType(ASTNode node) { 284 int position= getPosition(); 285 int startLineNumber= getCorrespondingLineNumber(node.getStartPosition()); 286 int endLineNumber= getCorrespondingLineNumber(node.getStartPosition() + node.getLength() - 1); 287 if (startLineNumber <= position && position <= endLineNumber) { 288 String typeName= fTypeName; 290 while (node != null) { 291 if (node instanceof TypeDeclaration || node instanceof EnumDeclaration) { 292 AbstractTypeDeclaration abstractTypeDeclaration= (AbstractTypeDeclaration) node; 293 String name= abstractTypeDeclaration.getName().getIdentifier(); 294 if (abstractTypeDeclaration.isLocalTypeDeclaration()) { 295 if (! typeName.endsWith('$' + name)) { 296 return false; 297 } 298 typeName= typeName.substring(0, typeName.length() - name.length() - 1); 299 int index= typeName.lastIndexOf('$'); 300 if (index < 0) { 301 return false; 302 } 303 for (int i= typeName.length() - 1; i > index; i--) { 304 if (!Character.isDigit(typeName.charAt(i))) { 305 return false; 306 } 307 } 308 typeName= typeName.substring(0, index); 309 ASTNode parent= node.getParent(); 310 while (!(parent instanceof CompilationUnit)) { 311 node= parent; 312 parent= node.getParent(); 313 } 314 } else { 315 if (abstractTypeDeclaration.isPackageMemberTypeDeclaration()) { 316 PackageDeclaration packageDeclaration= ((CompilationUnit) node.getParent()).getPackage(); 317 if (packageDeclaration == null) { 318 return typeName.equals(name); 319 } 320 return typeName.equals(getQualifiedIdentifier(packageDeclaration.getName()) + '.' + name); 321 } 322 if (!typeName.endsWith('$' + name)) { 323 return false; 324 } 325 typeName= typeName.substring(0, typeName.length() - name.length() - 1); 326 node= node.getParent(); 327 } 328 } else if (node instanceof ClassInstanceCreation) { 329 int index= typeName.lastIndexOf('$'); 330 if (index < 0) { 331 return false; 332 } 333 for (int i= typeName.length() - 1; i > index; i--) { 334 if (!Character.isDigit(typeName.charAt(i))) { 335 return false; 336 } 337 } 338 typeName= typeName.substring(0, index); 339 ASTNode parent= node.getParent(); 340 while (!(parent instanceof CompilationUnit)) { 341 node= parent; 342 parent= node.getParent(); 343 } 344 } 345 } 346 } 347 return false; 348 } 349 350 private StringBuffer buildTypeBody(StringBuffer buffer, List list) { 351 StringBuffer source = new StringBuffer (); 352 353 source.append('{').append('\n'); 354 355 if (buffer != null) { 356 fSnippetStartPosition+= source.length(); 357 } 358 359 source.append(buildBody(buffer, list)); 360 source.append('}').append('\n'); 361 362 return source; 363 } 364 365 private StringBuffer buildEnumBody(StringBuffer buffer, List constantDeclarations, List bodyDeclarations) { 366 StringBuffer source = new StringBuffer (); 367 368 source.append('{').append('\n'); 369 if (constantDeclarations.isEmpty()) { 370 source.append(';').append('\n'); 371 } else { 372 for (Iterator iter= constantDeclarations.iterator(); iter.hasNext();) { 373 source.append(((EnumConstantDeclaration) iter.next()).getName().getIdentifier()); 374 if (iter.hasNext()) { 375 source.append(','); 376 } else { 377 source.append(';'); 378 } 379 source.append('\n'); 380 } 381 } 382 383 if (buffer != null) { 384 fSnippetStartPosition+= source.length(); 385 } 386 387 source.append(buildBody(buffer, bodyDeclarations)); 388 source.append('}').append('\n'); 389 390 return source; 391 392 } 393 394 399 private StringBuffer buildBody(StringBuffer buffer, List list) { 400 StringBuffer source= new StringBuffer (); 401 if (buffer != null) { 402 fSnippetStartPosition += source.length(); 403 source.append(buffer.toString()); 404 } 405 for (Iterator iterator= list.iterator(); iterator.hasNext();) { 406 BodyDeclaration bodyDeclaration= (BodyDeclaration) iterator.next(); 407 if (bodyDeclaration instanceof FieldDeclaration) { 408 source.append(buildFieldDeclaration((FieldDeclaration) bodyDeclaration)); 409 } else if (bodyDeclaration instanceof MethodDeclaration) { 410 source.append(buildMethodDeclaration((MethodDeclaration) bodyDeclaration)); 411 } else if (bodyDeclaration instanceof TypeDeclaration) { 412 TypeDeclaration typeDeclaration = (TypeDeclaration) bodyDeclaration; 413 if (!typeDeclaration.getName().getIdentifier().equals(fLastTypeName)) { 414 source.append(buildTypeDeclaration(null, typeDeclaration)); 415 } 416 } else if (bodyDeclaration instanceof EnumDeclaration) { 417 EnumDeclaration enumDeclaration= (EnumDeclaration) bodyDeclaration; 418 if (!enumDeclaration.getName().getIdentifier().equals(fLastTypeName)) { 419 source.append(buildEnumDeclaration(null, enumDeclaration)); 420 } 421 } 422 } 423 return source; 424 } 425 426 private StringBuffer buildFieldDeclaration(FieldDeclaration fieldDeclaration) { 427 StringBuffer source = new StringBuffer (); 428 429 source.append(Flags.toString(fieldDeclaration.getModifiers())); 430 source.append(' '); 431 source.append(getDotName(getTypeName(fieldDeclaration.getType()))); 432 source.append(' '); 433 434 boolean first= true; 435 for (Iterator iterator= fieldDeclaration.fragments().iterator(); iterator.hasNext();) { 436 VariableDeclarationFragment variableDeclarationFragment= (VariableDeclarationFragment) iterator.next(); 437 if (first) { 438 first = false; 439 } else { 440 source.append(','); 441 } 442 source.append(variableDeclarationFragment.getName().getIdentifier()); 443 for (int i= 0, dim= variableDeclarationFragment.getExtraDimensions(); i < dim; i++) { 444 source.append('[').append(']'); 445 } 446 } 447 448 source.append(';').append('\n'); 449 450 return source; 451 } 452 453 private StringBuffer buildMethodDeclaration(MethodDeclaration methodDeclaration) { 454 StringBuffer source = new StringBuffer (); 455 int modifiers= methodDeclaration.getModifiers(); 456 source.append(Flags.toString(modifiers)); 457 source.append(' '); 458 459 appendTypeParameters(source, methodDeclaration.typeParameters()); 460 461 boolean isConstructor= methodDeclaration.isConstructor(); 462 if (!isConstructor) { 463 source.append(getDotName(getTypeName(methodDeclaration.getReturnType2()))); 464 source.append(' '); 465 } 466 467 source.append(methodDeclaration.getName().getIdentifier()); 468 source.append(' ').append('('); 469 470 boolean first= true; 471 for (Iterator iterator = methodDeclaration.parameters().iterator(); iterator.hasNext();) { 472 SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration) iterator.next(); 473 if (first) { 474 first = false; 475 } else { 476 source.append(','); 477 } 478 source.append(getDotName(getTypeName(singleVariableDeclaration.getType()))); 479 if (singleVariableDeclaration.isVarargs()) { 480 source.append("..."); } 482 source.append(' '); 483 source.append(singleVariableDeclaration.getName().getIdentifier()); 484 appendExtraDimensions(source, singleVariableDeclaration.getExtraDimensions()); 485 } 486 487 source.append(')'); 488 489 appendExtraDimensions(source, methodDeclaration.getExtraDimensions()); 490 491 first = true; 492 for (Iterator iterator = methodDeclaration.thrownExceptions().iterator(); iterator.hasNext();) { 493 Name name = (Name) iterator.next(); 494 if (first) { 495 first = false; 496 source.append(" throws "); } else { 498 source.append(','); 499 } 500 source.append(getQualifiedIdentifier(name)); 501 } 502 503 if (Flags.isAbstract(modifiers) || Flags.isNative(modifiers)) { 504 source.append(";\n"); } else { 507 source.append('{').append('\n'); 508 if (!isConstructor) { 509 source.append(getReturnExpression(methodDeclaration.getReturnType2())); 510 } 511 source.append('}').append('\n'); 512 } 513 514 return source; 515 } 516 517 private void appendExtraDimensions(StringBuffer source, int extraDimension) { 518 if (extraDimension > 0) { 519 source.append(' '); 520 for (int i= 0; i < extraDimension; i ++) { 521 source.append("[]"); } 523 } 524 } 525 526 private StringBuffer buildEnumDeclaration(StringBuffer buffer, EnumDeclaration enumDeclaration) { 527 StringBuffer source = new StringBuffer (); 528 source.append(Flags.toString(enumDeclaration.getModifiers())); 529 source.append(" enum "); 531 source.append(enumDeclaration.getName().getIdentifier()); 532 533 Iterator iterator= enumDeclaration.superInterfaceTypes().iterator(); 534 if (iterator.hasNext()) { 535 source.append(" implements "); source.append(getTypeName((Type) iterator.next())); 537 while (iterator.hasNext()) { 538 source.append(','); 539 source.append(getTypeName((Type) iterator.next())); 540 } 541 } 542 543 if (buffer != null) { 544 fSnippetStartPosition+= source.length(); 545 } 546 source.append(buildEnumBody(buffer, enumDeclaration.enumConstants(), enumDeclaration.bodyDeclarations())); 547 548 return source; 549 } 550 551 552 private StringBuffer buildTypeDeclaration(StringBuffer buffer, TypeDeclaration typeDeclaration) { 553 554 StringBuffer source = new StringBuffer (); 555 source.append(Flags.toString(typeDeclaration.getModifiers())); 556 if (typeDeclaration.isInterface()) { 557 source.append(" interface "); } else { 559 source.append(" class "); } 561 562 source.append(typeDeclaration.getName().getIdentifier()); 563 564 List typeParameters= typeDeclaration.typeParameters(); 565 if (!typeParameters.isEmpty() && isSourceLevelGreaterOrEqual(1, 5)) { 566 source.append('<'); 567 Iterator iter= typeParameters.iterator(); 568 TypeParameter typeParameter= (TypeParameter) iter.next(); 569 source.append(typeParameter.getName().getIdentifier()); 570 List typeBounds= typeParameter.typeBounds(); 571 if (!typeBounds.isEmpty()) { 572 source.append(" extends "); Iterator iter2= typeBounds.iterator(); 574 source.append(getTypeName((Type) iter2.next())); 575 while (iter2.hasNext()) { 576 source.append('&'); 577 source.append(getTypeName((Type) iter2.next())); 578 } 579 } 580 while (iter.hasNext()) { 581 source.append(','); 582 typeParameter= (TypeParameter) iter.next(); 583 source.append(typeParameter.getName().getIdentifier()); 584 typeBounds= typeParameter.typeBounds(); 585 if (!typeBounds.isEmpty()) { 586 source.append(" extends "); Iterator iter2= typeBounds.iterator(); 588 source.append(getTypeName((Type) iter2.next())); 589 while (iter2.hasNext()) { 590 source.append('&'); 591 source.append(getTypeName((Type) iter2.next())); 592 } 593 } 594 } 595 source.append('>'); 596 } 597 598 Type superClass = typeDeclaration.getSuperclassType(); 599 if (superClass != null) { 600 source.append(" extends "); source.append(getTypeName(superClass)); 602 } 603 604 Iterator iter= typeDeclaration.superInterfaceTypes().iterator(); 605 if (iter.hasNext()) { 606 if (typeDeclaration.isInterface()) { 607 source.append(" extends "); } else { 609 source.append(" implements "); } 611 source.append(getTypeName((Type) iter.next())); 612 while (iter.hasNext()) { 613 source.append(','); 614 source.append(getTypeName((Type) iter.next())); 615 } 616 } 617 618 if (buffer != null) { 619 fSnippetStartPosition+= source.length(); 620 } 621 source.append(buildTypeBody(buffer, typeDeclaration.bodyDeclarations())); 622 623 return source; 624 } 625 626 private StringBuffer buildCompilationUnit(StringBuffer buffer, CompilationUnit compilationUnit) { 627 StringBuffer source = new StringBuffer (); 628 629 PackageDeclaration packageDeclaration = compilationUnit.getPackage(); 630 if (packageDeclaration != null) { 631 source.append("package "); source.append(getQualifiedIdentifier(packageDeclaration.getName())); 633 source.append(";\n"); } 635 636 for (Iterator iterator = compilationUnit.imports().iterator(); iterator.hasNext();) { 637 ImportDeclaration importDeclaration = (ImportDeclaration) iterator.next(); 638 source.append("import "); if (importDeclaration.isStatic()) { 640 source.append("static "); } 642 source.append(getQualifiedIdentifier(importDeclaration.getName())); 643 if (importDeclaration.isOnDemand()) { 644 source.append(".*"); } 646 source.append(";\n"); } 648 649 fSnippetStartPosition += source.length(); 650 source.append(buffer); 651 652 for (Iterator iterator = compilationUnit.types().iterator(); iterator.hasNext();) { 653 AbstractTypeDeclaration typeDeclaration = (AbstractTypeDeclaration) iterator.next(); 654 if (Flags.isPublic(typeDeclaration.getModifiers())) { 655 fCompilationUnitName = typeDeclaration.getName().getIdentifier(); 656 } 657 if (!fLastTypeName.equals(typeDeclaration.getName().getIdentifier())) { 658 if (typeDeclaration instanceof TypeDeclaration) { 659 &n
|