src/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java

Tue, 13 Jan 2009 13:27:14 +0000

author
mcimadamore
date
Tue, 13 Jan 2009 13:27:14 +0000
changeset 184
905e151a185a
parent 117
24a47c3062fe
child 554
9d9f26857129
permissions
-rw-r--r--

6765045: Remove rawtypes warnings from langtools
Summary: Removed all occurrences of rawtypes warnings from langtools
Reviewed-by: jjg, bpatel

duke@1 1 /*
xdono@117 2 * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
duke@1 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1 4 *
duke@1 5 * This code is free software; you can redistribute it and/or modify it
duke@1 6 * under the terms of the GNU General Public License version 2 only, as
duke@1 7 * published by the Free Software Foundation. Sun designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
duke@1 9 * by Sun in the LICENSE file that accompanied this code.
duke@1 10 *
duke@1 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@1 15 * accompanied this code).
duke@1 16 *
duke@1 17 * You should have received a copy of the GNU General Public License version
duke@1 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@1 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1 20 *
duke@1 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@1 22 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@1 23 * have any questions.
duke@1 24 */
duke@1 25
duke@1 26 package com.sun.tools.doclets.internal.toolkit.util;
duke@1 27
duke@1 28 import com.sun.javadoc.*;
duke@1 29 import com.sun.tools.doclets.internal.toolkit.*;
duke@1 30 import java.util.*;
duke@1 31
duke@1 32 /**
duke@1 33 * A data structure that encapsulates the visible members of a particular
duke@1 34 * type for a given class tree. To use this data structor, you must specify
duke@1 35 * the type of member you are interested in (nested class, field, constructor
duke@1 36 * or method) and the leaf of the class tree. The data structure will map
duke@1 37 * all visible members in the leaf and classes above the leaf in the tree.
duke@1 38 *
duke@1 39 * This code is not part of an API.
duke@1 40 * It is implementation that is subject to change.
duke@1 41 * Do not use it as an API
duke@1 42 *
duke@1 43 * @author Atul M Dambalkar
duke@1 44 * @author Jamie Ho (rewrite)
duke@1 45 */
duke@1 46 public class VisibleMemberMap {
duke@1 47
duke@1 48 private boolean noVisibleMembers = true;
duke@1 49
duke@1 50 public static final int INNERCLASSES = 0;
duke@1 51 public static final int ENUM_CONSTANTS = 1;
duke@1 52 public static final int FIELDS = 2;
duke@1 53 public static final int CONSTRUCTORS = 3;
duke@1 54 public static final int METHODS = 4;
duke@1 55 public static final int ANNOTATION_TYPE_MEMBER_OPTIONAL = 5;
duke@1 56 public static final int ANNOTATION_TYPE_MEMBER_REQUIRED = 6;
duke@1 57
duke@1 58 /**
duke@1 59 * The total number of member types is {@value}.
duke@1 60 */
duke@1 61 public static final int NUM_MEMBER_TYPES = 7;
duke@1 62
duke@1 63 public static final String STARTLEVEL = "start";
duke@1 64
duke@1 65 /**
duke@1 66 * List of ClassDoc objects for which ClassMembers objects are built.
duke@1 67 */
jjg@74 68 private final List<ClassDoc> visibleClasses = new ArrayList<ClassDoc>();
duke@1 69
duke@1 70 /**
duke@1 71 * Map for each member name on to a map which contains members with same
duke@1 72 * name-signature. The mapped map will contain mapping for each MemberDoc
duke@1 73 * onto it's respecive level string.
duke@1 74 */
jjg@74 75 private final Map<Object,Map<ProgramElementDoc,String>> memberNameMap = new HashMap<Object,Map<ProgramElementDoc,String>>();
duke@1 76
duke@1 77 /**
duke@1 78 * Map of class and it's ClassMembers object.
duke@1 79 */
jjg@74 80 private final Map<ClassDoc,ClassMembers> classMap = new HashMap<ClassDoc,ClassMembers>();
duke@1 81
duke@1 82 /**
duke@1 83 * Type whose visible members are requested. This is the leaf of
duke@1 84 * the class tree being mapped.
duke@1 85 */
duke@1 86 private final ClassDoc classdoc;
duke@1 87
duke@1 88 /**
duke@1 89 * Member kind: InnerClasses/Fields/Methods?
duke@1 90 */
duke@1 91 private final int kind;
duke@1 92
duke@1 93 /**
duke@1 94 * Deprected members should be excluded or not?
duke@1 95 */
duke@1 96 private final boolean nodepr;
duke@1 97
duke@1 98 /**
duke@1 99 * Construct a VisibleMemberMap of the given type for the given
duke@1 100 * class. If nodepr is true, exclude the deprecated members from
duke@1 101 * the map.
duke@1 102 *
duke@1 103 * @param classdoc the class whose members are being mapped.
duke@1 104 * @param kind the kind of member that is being mapped.
duke@1 105 * @param nodepr if true, exclude the deprecated members from the map.
duke@1 106 */
duke@1 107 public VisibleMemberMap(ClassDoc classdoc, int kind, boolean nodepr) {
duke@1 108 this.classdoc = classdoc;
duke@1 109 this.nodepr = nodepr;
duke@1 110 this.kind = kind;
duke@1 111 new ClassMembers(classdoc, STARTLEVEL).build();
duke@1 112 }
duke@1 113
duke@1 114 /**
duke@1 115 * Return the list of visible classes in this map.
duke@1 116 *
duke@1 117 * @return the list of visible classes in this map.
duke@1 118 */
mcimadamore@184 119 public List<ClassDoc> getVisibleClassesList() {
duke@1 120 sort(visibleClasses);
duke@1 121 return visibleClasses;
duke@1 122 }
duke@1 123
duke@1 124 /**
duke@1 125 * Return the package private members inherited by the class. Only return
duke@1 126 * if parent is package private and not documented.
duke@1 127 *
duke@1 128 * @param configuation the current configuration of the doclet.
duke@1 129 * @return the package private members inherited by the class.
duke@1 130 */
jjg@74 131 private List<ProgramElementDoc> getInheritedPackagePrivateMethods(Configuration configuration) {
jjg@74 132 List<ProgramElementDoc> results = new ArrayList<ProgramElementDoc>();
mcimadamore@184 133 for (Iterator<ClassDoc> iter = visibleClasses.iterator(); iter.hasNext(); ) {
mcimadamore@184 134 ClassDoc currentClass = iter.next();
duke@1 135 if (currentClass != classdoc &&
duke@1 136 currentClass.isPackagePrivate() &&
duke@1 137 !Util.isLinkable(currentClass, configuration)) {
duke@1 138 // Document these members in the child class because
duke@1 139 // the parent is inaccessible.
duke@1 140 results.addAll(getMembersFor(currentClass));
duke@1 141 }
duke@1 142 }
duke@1 143 return results;
duke@1 144 }
duke@1 145
duke@1 146 /**
duke@1 147 * Return the visible members of the class being mapped. Also append at the
duke@1 148 * end of the list members that are inherited by inaccessible parents. We
duke@1 149 * document these members in the child because the parent is not documented.
duke@1 150 *
duke@1 151 * @param configuation the current configuration of the doclet.
duke@1 152 */
jjg@74 153 public List<ProgramElementDoc> getLeafClassMembers(Configuration configuration) {
jjg@74 154 List<ProgramElementDoc> result = getMembersFor(classdoc);
duke@1 155 result.addAll(getInheritedPackagePrivateMethods(configuration));
duke@1 156 return result;
duke@1 157 }
duke@1 158
duke@1 159 /**
duke@1 160 * Retrn the list of members for the given class.
duke@1 161 *
duke@1 162 * @param cd the class to retrieve the list of visible members for.
duke@1 163 *
duke@1 164 * @return the list of members for the given class.
duke@1 165 */
jjg@74 166 public List<ProgramElementDoc> getMembersFor(ClassDoc cd) {
jjg@74 167 ClassMembers clmembers = classMap.get(cd);
duke@1 168 if (clmembers == null) {
jjg@74 169 return new ArrayList<ProgramElementDoc>();
duke@1 170 }
duke@1 171 return clmembers.getMembers();
duke@1 172 }
duke@1 173
duke@1 174 /**
duke@1 175 * Sort the given mixed list of classes and interfaces to a list of
duke@1 176 * classes followed by interfaces traversed. Don't sort alphabetically.
duke@1 177 */
jjg@74 178 private void sort(List<ClassDoc> list) {
jjg@74 179 List<ClassDoc> classes = new ArrayList<ClassDoc>();
jjg@74 180 List<ClassDoc> interfaces = new ArrayList<ClassDoc>();
duke@1 181 for (int i = 0; i < list.size(); i++) {
jjg@74 182 ClassDoc cd = list.get(i);
duke@1 183 if (cd.isClass()) {
duke@1 184 classes.add(cd);
duke@1 185 } else {
duke@1 186 interfaces.add(cd);
duke@1 187 }
duke@1 188 }
duke@1 189 list.clear();
duke@1 190 list.addAll(classes);
duke@1 191 list.addAll(interfaces);
duke@1 192 }
duke@1 193
jjg@74 194 private void fillMemberLevelMap(List<ProgramElementDoc> list, String level) {
duke@1 195 for (int i = 0; i < list.size(); i++) {
jjg@74 196 Object key = getMemberKey(list.get(i));
jjg@74 197 Map<ProgramElementDoc,String> memberLevelMap = memberNameMap.get(key);
duke@1 198 if (memberLevelMap == null) {
jjg@74 199 memberLevelMap = new HashMap<ProgramElementDoc,String>();
duke@1 200 memberNameMap.put(key, memberLevelMap);
duke@1 201 }
duke@1 202 memberLevelMap.put(list.get(i), level);
duke@1 203 }
duke@1 204 }
duke@1 205
mcimadamore@184 206 private void purgeMemberLevelMap(List<ProgramElementDoc> list, String level) {
duke@1 207 for (int i = 0; i < list.size(); i++) {
mcimadamore@184 208 Object key = getMemberKey(list.get(i));
mcimadamore@184 209 Map<ProgramElementDoc, String> memberLevelMap = memberNameMap.get(key);
duke@1 210 if (level.equals(memberLevelMap.get(list.get(i))))
duke@1 211 memberLevelMap.remove(list.get(i));
duke@1 212 }
duke@1 213 }
duke@1 214
duke@1 215 /**
duke@1 216 * Represents a class member. We should be able to just use a
duke@1 217 * ProgramElementDoc instead of this class, but that doesn't take
duke@1 218 * type variables in consideration when comparing.
duke@1 219 */
duke@1 220 private class ClassMember {
jjg@74 221 private Set<ProgramElementDoc> members;
duke@1 222
duke@1 223 public ClassMember(ProgramElementDoc programElementDoc) {
jjg@74 224 members = new HashSet<ProgramElementDoc>();
duke@1 225 members.add(programElementDoc);
duke@1 226 }
duke@1 227
duke@1 228 public void addMember(ProgramElementDoc programElementDoc) {
duke@1 229 members.add(programElementDoc);
duke@1 230 }
duke@1 231
duke@1 232 public boolean isEqual(MethodDoc member) {
mcimadamore@184 233 for (Iterator<ProgramElementDoc> iter = members.iterator(); iter.hasNext(); ) {
duke@1 234 MethodDoc member2 = (MethodDoc) iter.next();
duke@1 235 if (Util.executableMembersEqual(member, member2)) {
duke@1 236 members.add(member);
duke@1 237 return true;
duke@1 238 }
duke@1 239 }
duke@1 240 return false;
duke@1 241 }
duke@1 242 }
duke@1 243
duke@1 244 /**
duke@1 245 * A data structure that represents the class members for
duke@1 246 * a visible class.
duke@1 247 */
duke@1 248 private class ClassMembers {
duke@1 249
duke@1 250 /**
duke@1 251 * The mapping class, whose inherited members are put in the
duke@1 252 * {@link #members} list.
duke@1 253 */
duke@1 254 private ClassDoc mappingClass;
duke@1 255
duke@1 256 /**
duke@1 257 * List of inherited members from the mapping class.
duke@1 258 */
jjg@74 259 private List<ProgramElementDoc> members = new ArrayList<ProgramElementDoc>();
duke@1 260
duke@1 261 /**
duke@1 262 * Level/Depth of inheritance.
duke@1 263 */
duke@1 264 private String level;
duke@1 265
duke@1 266 /**
duke@1 267 * Return list of inherited members from mapping class.
duke@1 268 *
duke@1 269 * @return List Inherited members.
duke@1 270 */
jjg@74 271 public List<ProgramElementDoc> getMembers() {
duke@1 272 return members;
duke@1 273 }
duke@1 274
duke@1 275 private ClassMembers(ClassDoc mappingClass, String level) {
duke@1 276 this.mappingClass = mappingClass;
duke@1 277 this.level = level;
duke@1 278 if (classMap.containsKey(mappingClass) &&
jjg@74 279 level.startsWith(classMap.get(mappingClass).level)) {
duke@1 280 //Remove lower level class so that it can be replaced with
duke@1 281 //same class found at higher level.
duke@1 282 purgeMemberLevelMap(getClassMembers(mappingClass, false),
jjg@74 283 classMap.get(mappingClass).level);
duke@1 284 classMap.remove(mappingClass);
duke@1 285 visibleClasses.remove(mappingClass);
duke@1 286 }
duke@1 287 if (!classMap.containsKey(mappingClass)) {
duke@1 288 classMap.put(mappingClass, this);
duke@1 289 visibleClasses.add(mappingClass);
duke@1 290 }
duke@1 291
duke@1 292 }
duke@1 293
duke@1 294 private void build() {
duke@1 295 if (kind == CONSTRUCTORS) {
duke@1 296 addMembers(mappingClass);
duke@1 297 } else {
duke@1 298 mapClass();
duke@1 299 }
duke@1 300 }
duke@1 301
duke@1 302 private void mapClass() {
duke@1 303 addMembers(mappingClass);
duke@1 304 ClassDoc[] interfaces = mappingClass.interfaces();
duke@1 305 for (int i = 0; i < interfaces.length; i++) {
duke@1 306 String locallevel = level + 1;
duke@1 307 ClassMembers cm = new ClassMembers(interfaces[i], locallevel);
duke@1 308 cm.mapClass();
duke@1 309 }
duke@1 310 if (mappingClass.isClass()) {
duke@1 311 ClassDoc superclass = mappingClass.superclass();
duke@1 312 if (!(superclass == null || mappingClass.equals(superclass))) {
duke@1 313 ClassMembers cm = new ClassMembers(superclass,
duke@1 314 level + "c");
duke@1 315 cm.mapClass();
duke@1 316 }
duke@1 317 }
duke@1 318 }
duke@1 319
duke@1 320 /**
duke@1 321 * Get all the valid members from the mapping class. Get the list of
duke@1 322 * members for the class to be included into(ctii), also get the level
duke@1 323 * string for ctii. If mapping class member is not already in the
duke@1 324 * inherited member list and if it is visible in the ctii and not
duke@1 325 * overridden, put such a member in the inherited member list.
duke@1 326 * Adjust member-level-map, class-map.
duke@1 327 */
duke@1 328 private void addMembers(ClassDoc fromClass) {
jjg@74 329 List<ProgramElementDoc> cdmembers = getClassMembers(fromClass, true);
jjg@74 330 List<ProgramElementDoc> incllist = new ArrayList<ProgramElementDoc>();
duke@1 331 for (int i = 0; i < cdmembers.size(); i++) {
jjg@74 332 ProgramElementDoc pgmelem = cdmembers.get(i);
duke@1 333 if (!found(members, pgmelem) &&
duke@1 334 memberIsVisible(pgmelem) &&
duke@1 335 !isOverridden(pgmelem, level)) {
duke@1 336 incllist.add(pgmelem);
duke@1 337 }
duke@1 338 }
duke@1 339 if (incllist.size() > 0) {
duke@1 340 noVisibleMembers = false;
duke@1 341 }
duke@1 342 members.addAll(incllist);
duke@1 343 fillMemberLevelMap(getClassMembers(fromClass, false), level);
duke@1 344 }
duke@1 345
duke@1 346 /**
duke@1 347 * Is given doc item visible in given classdoc in terms fo inheritance?
duke@1 348 * The given doc item is visible in the given classdoc if it is public
duke@1 349 * or protected and if it is package-private if it's containing class
duke@1 350 * is in the same package as the given classdoc.
duke@1 351 */
duke@1 352 private boolean memberIsVisible(ProgramElementDoc pgmdoc) {
duke@1 353 if (pgmdoc.containingClass().equals(classdoc)) {
duke@1 354 //Member is in class that we are finding visible members for.
duke@1 355 //Of course it is visible.
duke@1 356 return true;
duke@1 357 } else if (pgmdoc.isPrivate()) {
duke@1 358 //Member is in super class or implemented interface.
duke@1 359 //Private, so not inherited.
duke@1 360 return false;
duke@1 361 } else if (pgmdoc.isPackagePrivate()) {
duke@1 362 //Member is package private. Only return true if its class is in
duke@1 363 //same package.
duke@1 364 return pgmdoc.containingClass().containingPackage().equals(
duke@1 365 classdoc.containingPackage());
duke@1 366 } else {
duke@1 367 //Public members are always inherited.
duke@1 368 return true;
duke@1 369 }
duke@1 370 }
duke@1 371
duke@1 372 /**
duke@1 373 * Return all available class members.
duke@1 374 */
jjg@74 375 private List<ProgramElementDoc> getClassMembers(ClassDoc cd, boolean filter) {
duke@1 376 if (cd.isEnum() && kind == CONSTRUCTORS) {
duke@1 377 //If any of these rules are hit, return empty array because
duke@1 378 //we don't document these members ever.
duke@1 379 return Arrays.asList(new ProgramElementDoc[] {});
duke@1 380 }
duke@1 381 ProgramElementDoc[] members = null;
duke@1 382 switch (kind) {
duke@1 383 case ANNOTATION_TYPE_MEMBER_OPTIONAL:
duke@1 384 members = cd.isAnnotationType() ?
duke@1 385 filter((AnnotationTypeDoc) cd, false) :
duke@1 386 new AnnotationTypeElementDoc[] {};
duke@1 387 break;
duke@1 388 case ANNOTATION_TYPE_MEMBER_REQUIRED:
duke@1 389 members = cd.isAnnotationType() ?
duke@1 390 filter((AnnotationTypeDoc) cd, true) :
duke@1 391 new AnnotationTypeElementDoc[] {};
duke@1 392 break;
duke@1 393 case INNERCLASSES:
duke@1 394 members = cd.innerClasses(filter);
duke@1 395 break;
duke@1 396 case ENUM_CONSTANTS:
duke@1 397 members = cd.enumConstants();
duke@1 398 break;
duke@1 399 case FIELDS:
duke@1 400 members = cd.fields(filter);
duke@1 401 break;
duke@1 402 case CONSTRUCTORS:
duke@1 403 members = cd.constructors();
duke@1 404 break;
duke@1 405 case METHODS:
duke@1 406 members = cd.methods(filter);
duke@1 407 break;
duke@1 408 default:
duke@1 409 members = new ProgramElementDoc[0];
duke@1 410 }
duke@1 411 if (nodepr) {
duke@1 412 return Util.excludeDeprecatedMembersAsList(members);
duke@1 413 }
duke@1 414 return Arrays.asList(members);
duke@1 415 }
duke@1 416
duke@1 417 /**
duke@1 418 * Filter the annotation type members and return either the required
duke@1 419 * members or the optional members, depending on the value of the
duke@1 420 * required parameter.
duke@1 421 *
duke@1 422 * @param doc The annotation type to process.
duke@1 423 * @param required
duke@1 424 * @return the annotation type members and return either the required
duke@1 425 * members or the optional members, depending on the value of the
duke@1 426 * required parameter.
duke@1 427 */
duke@1 428 private AnnotationTypeElementDoc[] filter(AnnotationTypeDoc doc,
duke@1 429 boolean required) {
jjg@74 430 AnnotationTypeElementDoc[] members = doc.elements();
jjg@74 431 List<AnnotationTypeElementDoc> targetMembers = new ArrayList<AnnotationTypeElementDoc>();
duke@1 432 for (int i = 0; i < members.length; i++) {
duke@1 433 if ((required && members[i].defaultValue() == null) ||
duke@1 434 ((!required) && members[i].defaultValue() != null)){
duke@1 435 targetMembers.add(members[i]);
duke@1 436 }
duke@1 437 }
jjg@74 438 return targetMembers.toArray(new AnnotationTypeElementDoc[]{});
duke@1 439 }
duke@1 440
mcimadamore@184 441 private boolean found(List<ProgramElementDoc> list, ProgramElementDoc elem) {
duke@1 442 for (int i = 0; i < list.size(); i++) {
mcimadamore@184 443 ProgramElementDoc pgmelem = list.get(i);
duke@1 444 if (Util.matches(pgmelem, elem)) {
duke@1 445 return true;
duke@1 446 }
duke@1 447 }
duke@1 448 return false;
duke@1 449 }
duke@1 450
duke@1 451
duke@1 452 /**
duke@1 453 * Is member overridden? The member is overridden if it is found in the
duke@1 454 * same level hierarchy e.g. member at level "11" overrides member at
duke@1 455 * level "111".
duke@1 456 */
duke@1 457 private boolean isOverridden(ProgramElementDoc pgmdoc, String level) {
mcimadamore@184 458 Map<?,String> memberLevelMap = (Map<?,String>) memberNameMap.get(getMemberKey(pgmdoc));
duke@1 459 if (memberLevelMap == null)
duke@1 460 return false;
duke@1 461 String mappedlevel = null;
mcimadamore@184 462 Iterator<String> iterator = memberLevelMap.values().iterator();
duke@1 463 while (iterator.hasNext()) {
mcimadamore@184 464 mappedlevel = iterator.next();
duke@1 465 if (mappedlevel.equals(STARTLEVEL) ||
duke@1 466 (level.startsWith(mappedlevel) &&
duke@1 467 !level.equals(mappedlevel))) {
duke@1 468 return true;
duke@1 469 }
duke@1 470 }
duke@1 471 return false;
duke@1 472 }
duke@1 473 }
duke@1 474
duke@1 475 /**
duke@1 476 * Return true if this map has no visible members.
duke@1 477 *
duke@1 478 * @return true if this map has no visible members.
duke@1 479 */
duke@1 480 public boolean noVisibleMembers() {
duke@1 481 return noVisibleMembers;
duke@1 482 }
duke@1 483
duke@1 484 private ClassMember getClassMember(MethodDoc member) {
mcimadamore@184 485 for (Iterator<?> iter = memberNameMap.keySet().iterator(); iter.hasNext();) {
duke@1 486 Object key = iter.next();
duke@1 487 if (key instanceof String) {
duke@1 488 continue;
duke@1 489 } else if (((ClassMember) key).isEqual(member)) {
duke@1 490 return (ClassMember) key;
duke@1 491 }
duke@1 492 }
duke@1 493 return new ClassMember(member);
duke@1 494 }
duke@1 495
duke@1 496 /**
duke@1 497 * Return the key to the member map for the given member.
duke@1 498 */
duke@1 499 private Object getMemberKey(ProgramElementDoc doc) {
duke@1 500 if (doc.isConstructor()) {
duke@1 501 return doc.name() + ((ExecutableMemberDoc)doc).signature();
duke@1 502 } else if (doc.isMethod()) {
duke@1 503 return getClassMember((MethodDoc) doc);
duke@1 504 } else if (doc.isField() || doc.isEnumConstant() || doc.isAnnotationTypeElement()) {
duke@1 505 return doc.name();
duke@1 506 } else { // it's a class or interface
duke@1 507 String classOrIntName = doc.name();
duke@1 508 //Strip off the containing class name because we only want the member name.
duke@1 509 classOrIntName = classOrIntName.indexOf('.') != 0 ? classOrIntName.substring(classOrIntName.lastIndexOf('.'), classOrIntName.length()) : classOrIntName;
duke@1 510 return "clint" + classOrIntName;
duke@1 511 }
duke@1 512 }
duke@1 513 }

mercurial