1 package spoon.support.template; 2 3 import java.util.ArrayList ; 4 import java.util.Collection ; 5 import java.util.List ; 6 import java.util.TreeSet ; 7 8 import spoon.reflect.Factory; 9 import spoon.reflect.code.CtAbstractInvocation; 10 import spoon.reflect.code.CtArrayAccess; 11 import spoon.reflect.code.CtBlock; 12 import spoon.reflect.code.CtCodeElement; 13 import spoon.reflect.code.CtExpression; 14 import spoon.reflect.code.CtFieldAccess; 15 import spoon.reflect.code.CtInvocation; 16 import spoon.reflect.code.CtLiteral; 17 import spoon.reflect.code.CtReturn; 18 import spoon.reflect.code.CtStatement; 19 import spoon.reflect.code.CtVariableAccess; 20 import spoon.reflect.declaration.CtAnnotation; 21 import spoon.reflect.declaration.CtClass; 22 import spoon.reflect.declaration.CtConstructor; 23 import spoon.reflect.declaration.CtElement; 24 import spoon.reflect.declaration.CtExecutable; 25 import spoon.reflect.declaration.CtField; 26 import spoon.reflect.declaration.CtMethod; 27 import spoon.reflect.declaration.CtNamedElement; 28 import spoon.reflect.declaration.CtParameter; 29 import spoon.reflect.declaration.CtSimpleType; 30 import spoon.reflect.declaration.CtTypedElement; 31 import spoon.reflect.reference.CtArrayTypeReference; 32 import spoon.reflect.reference.CtExecutableReference; 33 import spoon.reflect.reference.CtFieldReference; 34 import spoon.reflect.reference.CtReference; 35 import spoon.reflect.reference.CtTypeReference; 36 import spoon.reflect.visitor.CtInheritanceScanner; 37 import spoon.reflect.visitor.CtScanner; 38 import spoon.template.Local; 39 import spoon.template.Parameter; 40 import spoon.template.Template; 41 import spoon.template.TemplateParameter; 42 43 class SkipException extends RuntimeException { 44 private static final long serialVersionUID = 1L; 45 46 Object skipped; 47 48 public SkipException(Object e) { 49 super("skipping " + e.toString()); 50 skipped = e; 51 } 52 53 } 54 55 58 public class SubstitutionVisitor extends CtScanner { 59 60 public class InheritanceSustitutionScanner extends CtInheritanceScanner { 61 62 SubstitutionVisitor parent = null; 63 64 public InheritanceSustitutionScanner(SubstitutionVisitor parent) { 65 this.parent = parent; 66 } 67 68 72 @Override 73 public <R> void scanCtExecutable(CtExecutable<R> e) { 74 for (CtParameter<?> parameter : new ArrayList <CtParameter>(e 76 .getParameters())) { 77 String name = parameter.getSimpleName(); 78 for (String pname : parameterNames) { 79 if (name.equals(pname)) { 80 Object value = Parameters.getValue(template, pname, 81 null); 82 int i = parameter.getParent().getParameters().indexOf( 83 parameter); 84 if (value instanceof List ) { 85 List l = (List ) value; 86 for (Object p : l) { 87 CtParameter<?> p2 = e.getFactory().Core() 88 .clone((CtParameter) p); 89 p2.setParent(parameter.getParent()); 90 parameter.getParent().getParameters().add(i++, 91 p2); 92 } 93 parameter.getParent().getParameters().remove( 94 parameter); 95 } 96 } 97 } 98 } 99 super.scanCtExecutable(e); 100 } 101 102 105 @Override 106 public void scanCtElement(CtElement e) { 107 CtAnnotation a = e.getAnnotation(e.getFactory().Type() 108 .createReference(Local.class)); 109 if (a != null) 110 e.getAnnotations().remove(a); 111 super.scanCtElement(e); 112 } 113 114 118 @Override 119 public void scanCtNamedElement(CtNamedElement element) { 120 if (element.getDocComment() != null) { 121 element.setDocComment(substituteInDocComment(element 122 .getDocComment())); 123 } 124 String name = element.getSimpleName(); 126 for (String pname : parameterNames) { 127 if (name.contains(pname)) { 128 Object value = Parameters.getValue(template, pname, null); 129 if (value instanceof String ) { 130 name = name.replace(pname, (String ) value); 132 element.setSimpleName(name); 133 } else if ((value instanceof CtTypeReference) 134 && (element instanceof CtSimpleType)) { 135 name = name.replace(pname, ((CtTypeReference) value) 137 .getSimpleName()); 138 element.setSimpleName(name); 139 } 140 } 141 } 142 super.scanCtNamedElement(element); 143 } 144 145 private String substituteInDocComment(String docComment) { 146 String result = docComment; 147 for (String pname : parameterNames) { 148 Object value = Parameters.getValue(template, pname, null); 149 if (value instanceof String ) { 150 result = result.replace(pname, (String ) value); 151 } 152 } 153 return result; 154 } 155 156 164 @Override 165 public <T> void visitCtClass(CtClass<T> ctClass) { 166 ctClass.getSuperInterfaces().remove( 167 f.Type().createReference(Template.class)); 168 for (CtMethod m : new TreeSet <CtMethod>(ctClass.getMethods())) { 169 if (m.getAnnotation(Local.class) != null) { 170 ctClass.getMethods().remove(m); 171 } 172 } 173 for (CtConstructor c : new TreeSet <CtConstructor>(ctClass 174 .getConstructors())) { 175 if (c.getAnnotation(Local.class) != null) { 176 ctClass.getConstructors().remove(c); 177 } 178 } 179 for (CtField<?> field : new TreeSet <CtField>(ctClass.getFields())) { 180 if (field.getAnnotation(Local.class) != null 181 || Parameters.isParameterSource(field.getReference())) { 182 ctClass.getFields().remove(field); 183 continue; 184 } 185 String name = field.getSimpleName(); 187 for (String pname : parameterNames) { 188 if (name.equals(pname)) { 189 Object value = Parameters.getValue(template, pname, 190 null); 191 int i = ctClass.getFields().indexOf(field); 192 if (value instanceof List ) { 193 List l = (List ) value; 194 for (Object f : l) { 195 CtField<?> f2 = ctClass.getFactory().Core() 196 .clone((CtField) f); 197 f2.setParent(ctClass); 198 ctClass.getFields().add(i++, f2); 199 } 200 ctClass.getFields().remove(field); 201 } 202 } 203 } 204 } 205 super.visitCtClass(ctClass); 206 } 207 208 211 @SuppressWarnings ("unchecked") 212 @Override 213 public <T> void visitCtFieldAccess(CtFieldAccess<T> fieldAccess) { 214 CtFieldReference<?> ref = fieldAccess.getVariable(); 215 if (Parameters.isParameterSource(ref)) { 216 Object value = Parameters.getValue(template, ref 218 .getSimpleName(), Parameters.getIndex(fieldAccess)); 219 CtElement toReplace = fieldAccess; 220 if (fieldAccess.getParent() instanceof CtArrayAccess) { 221 toReplace = fieldAccess.getParent(); 222 } 223 if (!(value instanceof TemplateParameter)) { 224 if (value instanceof Class ) { 225 toReplace.replace(f.Code().createClassAccess( 226 f.Type().createReference( 227 ((Class ) value).getName()))); 228 } else if (value instanceof Enum ) { 229 CtTypeReference<?> enumType = f.Type().createReference( 230 value.getClass()); 231 toReplace.replace(f.Code().createVariableAccess( 232 f.Field().createReference(enumType, enumType, 233 ((Enum ) value).name()), true)); 234 } else if (value instanceof List ) { 235 List <CtParameter<?>> l = (List <CtParameter<?>>) value; 238 List <CtExpression<?>> vas = f.Code() 239 .createVariableAccesses(l); 240 CtAbstractInvocation<?> inv = (CtAbstractInvocation<?>) fieldAccess 241 .getParent(); 242 int i = inv.getArguments().indexOf(fieldAccess); 243 inv.getArguments().remove(i); 244 inv.getExecutable().getParameterTypes().remove(i); 245 for (CtExpression<?> va : vas) { 246 va.setParent(fieldAccess.getParent()); 247 inv.getArguments().add(i, va); 248 inv.getExecutable().getParameterTypes().add(i, 249 va.getType()); 250 i++; 251 } 252 } else if (value!=null && value.getClass().isArray()) { 253 toReplace.replace(f.Code().createLiteralArray((Object [])value)); 254 } else { 255 toReplace.replace(f.Code().createLiteral(value)); 256 } 257 } else { 258 toReplace.replace(((TemplateParameter<?>) value) 259 .getSubstitution(targetType)); 260 } 261 throw new SkipException(fieldAccess); 263 } else { 264 super.visitCtFieldAccess(fieldAccess); 265 } 266 267 } 268 269 272 @Override 273 public <T> void visitCtInvocation(CtInvocation<T> invocation) { 274 if (invocation.getExecutable().isOverloading(S)) { 275 CtFieldAccess<?> fa = null; 276 if ((invocation.getTarget() instanceof CtFieldAccess)) { 277 fa = (CtFieldAccess<?>) invocation.getTarget(); 278 } 279 if ((invocation.getTarget() instanceof CtArrayAccess && ((CtArrayAccess<?, CtExpression>) invocation 280 .getTarget()).getTarget() instanceof CtFieldAccess)) { 281 fa = (CtFieldAccess<?>) ((CtArrayAccess<?, CtExpression>) invocation 282 .getTarget()).getTarget(); 283 } 284 if (fa != null && fa.getTarget() == null) { 285 TemplateParameter<?> tparamValue = (TemplateParameter) Parameters 286 .getValue(template, fa.getVariable() 287 .getSimpleName(), Parameters.getIndex(fa)); 288 CtCodeElement r = null; 289 if (tparamValue != null) { 290 r = tparamValue.getSubstitution(targetType); 291 r.accept(parent); 296 } 297 if ((invocation.getParent() instanceof CtReturn) 298 && (r instanceof CtBlock)) { 299 invocation.getParent().replace(r); 303 } else { 304 invocation.replace(r); 305 } 306 } 307 throw new SkipException(invocation); 309 } else { 310 super.visitCtInvocation(invocation); 311 } 312 313 } 314 315 @SuppressWarnings ("unchecked") 316 @Override 317 public <T> void scanCtExpression(CtExpression<T> expression) { 318 for (int i = 0; i < expression.getTypeCasts().size(); i++) { 319 CtTypeReference<T> t = (CtTypeReference<T>) expression 320 .getTypeCasts().get(i); 321 if (parameterNames.contains(t.getSimpleName())) { 322 Object o = Parameters.getValue(template, t.getSimpleName(), 325 null); 326 if (o instanceof Class ) { 327 t = f.Type().createReference(((Class <T>) o)); 328 } else if (o instanceof CtTypeReference) { 329 t = (CtTypeReference<T>) o; 330 expression.getTypeCasts().set(i, t); 331 } else { 332 throw new RuntimeException ( 333 "unsupported reference substitution"); 334 } 335 } 336 } 337 if (expression instanceof CtLiteral) { 338 CtLiteral lit = (CtLiteral) expression; 339 if (lit.getValue() instanceof CtTypeReference) { 340 CtTypeReference t = (CtTypeReference) lit.getValue(); 341 if (parameterNames.contains(t.getSimpleName())) { 342 Object o = Parameters.getValue(template, t 346 .getSimpleName(), null); 347 if (o instanceof Class ) { 348 t = f.Type().createReference(((Class <T>) o)); 349 } else if (o instanceof CtTypeReference) { 350 t = (CtTypeReference<T>) o; 351 lit.setValue(t); 352 } else { 353 throw new RuntimeException ( 354 "unsupported reference substitution"); 355 } 356 } 357 } 358 } 359 super.scanCtExpression(expression); 360 } 361 362 @SuppressWarnings ("unchecked") 363 @Override 364 public <T> void scanCtTypedElement(CtTypedElement<T> e) { 365 if (e.getType() != null 366 && (!(e.getType() instanceof CtArrayTypeReference)) 367 && parameterNames.contains(e.getType().getSimpleName())) { 368 CtTypeReference<T> t; 371 Object o = Parameters.getValue(template, e.getType() 372 .getSimpleName(), null); 373 if (o instanceof Class ) { 374 t = f.Type().createReference(((Class <T>) o)); 375 } else if (o instanceof CtTypeReference) { 376 t = (CtTypeReference<T>) o; 377 e.setType(t); 378 } else { 379 throw new RuntimeException ( 380 "unsupported reference substitution"); 381 } 382 } 383 super.scanCtTypedElement(e); 384 } 385 386 public <T> void visitCtExecutableReference( 388 CtExecutableReference<T> reference) { 389 scanCtReference(reference); 390 visitCtTypeReference(reference.getDeclaringType()); 391 scanCtGenericElementReference(reference); 392 } 393 394 399 @Override 400 public <T> void visitCtTypeReference(CtTypeReference<T> reference) { 401 if (reference.equals(templateRef)) { 405 reference.setDeclaringType(targetRef.getDeclaringType()); 409 reference.setPackage(targetRef.getPackage()); 410 reference.setSimpleName(targetRef.getSimpleName()); 411 } 412 if (parameterNames.contains(reference.getSimpleName())) { 413 CtTypeReference<?> t; 416 Object o = Parameters.getValue(template, reference 417 .getSimpleName(), null); 418 if (o instanceof Class ) { 419 t = f.Type().createReference(((Class <?>) o)); 420 } else if (o instanceof CtTypeReference) { 421 t = (CtTypeReference<?>) o; 422 reference 423 .setActualTypeArguments(t.getActualTypeArguments()); 424 } else { 425 throw new RuntimeException ( 426 "unsupported reference substitution"); 427 } 428 reference.setPackage(t.getPackage()); 429 reference.setSimpleName(t.getSimpleName()); 430 reference.setDeclaringType(t.getDeclaringType()); 431 } 432 super.visitCtTypeReference(reference); 433 } 434 435 @SuppressWarnings ("unchecked") 436 @Override 437 public <T> void visitCtVariableAccess(CtVariableAccess<T> variableAccess) { 438 String name = variableAccess.getVariable().getSimpleName(); 439 for (String pname : parameterNames) { 440 if (name.contains(pname)) { 441 Object value = Parameters.getValue(template, pname, null); 442 if (value instanceof List && name.equals(pname)) { 443 List <CtParameter<?>> l = (List <CtParameter<?>>) value; 446 List <CtExpression<?>> vas = f.Code() 447 .createVariableAccesses(l); 448 CtAbstractInvocation<?> inv = (CtAbstractInvocation<?>) variableAccess 449 .getParent(); 450 int i = inv.getArguments().indexOf(variableAccess); 451 inv.getArguments().remove(i); 452 inv.getExecutable().getParameterTypes().remove(i); 453 for (CtExpression<?> va : vas) { 454 va.setParent(variableAccess.getParent()); 455 inv.getArguments().add(i, va); 456 inv.getExecutable().getParameterTypes().add(i, 457 va.getType()); 458 i++; 459 } 460 throw new SkipException(variableAccess); 462 } else { 463 if (value instanceof String ) { 465 name = name.replace(pname, (String ) value); 466 variableAccess.getVariable().setSimpleName(name); 467 } 468 } 469 } 470 } 471 CtTypeReference<T> reference = variableAccess.getType(); 472 if (parameterNames != null && reference != null 473 && parameterNames.contains(reference.getSimpleName())) { 474 CtTypeReference<T> t; 475 Object o = Parameters.getValue(template, reference 476 .getSimpleName(), null); 477 if (o instanceof Class ) { 478 t = f.Type().createReference(((Class <T>) o)); 479 } else if (o instanceof CtTypeReference) { 480 t = (CtTypeReference<T>) o; 481 reference 482 .setActualTypeArguments(t.getActualTypeArguments()); 483 } else { 484 throw new RuntimeException ( 485 "unsupported reference substitution"); 486 } 487 variableAccess.setType(t); 488 } 489 super.visitCtVariableAccess(variableAccess); 490 } 491 492 } 493 494 Factory f; 495 496 InheritanceSustitutionScanner inheritanceScanner; 497 498 CtExecutableReference S; 499 500 CtTypeReference<?> targetRef; 501 502 CtSimpleType<?> targetType; 503 504 Template template; 505 506 CtTypeReference<? extends Template> templateRef; 507 508 CtClass<? extends Template> templateType; 509 510 Collection <String > parameterNames; 511 512 522 public SubstitutionVisitor(Factory f, CtSimpleType<?> targetType, 523 Template template) { 524 inheritanceScanner = new InheritanceSustitutionScanner(this); 525 this.f = f; 526 this.template = template; 527 this.targetType = targetType; 528 this.S = f.Executable().createReference( 529 f.Type().createReference(TemplateParameter.class), 530 f.Type().createTypeParameterReference("T"), "S"); 531 this.templateRef = f.Type().createReference(template.getClass()); 532 this.templateType = f.Template().get( 533 templateRef.getQualifiedName()); 534 this.parameterNames = Parameters.getNames(templateType); 535 this.targetRef = f.Type().createReference(targetType); 536 this.targetRef.accept(this); 538 } 539 540 544 @Override 545 public void scan(Collection <? extends CtElement> elements) { 546 super.scan(new ArrayList <CtElement>(elements)); 547 } 548 549 @Override 550 public void scan(CtElement element) { 551 try { 552 inheritanceScanner.scan(element); 553 super.scan(element); 554 } catch (SkipException e) { 555 } catch (UndefinedParameterException upe) { 557 if (element instanceof CtStatement) { 558 element.replace(null); 559 } else { 560 throw upe; 561 } 562 } 563 } 564 565 568 @Override 569 public void scan(CtReference reference) { 570 if (reference == null) 571 return; 572 inheritanceScanner.scan(reference); 573 if (!(reference instanceof CtTypeReference)) { 574 String name = reference.getSimpleName(); 576 for (String pname : parameterNames) { 577 if (name.contains(pname)) { 578 name = name.replace(pname, (String ) Parameters.getValue( 579 template, pname, null)); 580 reference.setSimpleName(name); 581 } 582 } 583 super.scan(reference); 584 } else { 585 if (!(parameterNames.contains(reference.getSimpleName()) 586 && ((CtTypeReference<?>) reference).getDeclaringType() != null && ((CtTypeReference<?>) reference) 587 .getDeclaringType().equals(templateRef))) { 588 super.scan(reference); 589 } 590 } 591 } 592 } | Popular Tags |