1 12 13 package org.eclipse.jdt.internal.compiler.apt.model; 14 15 import java.io.IOException ; 16 import java.io.Writer ; 17 import java.util.ArrayList ; 18 import java.util.Collections ; 19 import java.util.HashMap ; 20 import java.util.HashSet ; 21 import java.util.LinkedHashSet ; 22 import java.util.List ; 23 import java.util.Map ; 24 import java.util.Set ; 25 import java.util.regex.Matcher ; 26 import java.util.regex.Pattern ; 27 28 import javax.lang.model.element.AnnotationMirror; 29 import javax.lang.model.element.AnnotationValue; 30 import javax.lang.model.element.Element; 31 import javax.lang.model.element.ElementKind; 32 import javax.lang.model.element.ExecutableElement; 33 import javax.lang.model.element.Name; 34 import javax.lang.model.element.PackageElement; 35 import javax.lang.model.element.TypeElement; 36 import javax.lang.model.util.Elements; 37 38 import org.eclipse.jdt.core.compiler.CharOperation; 39 import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; 40 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; 41 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; 42 import org.eclipse.jdt.internal.compiler.ast.Javadoc; 43 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; 44 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; 45 import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; 46 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; 47 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; 48 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; 49 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; 50 import org.eclipse.jdt.internal.compiler.lookup.MethodVerifier; 51 import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; 52 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; 53 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; 54 import org.eclipse.jdt.internal.compiler.lookup.TagBits; 55 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; 56 57 61 public class ElementsImpl implements Elements { 62 63 private static final Pattern INITIAL_DELIMITER = Pattern.compile("^\\s*/\\*+"); 66 private final BaseProcessingEnvImpl _env; 67 68 72 public ElementsImpl(BaseProcessingEnvImpl env) { 73 _env = env; 74 } 75 76 82 @Override 83 public List <? extends AnnotationMirror> getAllAnnotationMirrors(Element e) { 84 if (e.getKind() == ElementKind.CLASS && e instanceof TypeElementImpl) { 86 List <AnnotationBinding> annotations = new ArrayList <AnnotationBinding>(); 87 Set <ReferenceBinding> annotationTypes = new HashSet <ReferenceBinding>(); 89 ReferenceBinding binding = (ReferenceBinding)((TypeElementImpl)e)._binding; 90 while (null != binding) { 91 for (AnnotationBinding annotation : binding.getAnnotations()) { 92 if (annotation == null) continue; 93 ReferenceBinding annotationType = annotation.getAnnotationType(); 94 if (!annotationTypes.contains(annotationType)) { 95 annotationTypes.add(annotationType); 96 annotations.add(annotation); 97 } 98 } 99 binding = binding.superclass(); 100 } 101 List <AnnotationMirror> list = new ArrayList <AnnotationMirror>(annotations.size()); 102 for (AnnotationBinding annotation : annotations) { 103 list.add(_env.getFactory().newAnnotationMirror(annotation)); 104 } 105 return Collections.unmodifiableList(list); 106 } 107 else { 108 return e.getAnnotationMirrors(); 109 } 110 } 111 112 130 @Override 131 public List <? extends Element> getAllMembers(TypeElement type) { 132 if (null == type || !(type instanceof TypeElementImpl)) { 133 return Collections.emptyList(); 134 } 135 ReferenceBinding binding = (ReferenceBinding)((TypeElementImpl)type)._binding; 136 Map <String , ReferenceBinding> types = new HashMap <String , ReferenceBinding>(); 138 List <FieldBinding> fields = new ArrayList <FieldBinding>(); 140 Map <String , Set <MethodBinding>> methods = new HashMap <String , Set <MethodBinding>>(); 142 Set <ReferenceBinding> superinterfaces = new LinkedHashSet <ReferenceBinding>(); 143 boolean ignoreVisibility = true; 144 while (null != binding) { 145 addMembers(binding, ignoreVisibility, types, fields, methods); 146 Set <ReferenceBinding> newfound = new LinkedHashSet <ReferenceBinding>(); 147 collectSuperInterfaces(binding, superinterfaces, newfound); 148 for (ReferenceBinding superinterface : newfound) { 149 addMembers(superinterface, false, types, fields, methods); 150 } 151 superinterfaces.addAll(newfound); 152 binding = binding.superclass(); 153 ignoreVisibility = false; 154 } 155 List <Element> allMembers = new ArrayList <Element>(); 156 for (ReferenceBinding nestedType : types.values()) { 157 allMembers.add(_env.getFactory().newElement(nestedType)); 158 } 159 for (FieldBinding field : fields) { 160 allMembers.add(_env.getFactory().newElement(field)); 161 } 162 for (Set <MethodBinding> sameNamedMethods : methods.values()) { 163 for (MethodBinding method : sameNamedMethods) { 164 allMembers.add(_env.getFactory().newElement(method)); 165 } 166 } 167 return allMembers; 168 } 169 170 178 private void collectSuperInterfaces(ReferenceBinding type, 179 Set <ReferenceBinding> existing, Set <ReferenceBinding> newfound) { 180 for (ReferenceBinding superinterface : type.superInterfaces()) { 181 if (!existing.contains(superinterface) && !newfound.contains(superinterface)) { 182 newfound.add(superinterface); 183 collectSuperInterfaces(superinterface, existing, newfound); 184 } 185 } 186 } 187 188 199 private void addMembers(ReferenceBinding binding, boolean ignoreVisibility, Map <String , ReferenceBinding> types, 200 List <FieldBinding> fields, Map <String , Set <MethodBinding>> methods) 201 { 202 for (ReferenceBinding subtype : binding.memberTypes()) { 203 if (ignoreVisibility || !subtype.isPrivate()) { 204 String name = new String (subtype.sourceName()); 205 if (null == types.get(name)) { 206 types.put(name, subtype); 207 } 208 } 209 } 210 for (FieldBinding field : binding.fields()) { 211 if (ignoreVisibility || !field.isPrivate()) { 212 fields.add(field); 213 } 214 } 215 for (MethodBinding method : binding.methods()) { 216 if (!method.isSynthetic() && (ignoreVisibility || (!method.isPrivate() && !method.isConstructor()))) { 217 String methodName = new String (method.selector); 218 Set <MethodBinding> sameNamedMethods = methods.get(methodName); 219 if (null == sameNamedMethods) { 220 sameNamedMethods = new HashSet <MethodBinding>(4); 223 methods.put(methodName, sameNamedMethods); 224 sameNamedMethods.add(method); 225 } 226 else { 227 boolean unique = true; 229 if (!ignoreVisibility) { 230 for (MethodBinding existing : sameNamedMethods) { 231 MethodVerifier verifier = _env.getLookupEnvironment().methodVerifier(); 232 if (verifier.doesMethodOverride(existing, method)) { 233 unique = false; 234 break; 235 } 236 } 237 } 238 if (unique) { 239 sameNamedMethods.add(method); 240 } 241 } 242 } 243 } 244 } 245 246 249 @Override 250 public Name getBinaryName(TypeElement type) { 251 TypeElementImpl typeElementImpl = (TypeElementImpl) type; 252 ReferenceBinding referenceBinding = (ReferenceBinding) typeElementImpl._binding; 253 return new NameImpl( 254 CharOperation.replaceOnCopy(referenceBinding.constantPoolName(), '/', '.')); 255 } 256 257 260 @Override 261 public String getConstantExpression(Object value) { 262 if (!(value instanceof Integer ) 263 && !(value instanceof Byte ) 264 && !(value instanceof Float ) 265 && !(value instanceof Double ) 266 && !(value instanceof Long ) 267 && !(value instanceof Short ) 268 && !(value instanceof Character ) 269 && !(value instanceof String ) 270 && !(value instanceof Boolean )) { 271 throw new IllegalArgumentException ("Not a valid wrapper type : " + value.getClass()); } 273 if (value instanceof Character ) { 274 StringBuilder builder = new StringBuilder (); 275 builder.append('\'').append(value).append('\''); 276 return String.valueOf(builder); 277 } 278 return String.valueOf(value); 279 } 280 281 284 @Override 285 public String getDocComment(Element e) { 286 char[] unparsed = getUnparsedDocComment(e); 287 return formatJavadoc(unparsed); 288 } 289 290 295 private char[] getUnparsedDocComment(Element e) 296 { 297 Javadoc javadoc = null; 298 ReferenceContext referenceContext = null; 299 switch(e.getKind()) { 300 case ANNOTATION_TYPE : 301 case CLASS : 302 case ENUM : 303 case INTERFACE : 304 TypeElementImpl typeElementImpl = (TypeElementImpl) e; 305 ReferenceBinding referenceBinding = (ReferenceBinding)typeElementImpl._binding; 306 if (referenceBinding instanceof SourceTypeBinding) { 307 SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) referenceBinding; 308 referenceContext = sourceTypeBinding.scope.referenceContext; 309 javadoc = ((TypeDeclaration) referenceContext).javadoc; 310 } 311 break; 312 case PACKAGE : 313 PackageElementImpl packageElementImpl = (PackageElementImpl) e; 315 PackageBinding packageBinding = (PackageBinding) packageElementImpl._binding; 316 char[][] compoundName = CharOperation.arrayConcat(packageBinding.compoundName, TypeConstants.PACKAGE_INFO_NAME); 317 ReferenceBinding type = this._env.getLookupEnvironment().getType(compoundName); 318 if (type != null && type.isValidBinding() && (type instanceof SourceTypeBinding)) { 319 SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) type; 320 referenceContext = sourceTypeBinding.scope.referenceContext; 321 javadoc = ((TypeDeclaration) referenceContext).javadoc; 322 } 323 break; 324 case CONSTRUCTOR : 325 case METHOD : 326 ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) e; 327 MethodBinding methodBinding = (MethodBinding) executableElementImpl._binding; 328 AbstractMethodDeclaration sourceMethod = methodBinding.sourceMethod(); 329 if (sourceMethod != null) { 330 javadoc = sourceMethod.javadoc; 331 referenceContext = sourceMethod; 332 } 333 break; 334 case ENUM_CONSTANT : 335 case FIELD : 336 VariableElementImpl variableElementImpl = (VariableElementImpl) e; 337 FieldBinding fieldBinding = (FieldBinding) variableElementImpl._binding; 338 FieldDeclaration sourceField = fieldBinding.sourceField(); 339 if (sourceField != null) { 340 javadoc = sourceField.javadoc; 341 if (fieldBinding.declaringClass instanceof SourceTypeBinding) { 342 SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) fieldBinding.declaringClass; 343 referenceContext = sourceTypeBinding.scope.referenceContext; 344 } 345 } 346 } 347 if (javadoc != null && referenceContext != null) { 348 char[] contents = referenceContext.compilationResult().getCompilationUnit().getContents(); 349 if (contents != null) { 350 return CharOperation.subarray(contents, javadoc.sourceStart, javadoc.sourceEnd - 1); 351 } 352 } 353 return null; 354 } 355 356 363 private static String formatJavadoc(char[] unparsed) 364 { 365 if (unparsed == null || unparsed.length < 5) { return null; 367 } 368 369 String [] lines = new String (unparsed).split("\n"); Matcher delimiterMatcher = INITIAL_DELIMITER.matcher(lines[0]); 371 if (!delimiterMatcher.find()) { 372 return null; 373 } 374 int iOpener = delimiterMatcher.end(); 375 lines[0] = lines[0].substring(iOpener); 376 if (lines.length == 1) { 377 StringBuilder sb = new StringBuilder (); 380 char[] chars = lines[0].toCharArray(); 381 boolean startingWhitespaces = true; 382 for (char c : chars) { 383 if (Character.isWhitespace(c)) 384 if (startingWhitespaces) { 385 continue; 386 } else { 387 sb.append(c); 388 } else { 389 startingWhitespaces = false; 390 sb.append(c); 391 } 392 } 393 return sb.toString(); 394 } 395 396 int firstLine = lines[0].trim().length() > 0 ? 0 : 1; 398 399 int lastLine = lines[lines.length - 1].trim().length() > 0 ? lines.length - 1 : lines.length - 2; 401 402 StringBuilder sb = new StringBuilder (); 403 if (lines[0].length() != 0 && firstLine == 1) { 404 sb.append('\n'); 406 } 407 boolean preserveLineSeparator = lines[0].length() == 0; 408 for (int line = firstLine; line <= lastLine; ++line) { 409 char[] chars = lines[line].toCharArray(); 410 int starsIndex = getStars(chars); 411 int leadingWhitespaces = 0; 412 boolean recordLeadingWhitespaces = true; 413 for (int i = 0, max = chars.length; i < max; i++) { 414 char c = chars[i]; 415 switch(c) { 416 case '\t' : 417 if (starsIndex == -1) { 418 if (recordLeadingWhitespaces) { 419 leadingWhitespaces += 8; 420 } else { 421 sb.append(c); 422 } 423 } else if (i >= starsIndex) { 424 sb.append(c); 425 } 426 break; 427 case ' ' : 428 if (starsIndex == -1) { 429 if (recordLeadingWhitespaces) { 430 leadingWhitespaces++; 431 } else { 432 sb.append(c); 433 } 434 } else if (i >= starsIndex) { 435 sb.append(c); 436 } 437 break; 438 default : 439 recordLeadingWhitespaces = false; 441 if (leadingWhitespaces != 0) { 442 int numberOfTabs = leadingWhitespaces / 8; 443 if (numberOfTabs != 0) { 444 for (int j = 0, max2 = numberOfTabs; j < max2; j++) { 445 sb.append(" "); } 447 if ((leadingWhitespaces % 8) >= 1) { 448 sb.append(' '); 449 } 450 } else if (line != 0) { 451 for (int j = 0, max2 = leadingWhitespaces; j < max2; j++) { 453 sb.append(' '); 454 } 455 } 456 leadingWhitespaces = 0; 457 sb.append(c); 458 } else if (c != '*' || i > starsIndex) { 459 sb.append(c); 460 } 461 } 462 } 463 464 int end = lines.length - 1; 466 if (line < end) { 467 sb.append('\n'); 468 } else if (preserveLineSeparator && line == end) { 469 sb.append('\n'); 470 } 471 } 472 return sb.toString(); 473 } 474 475 481 private static int getStars(char[] line) { 482 loop: for (int i = 0, max = line.length; i < max; i++) { 483 char c = line[i]; 484 if (!Character.isWhitespace(c)) { 485 if (c == '*') { 486 for (int j = i + 1; j < max; j++) { 489 if (line[j] != '*') { 490 return j; 491 } 492 } 493 return max - 1; 494 } 495 break loop; 497 } 498 } 499 return -1; 500 } 501 508 @Override 509 public Map <? extends ExecutableElement, ? extends AnnotationValue> getElementValuesWithDefaults( 510 AnnotationMirror a) { 511 return ((AnnotationMirrorImpl)a).getElementValuesWithDefaults(); 512 } 513 514 517 @Override 518 public Name getName(CharSequence cs) { 519 return new NameImpl(cs); 520 } 521 522 @Override 523 public PackageElement getPackageElement(CharSequence name) { 524 LookupEnvironment le = _env.getLookupEnvironment(); 525 if (name.length() == 0) { 526 return new PackageElementImpl(_env, le.defaultPackage); 527 } 528 char[] packageName = name.toString().toCharArray(); 529 PackageBinding packageBinding = le.createPackage(CharOperation.splitOn('.', packageName)); 530 if (packageBinding == null) { 531 return null; 532 } 533 return new PackageElementImpl(_env, packageBinding); 534 } 535 536 @Override 537 public PackageElement getPackageOf(Element type) { 538 switch(type.getKind()) { 539 case ANNOTATION_TYPE : 540 case CLASS : 541 case ENUM : 542 case INTERFACE : 543 TypeElementImpl typeElementImpl = (TypeElementImpl) type; 544 ReferenceBinding referenceBinding = (ReferenceBinding)typeElementImpl._binding; 545 return (PackageElement) _env.getFactory().newElement(referenceBinding.fPackage); 546 case PACKAGE : 547 return (PackageElement) type; 548 case CONSTRUCTOR : 549 case METHOD : 550 ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) type; 551 MethodBinding methodBinding = (MethodBinding) executableElementImpl._binding; 552 return (PackageElement) _env.getFactory().newElement(methodBinding.declaringClass.fPackage); 553 case ENUM_CONSTANT : 554 case FIELD : 555 VariableElementImpl variableElementImpl = (VariableElementImpl) type; 556 FieldBinding fieldBinding = (FieldBinding) variableElementImpl._binding; 557 return (PackageElement) _env.getFactory().newElement(fieldBinding.declaringClass.fPackage); 558 case PARAMETER : 559 variableElementImpl = (VariableElementImpl) type; 560 LocalVariableBinding localVariableBinding = (LocalVariableBinding) variableElementImpl._binding; 561 return (PackageElement) _env.getFactory().newElement(localVariableBinding.declaringScope.classScope().referenceContext.binding.fPackage); 562 case EXCEPTION_PARAMETER : 563 case INSTANCE_INIT : 564 case OTHER : 565 case STATIC_INIT : 566 case TYPE_PARAMETER : 567 case LOCAL_VARIABLE : 568 return null; 569 } 570 return null; 572 } 573 574 577 @Override 578 public TypeElement getTypeElement(CharSequence name) { 579 LookupEnvironment le = _env.getLookupEnvironment(); 580 final char[][] compoundName = CharOperation.splitOn('.', name.toString().toCharArray()); 581 ReferenceBinding binding = le.getType(compoundName); 582 if (null == binding) { 585 ReferenceBinding topLevelBinding = null; 586 int topLevelSegments = compoundName.length; 587 while (--topLevelSegments > 0) { 588 char[][] topLevelName = new char[topLevelSegments][]; 589 for (int i = 0; i < topLevelSegments; ++i) { 590 topLevelName[i] = compoundName[i]; 591 } 592 topLevelBinding = le.getType(topLevelName); 593 if (null != topLevelBinding) { 594 break; 595 } 596 } 597 if (null == topLevelBinding) { 598 return null; 599 } 600 binding = topLevelBinding; 601 for (int i = topLevelSegments; null != binding && i < compoundName.length; ++i) { 602 binding = binding.getMemberType(compoundName[i]); 603 } 604 } 605 if (null == binding) { 606 return null; 607 } 608 return new TypeElementImpl(_env, binding); 609 } 610 611 617 @Override 618 public boolean hides(Element hider, Element hidden) { 619 if (hidden == null) { 620 throw new NullPointerException (); 622 } 623 return ((ElementImpl)hider).hides(hidden); 624 } 625 626 629 @Override 630 public boolean isDeprecated(Element e) { 631 if (!(e instanceof ElementImpl)) { 632 return false; 633 } 634 return (((ElementImpl)e)._binding.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0; 635 } 636 637 641 @Override 642 public boolean overrides(ExecutableElement overrider, ExecutableElement overridden, 643 TypeElement type) { 644 if (overridden == null || type == null) { 645 throw new NullPointerException (); 646 } 647 return ((ExecutableElementImpl)overrider).overrides(overridden, type); 648 } 649 650 653 @Override 654 public void printElements(Writer w, Element... elements) { 655 String lineSeparator = System.getProperty("line.separator"); for (Element element : elements) { 657 try { 658 w.write(element.toString()); 659 w.write(lineSeparator); 660 } catch (IOException e) { 661 } 663 } 664 try { 665 w.flush(); 666 } catch (IOException e) { 667 } 669 } 670 671 } 672 | Popular Tags |