001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.java.editor.codegen;
042:
043: import com.sun.source.tree.AnnotationTree;
044: import com.sun.source.tree.BlockTree;
045: import com.sun.source.tree.ClassTree;
046: import com.sun.source.tree.ExpressionTree;
047: import com.sun.source.tree.IdentifierTree;
048: import com.sun.source.tree.MemberSelectTree;
049: import com.sun.source.tree.MethodTree;
050: import com.sun.source.tree.ModifiersTree;
051: import com.sun.source.tree.StatementTree;
052: import com.sun.source.tree.Tree;
053: import com.sun.source.tree.TypeParameterTree;
054: import com.sun.source.tree.VariableTree;
055: import com.sun.source.util.TreePath;
056: import com.sun.source.util.TreePathScanner;
057: import com.sun.source.util.Trees;
058: import java.awt.Dialog;
059: import java.io.IOException;
060: import java.util.ArrayList;
061: import java.util.Collection;
062: import java.util.Collections;
063: import java.util.EnumSet;
064: import java.util.LinkedList;
065: import java.util.List;
066: import java.util.Random;
067: import java.util.Set;
068: import javax.lang.model.element.Element;
069: import javax.lang.model.element.ElementKind;
070: import javax.lang.model.element.ExecutableElement;
071: import javax.lang.model.element.Modifier;
072: import javax.lang.model.element.TypeElement;
073: import javax.lang.model.element.VariableElement;
074: import javax.lang.model.type.DeclaredType;
075: import javax.lang.model.type.TypeKind;
076: import javax.lang.model.type.TypeMirror;
077: import javax.lang.model.util.ElementFilter;
078: import javax.swing.text.JTextComponent;
079: import org.netbeans.api.java.source.Task;
080: import org.netbeans.api.java.source.CompilationController;
081: import org.netbeans.api.java.source.CompilationInfo;
082: import org.netbeans.api.java.source.ElementHandle;
083: import org.netbeans.api.java.source.JavaSource;
084: import org.netbeans.api.java.source.ModificationResult;
085: import org.netbeans.api.java.source.TreeMaker;
086: import org.netbeans.api.java.source.TreePathHandle;
087: import org.netbeans.api.java.source.WorkingCopy;
088: import org.netbeans.modules.editor.java.Utilities;
089: import org.netbeans.modules.java.editor.codegen.ui.ElementNode;
090: import org.netbeans.modules.java.editor.codegen.ui.EqualsHashCodePanel;
091: import org.openide.DialogDescriptor;
092: import org.openide.DialogDisplayer;
093: import org.openide.util.Exceptions;
094: import org.openide.util.NbBundle;
095:
096: /**
097: *
098: * @author Dusan Balek
099: */
100: public class EqualsHashCodeGenerator implements CodeGenerator {
101:
102: private static final String ERROR = "<error>"; //NOI18N
103:
104: public static class Factory implements CodeGenerator.Factory {
105:
106: public Factory() {
107: }
108:
109: public Iterable<? extends CodeGenerator> create(
110: CompilationController cc, TreePath path)
111: throws IOException {
112: path = Utilities
113: .getPathElementOfKind(Tree.Kind.CLASS, path);
114: if (path == null)
115: return Collections.emptySet();
116: cc.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
117:
118: Element elem = cc.getTrees().getElement(path);
119: if (elem == null) {
120: return Collections.emptySet();
121: }
122: EqualsHashCodeGenerator gen = createEqualsHashCodeGenerator(
123: cc, elem);
124:
125: if (gen == null) {
126: return Collections.emptySet();
127: } else {
128: return Collections.singleton(gen);
129: }
130: }
131: }
132:
133: final ElementNode.Description description;
134: final boolean generateEquals;
135: final boolean generateHashCode;
136:
137: /** Creates a new instance of EqualsHashCodeGenerator */
138: private EqualsHashCodeGenerator(
139: ElementNode.Description description,
140: boolean generateEquals, boolean generateHashCode) {
141: this .description = description;
142: this .generateEquals = generateEquals;
143: this .generateHashCode = generateHashCode;
144:
145: }
146:
147: public String getDisplayName() {
148: if (generateEquals && generateHashCode)
149: return org.openide.util.NbBundle.getMessage(
150: EqualsHashCodeGenerator.class,
151: "LBL_equals_and_hashcode"); //NOI18N
152: if (!generateEquals)
153: return org.openide.util.NbBundle.getMessage(
154: EqualsHashCodeGenerator.class, "LBL_hashcode"); //NOI18N
155: return org.openide.util.NbBundle.getMessage(
156: EqualsHashCodeGenerator.class, "LBL_equals"); //NOI18N
157: }
158:
159: static EqualsHashCodeGenerator createEqualsHashCodeGenerator(
160: CompilationController cc, Element el) throws IOException {
161: if (el.getKind() != ElementKind.CLASS)
162: return null;
163: //#125114: ignore anonymous innerclasses:
164: if (el.getSimpleName() == null
165: || el.getSimpleName().length() == 0) {
166: return null;
167: }
168: TypeElement typeElement = (TypeElement) el;
169:
170: ExecutableElement[] equalsHashCode = overridesHashCodeAndEquals(
171: cc, typeElement, null);
172:
173: List<ElementNode.Description> descriptions = new ArrayList<ElementNode.Description>();
174: for (VariableElement variableElement : ElementFilter
175: .fieldsIn(typeElement.getEnclosedElements())) {
176: if (!ERROR.contentEquals(variableElement.getSimpleName())
177: && !variableElement.getModifiers().contains(
178: Modifier.STATIC))
179: descriptions.add(ElementNode.Description.create(
180: variableElement, null, true, isUsed(cc,
181: variableElement, equalsHashCode)));
182: }
183: if (descriptions.isEmpty()
184: || (equalsHashCode[0] != null && equalsHashCode[1] != null))
185: return null;
186: return new EqualsHashCodeGenerator(ElementNode.Description
187: .create(typeElement, descriptions, false, false),
188: equalsHashCode[0] == null, equalsHashCode[1] == null);
189: }
190:
191: /** Checks whether a field is used inside given methods.
192: */
193: private static boolean isUsed(CompilationInfo cc,
194: VariableElement field, ExecutableElement... methods) {
195: class Used extends TreePathScanner<Void, VariableElement> {
196: boolean found;
197:
198: @Override
199: public Void visitIdentifier(IdentifierTree id,
200: VariableElement what) {
201: if (id.getName().equals(what.getSimpleName())) {
202: found = true;
203: }
204:
205: return super .visitIdentifier(id, what);
206: }
207:
208: @Override
209: public Void visitMemberSelect(MemberSelectTree sel,
210: VariableElement what) {
211: if (sel.getIdentifier().equals(what.getSimpleName())) {
212: found = true;
213: }
214: return super .visitMemberSelect(sel, what);
215: }
216: }
217: for (ExecutableElement e : methods) {
218: if (e == null) {
219: continue;
220: }
221: Trees tree = cc.getTrees();
222: TreePath path = tree.getPath(e);
223: Used used = new Used();
224: used.scan(path, field);
225: if (used.found) {
226: return true;
227: }
228: }
229: return false;
230: }
231:
232: /** Computes whether a class defines equals and hashcode or not.
233: * @param compilationInfo context
234: * @param type the class element to check
235: * @param stop array of booleans that is checked for [0], if true the method imediatelly returns
236: * @return array of two elements [0] is equals, if it exists, [1] is hashCode, if it exists, otherwise the indexes are null
237: */
238: public static ExecutableElement[] overridesHashCodeAndEquals(
239: CompilationInfo compilationInfo, Element type,
240: boolean[] stop) {
241: ExecutableElement[] ret = new ExecutableElement[2];
242:
243: TypeElement el = compilationInfo.getElements().getTypeElement(
244: "java.lang.Object"); // NOI18N
245:
246: if (el == null) {
247: return ret;
248: }
249: if (type == null || type.getKind() != ElementKind.CLASS) {
250: return ret;
251: }
252:
253: ExecutableElement hashCode = null;
254: ExecutableElement equals = null;
255:
256: for (Element method : el.getEnclosedElements()) {
257: if (stop != null && stop[0]) {
258: return ret;
259: }
260: if (method.getKind() == ElementKind.METHOD) {
261: if (method.getSimpleName().contentEquals("equals")) { // NOI18N
262: assert equals == null;
263: equals = (ExecutableElement) method;
264: }
265: if (method.getSimpleName().contentEquals("hashCode")) { // NOI18N
266: assert hashCode == null;
267: hashCode = (ExecutableElement) method;
268: }
269: }
270: }
271: assert hashCode != null;
272: assert equals != null;
273:
274: TypeElement clazz = (TypeElement) type;
275: for (Element ee : type.getEnclosedElements()) {
276: if (stop != null && stop[0]) {
277: return ret;
278: }
279: if (ee.getKind() != ElementKind.METHOD) {
280: continue;
281: }
282: ExecutableElement method = (ExecutableElement) ee;
283:
284: if (compilationInfo.getElements().overrides(method,
285: hashCode, clazz)) {
286: ret[1] = method;
287: }
288:
289: if (compilationInfo.getElements().overrides(method, equals,
290: clazz)) {
291: ret[0] = method;
292: }
293: }
294:
295: return ret;
296: }
297:
298: public static void invokeEqualsHashCode(
299: final TreePathHandle handle, final JTextComponent component) {
300: JavaSource js = JavaSource.forDocument(component.getDocument());
301: if (js != null) {
302: class FillIn implements Task<CompilationController> {
303: EqualsHashCodeGenerator gen;
304:
305: public void run(CompilationController cc)
306: throws Exception {
307: cc.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
308: Element e = handle.resolveElement(cc);
309:
310: gen = createEqualsHashCodeGenerator(cc, e);
311: }
312:
313: public void invoke() {
314: if (gen != null) {
315: gen.invoke(component);
316: }
317: }
318:
319: }
320: FillIn fillIn = new FillIn();
321: try {
322: js.runUserActionTask(fillIn, true);
323: fillIn.invoke();
324: } catch (IOException ex) {
325: Exceptions.printStackTrace(ex);
326: }
327: }
328: }
329:
330: public void invoke(JTextComponent component) {
331: final EqualsHashCodePanel panel = new EqualsHashCodePanel(
332: description, generateEquals, generateHashCode);
333: String title = NbBundle.getMessage(ConstructorGenerator.class,
334: "LBL_generate_equals_and_hashcode"); //NOI18N
335: if (!generateEquals)
336: title = NbBundle.getMessage(ConstructorGenerator.class,
337: "LBL_generate_hashcode"); //NOI18N
338: else if (!generateHashCode)
339: title = NbBundle.getMessage(ConstructorGenerator.class,
340: "LBL_generate_equals"); //NOI18N
341: DialogDescriptor dialogDescriptor = GeneratorUtils
342: .createDialogDescriptor(panel, title);
343: Dialog dialog = DialogDisplayer.getDefault().createDialog(
344: dialogDescriptor);
345: dialog.setVisible(true);
346: if (dialogDescriptor.getValue() == dialogDescriptor
347: .getDefaultValue()) {
348: JavaSource js = JavaSource.forDocument(component
349: .getDocument());
350: if (js != null) {
351: try {
352: final int caretOffset = component
353: .getCaretPosition();
354: ModificationResult mr = js
355: .runModificationTask(new Task<WorkingCopy>() {
356: public void run(WorkingCopy copy)
357: throws IOException {
358: copy
359: .toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
360: TreePath path = copy
361: .getTreeUtilities()
362: .pathFor(caretOffset);
363: path = Utilities
364: .getPathElementOfKind(
365: Tree.Kind.CLASS,
366: path);
367: int idx = GeneratorUtils
368: .findClassMemberIndex(copy,
369: (ClassTree) path
370: .getLeaf(),
371: caretOffset);
372: ArrayList<VariableElement> equalsElements = new ArrayList<VariableElement>();
373: if (generateEquals) {
374: for (ElementHandle<? extends Element> elementHandle : panel
375: .getEqualsVariables())
376: equalsElements
377: .add((VariableElement) elementHandle
378: .resolve(copy));
379: }
380: ArrayList<VariableElement> hashCodeElements = new ArrayList<VariableElement>();
381: if (generateHashCode) {
382: for (ElementHandle<? extends Element> elementHandle : panel
383: .getHashCodeVariables())
384: hashCodeElements
385: .add((VariableElement) elementHandle
386: .resolve(copy));
387: }
388: generateEqualsAndHashCode(
389: copy,
390: path,
391: generateEquals ? equalsElements
392: : null,
393: generateHashCode ? hashCodeElements
394: : null, idx);
395: }
396: });
397: GeneratorUtils.guardedCommit(component, mr);
398: } catch (IOException ex) {
399: Exceptions.printStackTrace(ex);
400: }
401: }
402: }
403: }
404:
405: public static void generateEqualsAndHashCode(WorkingCopy wc,
406: TreePath path) {
407: ExecutableElement[] arr = overridesHashCodeAndEquals(wc, wc
408: .getTrees().getElement(path), null);
409:
410: Collection<VariableElement> e = arr[0] == null ? Collections
411: .<VariableElement> emptySet() : null;
412: Collection<VariableElement> h = arr[1] == null ? Collections
413: .<VariableElement> emptySet() : null;
414:
415: generateEqualsAndHashCode(wc, path, e, h, -1);
416: }
417:
418: private static void generateEqualsAndHashCode(WorkingCopy wc,
419: TreePath path,
420: Iterable<? extends VariableElement> equalsFields,
421: Iterable<? extends VariableElement> hashCodeFields,
422: int index) {
423: assert path.getLeaf().getKind() == Tree.Kind.CLASS;
424: TypeElement te = (TypeElement) wc.getTrees().getElement(path);
425: if (te != null) {
426: TreeMaker make = wc.getTreeMaker();
427: ClassTree nue = (ClassTree) path.getLeaf();
428: if (hashCodeFields != null) {
429: if (index >= 0) {
430: nue = make.insertClassMember(nue, index,
431: createHashCodeMethod(wc, hashCodeFields,
432: (DeclaredType) te.asType()));
433: } else {
434: nue = make.addClassMember(nue,
435: createHashCodeMethod(wc, hashCodeFields,
436: (DeclaredType) te.asType()));
437: }
438: }
439: if (equalsFields != null) {
440: if (index >= 0) {
441: nue = make.insertClassMember(nue, index,
442: createEqualsMethod(wc, equalsFields,
443: (DeclaredType) te.asType()));
444: } else {
445: nue = make.addClassMember(nue, createEqualsMethod(
446: wc, equalsFields, (DeclaredType) te
447: .asType()));
448: }
449: }
450: wc.rewrite(path.getLeaf(), nue);
451: }
452: }
453:
454: private static MethodTree createEqualsMethod(WorkingCopy wc,
455: Iterable<? extends VariableElement> equalsFields,
456: DeclaredType type) {
457: TreeMaker make = wc.getTreeMaker();
458: Set<Modifier> mods = EnumSet.of(Modifier.PUBLIC);
459: List<VariableTree> params = Collections.singletonList(make
460: .Variable(make
461: .Modifiers(EnumSet.noneOf(Modifier.class)),
462: "obj", make.Type(wc.getElements()
463: .getTypeElement("java.lang.Object")
464: .asType()), null)); //NOI18N
465:
466: List<StatementTree> statements = new ArrayList<StatementTree>();
467: //if (obj == null) return false;
468: statements.add(make.If(make.Binary(Tree.Kind.EQUAL_TO, make
469: .Identifier("obj"), make.Identifier("null")), make
470: .Return(make.Identifier("false")), null)); //NOI18N
471: //if (getClass() != obj.getClass()) return false;
472: statements.add(make.If(make.Binary(Tree.Kind.NOT_EQUAL_TO, make
473: .MethodInvocation(Collections
474: .<ExpressionTree> emptyList(), make
475: .Identifier("getClass"), Collections
476: .<ExpressionTree> emptyList()), //NOI18N
477: make.MethodInvocation(Collections
478: .<ExpressionTree> emptyList(), make
479: .MemberSelect(make.Identifier("obj"),
480: "getClass"), Collections
481: .<ExpressionTree> emptyList())), make
482: .Return(make.Identifier("false")), null)); //NOI18N
483: //<this type> other = (<this type>) o;
484: statements.add(make.Variable(make.Modifiers(EnumSet
485: .of(Modifier.FINAL)), "other", make.Type(type), make
486: .TypeCast(make.Type(type), make.Identifier("obj")))); //NOI18N
487: for (VariableElement ve : equalsFields) {
488: TypeMirror tm = ve.asType();
489: if (tm.getKind().isPrimitive()
490: || tm.getKind() == TypeKind.DECLARED
491: && ((DeclaredType) tm).asElement().getKind() == ElementKind.ENUM) {
492: //if (this.<var> != other.<var>) return false;
493: statements.add(make.If(make.Binary(
494: Tree.Kind.NOT_EQUAL_TO, make
495: .MemberSelect(make.Identifier("this"),
496: ve.getSimpleName()), make
497: .MemberSelect(make.Identifier("other"),
498: ve.getSimpleName())), make
499: .Return(make.Identifier("false")), null)); //NOI18N
500: } else {
501: //if (this.<var> != other.<var> && (this.<var> == null || !this.<var>.equals(other.<var>))) return false;
502: ExpressionTree exp1 = make.Binary(
503: Tree.Kind.NOT_EQUAL_TO, make
504: .MemberSelect(make.Identifier("this"),
505: ve.getSimpleName()), make
506: .MemberSelect(make.Identifier("other"),
507: ve.getSimpleName())); //NOI18N
508: ExpressionTree exp2 = make.Binary(Tree.Kind.EQUAL_TO,
509: make.MemberSelect(make.Identifier("this"), ve
510: .getSimpleName()), make
511: .Identifier("null")); //NOI18N
512: ExpressionTree exp3 = make.Unary(
513: Tree.Kind.LOGICAL_COMPLEMENT,
514: make.MethodInvocation(Collections
515: .<ExpressionTree> emptyList(), make
516: .MemberSelect(make.MemberSelect(make
517: .Identifier("this"), ve
518: .getSimpleName()), "equals"),
519: Collections.singletonList(make
520: .MemberSelect(make
521: .Identifier("other"),
522: ve.getSimpleName())))); //NOI18N
523: statements.add(make.If(make.Binary(
524: Tree.Kind.CONDITIONAL_AND, exp1, make
525: .Parenthesized(make.Binary(
526: Tree.Kind.CONDITIONAL_OR, exp2,
527: exp3))), make.Return(make
528: .Identifier("false")), null)); //NOI18N
529: }
530: }
531: statements.add(make.Return(make.Identifier("true")));
532: BlockTree body = make.Block(statements, false);
533: ModifiersTree modifiers = prepareModifiers(wc, mods, make);
534:
535: return make.Method(modifiers, "equals", make
536: .PrimitiveType(TypeKind.BOOLEAN), Collections
537: .<TypeParameterTree> emptyList(), params, Collections
538: .<ExpressionTree> emptyList(), body, null); //NOI18N
539: }
540:
541: private static MethodTree createHashCodeMethod(WorkingCopy wc,
542: Iterable<? extends VariableElement> hashCodeFields,
543: DeclaredType type) {
544: TreeMaker make = wc.getTreeMaker();
545: Set<Modifier> mods = EnumSet.of(Modifier.PUBLIC);
546:
547: int startNumber = generatePrimeNumber(2, 10);
548: int multiplyNumber = generatePrimeNumber(10, 100);
549: List<StatementTree> statements = new ArrayList<StatementTree>();
550: //int hash = <startNumber>;
551: statements.add(make
552: .Variable(make
553: .Modifiers(EnumSet.noneOf(Modifier.class)),
554: "hash", make.PrimitiveType(TypeKind.INT), make
555: .Literal(startNumber))); //NOI18N
556: for (VariableElement ve : hashCodeFields) {
557: ExpressionTree variableRead;
558: switch (ve.asType().getKind()) {
559: case BYTE:
560: case CHAR:
561: case SHORT:
562: case INT:
563: variableRead = make.MemberSelect(make
564: .Identifier("this"), ve.getSimpleName()); //NOI18N
565: break;
566: case LONG:
567: variableRead = make.TypeCast(make
568: .PrimitiveType(TypeKind.INT), make
569: .Parenthesized(make.Binary(Tree.Kind.XOR, make
570: .MemberSelect(make.Identifier("this"),
571: ve.getSimpleName()), make
572: .Parenthesized(make.Binary(
573: Tree.Kind.UNSIGNED_RIGHT_SHIFT, //NOI18N
574: make.MemberSelect(make
575: .Identifier("this"), ve
576: .getSimpleName()), make
577: .Literal(32)))))); //NOI18N
578: break;
579: case FLOAT:
580: variableRead = make.MethodInvocation(Collections
581: .<ExpressionTree> emptyList(), make
582: .MemberSelect(make.Identifier("Float"),
583: "floatToIntBits"), //NOI18N
584: Collections.singletonList(make.MemberSelect(
585: make.Identifier("this"), ve
586: .getSimpleName()))); //NOI18N
587: break;
588: case DOUBLE:
589: ExpressionTree et = make.MethodInvocation(Collections
590: .<ExpressionTree> emptyList(), make
591: .MemberSelect(make.Identifier("Double"),
592: "doubleToLongBits"), //NOI18N
593: Collections.singletonList(make.MemberSelect(
594: make.Identifier("this"), ve
595: .getSimpleName()))); //NOI18N
596: variableRead = make.TypeCast(make
597: .PrimitiveType(TypeKind.INT), make
598: .Parenthesized(make.Binary(Tree.Kind.XOR, et,
599: make.Parenthesized(make.Binary(
600: Tree.Kind.UNSIGNED_RIGHT_SHIFT,
601: et, make.Literal(32)))))); //NOI18N
602: break;
603: case BOOLEAN:
604: variableRead = make.Parenthesized(make
605: .ConditionalExpression(make
606: .MemberSelect(make.Identifier("this"),
607: ve.getSimpleName()), make
608: .Literal(1), make.Literal(0))); //NOI18N
609: break;
610: default:
611: variableRead = make
612: .Parenthesized(make
613: .ConditionalExpression(
614: make
615: .Binary(
616: Tree.Kind.NOT_EQUAL_TO,
617: make
618: .MemberSelect(
619: make
620: .Identifier("this"),
621: ve
622: .getSimpleName()),
623: make
624: .Identifier("null")), //NOI18N
625: make
626: .MethodInvocation(
627: Collections
628: .<ExpressionTree> emptyList(),
629: make
630: .MemberSelect(
631: make
632: .MemberSelect(
633: make
634: .Identifier("this"),
635: ve
636: .getSimpleName()),
637: "hashCode"),
638: Collections
639: .<ExpressionTree> emptyList()), //NOI18N
640: make.Literal(0)));
641: }
642: statements.add(make.ExpressionStatement(make.Assignment(
643: make.Identifier("hash"), make.Binary(
644: Tree.Kind.PLUS, make.Binary(
645: Tree.Kind.MULTIPLY, make
646: .Literal(multiplyNumber),
647: make.Identifier("hash")),
648: variableRead)))); //NOI18N
649: }
650: statements.add(make.Return(make.Identifier("hash"))); //NOI18N
651: BlockTree body = make.Block(statements, false);
652: ModifiersTree modifiers = prepareModifiers(wc, mods, make);
653:
654: return make.Method(modifiers, "hashCode", make
655: .PrimitiveType(TypeKind.INT), Collections
656: .<TypeParameterTree> emptyList(), Collections
657: .<VariableTree> emptyList(), Collections
658: .<ExpressionTree> emptyList(), body, null); //NOI18N
659: }
660:
661: private static boolean isPrimeNumber(int n) {
662: int squareRoot = (int) Math.sqrt(n) + 1;
663: if (n % 2 == 0)
664: return false;
665: for (int cntr = 3; cntr < squareRoot; cntr++) {
666: if (n % cntr == 0)
667: return false;
668: }
669: return true;
670: }
671:
672: private static int generatePrimeNumber(int lowerLimit,
673: int higherLimit) {
674: Random r = new Random(System.currentTimeMillis());
675: int proposed = r.nextInt(higherLimit - lowerLimit) + lowerLimit;
676: while (!isPrimeNumber(proposed))
677: proposed++;
678: if (proposed > higherLimit) {
679: proposed--;
680: while (!isPrimeNumber(proposed))
681: proposed--;
682: }
683: return proposed;
684: }
685:
686: private static ModifiersTree prepareModifiers(WorkingCopy wc,
687: Set<Modifier> mods, TreeMaker make) {
688:
689: List<AnnotationTree> annotations = new LinkedList<AnnotationTree>();
690:
691: if (GeneratorUtils.supportsOverride(wc.getFileObject())) {
692: TypeElement override = wc.getElements().getTypeElement(
693: "java.lang.Override");
694:
695: if (override != null) {
696: annotations.add(wc.getTreeMaker().Annotation(
697: wc.getTreeMaker().QualIdent(override),
698: Collections.<ExpressionTree> emptyList()));
699: }
700: }
701:
702: ModifiersTree modifiers = make.Modifiers(mods, annotations);
703:
704: return modifiers;
705: }
706:
707: }
|