001: ////////////////////////////////////////////////////////////////////////////////
002: // checkstyle: Checks Java source code for adherence to a set of rules.
003: // Copyright (C) 2001-2007 Oliver Burn
004: //
005: // This library is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU Lesser General Public
007: // License as published by the Free Software Foundation; either
008: // version 2.1 of the License, or (at your option) any later version.
009: //
010: // This library is distributed in the hope that it will be useful,
011: // but WITHOUT ANY WARRANTY; without even the implied warranty of
012: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: // Lesser General Public License for more details.
014: //
015: // You should have received a copy of the GNU Lesser General Public
016: // License along with this library; if not, write to the Free Software
017: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: ////////////////////////////////////////////////////////////////////////////////
019: package com.puppycrawl.tools.checkstyle.checks.j2ee;
020:
021: import com.puppycrawl.tools.checkstyle.api.DetailAST;
022: import com.puppycrawl.tools.checkstyle.api.TokenTypes;
023:
024: /**
025: * J2EE check utility methods.
026: * @author Rick Giles
027: */
028: public class Utils {
029: /**
030: * Determines whether an AST node has a definition of a public method.
031: * @param aAST the node to check. Normally aAST is a CLASS_DEF.
032: * @param aName the name of the method.
033: * @return true if aAST has a definition of a public method with name
034: * aName.
035: */
036: public static boolean hasPublicMethod(DetailAST aAST, String aName) {
037: final DetailAST objBlock = aAST
038: .findFirstToken(TokenTypes.OBJBLOCK);
039: if (objBlock != null) {
040: DetailAST child = (DetailAST) objBlock.getFirstChild();
041: while (child != null) {
042: if ((child.getType() == TokenTypes.METHOD_DEF)
043: && Utils.isPublicMethod(child, aName)) {
044: return true;
045: }
046: child = (DetailAST) child.getNextSibling();
047: }
048: }
049: return false;
050: }
051:
052: /**
053: * Determines whether an AST node has a definition of a public method.
054: * @param aAST the node to check. Normally aAST is a CLASS_DEF.
055: * @param aName the name of the method.
056: * @param aIsVoid designates whether the method is void.
057: * @return true if aAST has a definition of a public method with name
058: * aName and that is void according to aIsVoid.
059: */
060: public static boolean hasPublicMethod(DetailAST aAST, String aName,
061: boolean aIsVoid) {
062: final DetailAST objBlock = aAST
063: .findFirstToken(TokenTypes.OBJBLOCK);
064: if (objBlock != null) {
065: DetailAST child = (DetailAST) objBlock.getFirstChild();
066: while (child != null) {
067: if ((child.getType() == TokenTypes.METHOD_DEF)
068: && Utils.isPublicMethod(child, aName, aIsVoid)) {
069: return true;
070: }
071: child = (DetailAST) child.getNextSibling();
072: }
073: }
074: return false;
075: }
076:
077: /**
078: * Determines whether an AST node has a definition of a public method.
079: * @param aAST the node to check. Normally aAST is a CLASS_DEF.
080: * @param aName the name of the method.
081: * @param aIsVoid designates whether the method is void.
082: * @param aParameterCount the number of method parameters.
083: * @return true if aAST has a definition of a public method with name
084: * aName and that is void according to aIsVoid.
085: */
086: public static boolean hasPublicMethod(DetailAST aAST, String aName,
087: boolean aIsVoid, int aParameterCount) {
088: final DetailAST objBlock = aAST
089: .findFirstToken(TokenTypes.OBJBLOCK);
090: if (objBlock != null) {
091: DetailAST child = (DetailAST) objBlock.getFirstChild();
092: while (child != null) {
093: if ((child.getType() == TokenTypes.METHOD_DEF)
094: && Utils.isPublicMethod(child, aName, aIsVoid,
095: aParameterCount)) {
096: return true;
097: }
098: child = (DetailAST) child.getNextSibling();
099: }
100: }
101: return false;
102: }
103:
104: /**
105: * Determines whether an AST defines a class with a public constructor
106: * with a given number of parameters.
107: * @param aAST the AST to check.
108: * @param aParameterCount the number of parameters
109: * @return true if aAST defines a class with a public constructor
110: * with aParameterCount parameters.
111: */
112: public static boolean hasPublicConstructor(DetailAST aAST,
113: int aParameterCount) {
114: final DetailAST objBlock = aAST
115: .findFirstToken(TokenTypes.OBJBLOCK);
116: if (objBlock == null) {
117: return false;
118: }
119: int constructorCount = 0;
120: DetailAST child = (DetailAST) objBlock.getFirstChild();
121: while (child != null) {
122: if (child.getType() == TokenTypes.CTOR_DEF) {
123: constructorCount++;
124: final DetailAST parameters = child
125: .findFirstToken(TokenTypes.PARAMETERS);
126: if (Utils.isPublic(child)
127: && (parameters.getChildCount() == aParameterCount)) {
128: return true;
129: }
130: }
131: child = (DetailAST) child.getNextSibling();
132: }
133: // implicit, no parameter constructor?
134: return ((constructorCount == 0) && (aParameterCount == 0));
135: }
136:
137: /**
138: * Determines whether an AST node is in the definition of a
139: * class that implements javax.ejb.EntityBean.
140: * @param aAST the AST to check.
141: * @return true if aAST is in the definition of a
142: * class that implements javax.ejb.SessionBean.
143: */
144: public static boolean implements EntityBean(DetailAST aAST) {
145: final DetailAST definer = getDefiner(aAST);
146: return ((definer != null) && Utils.hasImplements(definer,
147: "javax.ejb.EntityBean"));
148: }
149:
150: /**
151: * Determines whether an AST node is in the definition of a
152: * class that implements javax.ejb.SessionBean.
153: * @param aAST the AST to check.
154: * @return true if aAST is in the definition of a
155: * class that implements javax.ejb.SessionBean.
156: */
157: public static boolean implements SessionBean(DetailAST aAST) {
158: final DetailAST definer = getDefiner(aAST);
159: return ((definer != null) && Utils.hasImplements(definer,
160: "javax.ejb.SessionBean"));
161: }
162:
163: /**
164: * Determines whether an AST node is in the definition of an
165: * EJB class.
166: * @param aAST the AST to check.
167: * @return true if aAST is in the definition of a
168: * an EJB class.
169: */
170: public static boolean isInEJB(DetailAST aAST) {
171: final DetailAST definer = getDefiner(aAST);
172: return ((definer != null) && (Utils.hasImplements(definer,
173: "javax.ejb.SessionBean")
174: || Utils.hasImplements(definer, "javax.ejb.EntityBean") || (Utils
175: .hasImplements(definer, "javax.ejb.MessageDrivenBean") && Utils
176: .hasImplements(definer, "javax.jms.MessageListener"))));
177: }
178:
179: /**
180: * Finds the DetailAST for the class definition of an AST.
181: * @param aAST the AST for the search.
182: * @return the class definition AST for aAST.
183: */
184: private static DetailAST getDefiner(DetailAST aAST) {
185: DetailAST definer = aAST.getParent();
186: while ((definer != null)) {
187: if (definer.getType() == TokenTypes.CLASS_DEF) {
188: break;
189: }
190: definer = definer.getParent();
191: }
192: return definer;
193: }
194:
195: /**
196: * Determines whether an AST defines an abstract element.
197: * @param aAST the AST to check.
198: * @return true if aAST defines an abstract element.
199: */
200: public static boolean isAbstract(DetailAST aAST) {
201: final DetailAST mods = aAST
202: .findFirstToken(TokenTypes.MODIFIERS);
203: return ((mods != null) && mods
204: .branchContains(TokenTypes.ABSTRACT));
205: }
206:
207: /**
208: * Determines whether an AST defines a final element.
209: * @param aAST the AST to check.
210: * @return true if aAST defines a final element.
211: */
212: public static boolean isFinal(DetailAST aAST) {
213: final DetailAST mods = aAST
214: .findFirstToken(TokenTypes.MODIFIERS);
215: return ((mods != null) && mods.branchContains(TokenTypes.FINAL));
216: }
217:
218: /**
219: * Determines whether an AST defines a public element.
220: * @param aAST the AST to check.
221: * @return true if aAST defines a public element.
222: */
223: public static boolean isPublic(DetailAST aAST) {
224: final DetailAST mods = aAST
225: .findFirstToken(TokenTypes.MODIFIERS);
226: return ((mods != null) && mods
227: .branchContains(TokenTypes.LITERAL_PUBLIC));
228: }
229:
230: /**
231: * Determines whether an AST defines a static element.
232: * @param aAST the AST to check.
233: * @return true if aAST defines a static element.
234: */
235: public static boolean isStatic(DetailAST aAST) {
236: final DetailAST mods = aAST
237: .findFirstToken(TokenTypes.MODIFIERS);
238: return ((mods != null) && mods
239: .branchContains(TokenTypes.LITERAL_STATIC));
240: }
241:
242: /**
243: * Determines whether an AST defines a void method.
244: * @param aAST the AST to check.
245: * @return true if aAST defines a void method.
246: */
247: public static boolean isVoid(DetailAST aAST) {
248: final DetailAST type = aAST.findFirstToken(TokenTypes.TYPE);
249: return ((type != null) && type
250: .branchContains(TokenTypes.LITERAL_VOID));
251: }
252:
253: /**
254: * Determines whether an AST node declares an implementation of an
255: * interface.
256: * @param aAST the AST to check.
257: * @param aInterface the interface to check.
258: * @return if the class defined by aAST implements declares an
259: * implementation of aInterface.
260: */
261: public static boolean hasImplements(DetailAST aAST,
262: String aInterface) {
263: final String shortName = com.puppycrawl.tools.checkstyle.api.Utils
264: .baseClassname(aInterface);
265: final DetailAST implements AST = aAST
266: .findFirstToken(TokenTypes.IMPLEMENTS_CLAUSE);
267: if (implements AST != null) {
268: DetailAST child = (DetailAST) implements AST.getFirstChild();
269: while (child != null) {
270: if ((child.getType() == TokenTypes.IDENT)
271: || (child.getType() == TokenTypes.DOT)) {
272: final String name = Utils
273: .constructDottedName(child);
274: if (name.equals(aInterface)
275: || name.equals(shortName)) {
276: return true;
277: }
278: }
279: child = (DetailAST) child.getNextSibling();
280: }
281: }
282: return false;
283: }
284:
285: /**
286: * Determines whether an AST node declares an extension of a class or
287: * interface.
288: * @param aAST the AST to check.
289: * @param aClassOrInterface the class or interface to check.
290: * @return if the class defined by aAST implements declares an
291: * extension of aClassOrInterface.
292: */
293: public static boolean hasExtends(DetailAST aAST,
294: String aClassOrInterface) {
295: final String shortName = com.puppycrawl.tools.checkstyle.api.Utils
296: .baseClassname(aClassOrInterface);
297: final DetailAST extendsAST = aAST
298: .findFirstToken(TokenTypes.EXTENDS_CLAUSE);
299: if (extendsAST != null) {
300: DetailAST child = (DetailAST) extendsAST.getFirstChild();
301: while (child != null) {
302: if ((child.getType() == TokenTypes.IDENT)
303: || (child.getType() == TokenTypes.DOT)) {
304: final String name = Utils
305: .constructDottedName(child);
306: if (name.equals(aClassOrInterface)
307: || name.equals(shortName)) {
308: return true;
309: }
310: }
311: child = (DetailAST) child.getNextSibling();
312: }
313: }
314: return false;
315: }
316:
317: /**
318: * Determines whether an AST node declares a throw of an Exception.
319: * @param aAST the AST to check.
320: * @param aException the name of the Exception to check.
321: * @return if the class defined by aAST implements declares a throw
322: * of aException.
323: */
324: public static boolean hasThrows(DetailAST aAST, String aException) {
325: final String shortName = com.puppycrawl.tools.checkstyle.api.Utils
326: .baseClassname(aException);
327: final DetailAST throwsAST = aAST
328: .findFirstToken(TokenTypes.LITERAL_THROWS);
329: if (throwsAST != null) {
330: DetailAST child = (DetailAST) throwsAST.getFirstChild();
331: while (child != null) {
332: if ((child.getType() == TokenTypes.IDENT)
333: || (child.getType() == TokenTypes.DOT)) {
334: final String name = Utils
335: .constructDottedName(child);
336: if (name.equals(aException)
337: || name.equals(shortName)) {
338: return true;
339: }
340: }
341: child = (DetailAST) child.getNextSibling();
342: }
343: }
344: return false;
345: }
346:
347: /**
348: * Determines whether an AST node defines a public method.
349: * @param aAST the node to check. Normally aAST is a METHOD_DEF.
350: * @param aName the name of the method.
351: * @param aIsVoid designates whether the method is void.
352: * @param aParameterCount the number of method parameters.
353: * @return true if aAST is the definition of a public method with name
354: * aName and that is void according to aIsVoid.
355: */
356: public static boolean isPublicMethod(DetailAST aAST, String aName,
357: boolean aIsVoid, int aParameterCount) {
358: final DetailAST nameNode = aAST
359: .findFirstToken(TokenTypes.IDENT);
360: if (nameNode != null) {
361: final String name = nameNode.getText();
362: if (name.equals(aName) && isPublic(aAST)
363: && (isVoid(aAST) == aIsVoid)) {
364: final DetailAST parameters = aAST
365: .findFirstToken(TokenTypes.PARAMETERS);
366: if (parameters.getChildCount() == aParameterCount) {
367: return true;
368: }
369: }
370: }
371: return false;
372: }
373:
374: /**
375: * Determines whether an AST node defines a public method.
376: * @param aAST the node to check. Normally aAST is a METHOD_DEF.
377: * @param aName the name of the method.
378: * @param aIsVoid designates whether the method is void.
379: * @return true if aAST is the definition of a public method with name
380: * aName and that is void according to aIsVoid.
381: */
382: public static boolean isPublicMethod(DetailAST aAST, String aName,
383: boolean aIsVoid) {
384: final DetailAST nameNode = aAST
385: .findFirstToken(TokenTypes.IDENT);
386: if (nameNode != null) {
387: final String name = nameNode.getText();
388: if (name.equals(aName) && isPublic(aAST)
389: && (isVoid(aAST) == aIsVoid)) {
390: return true;
391: }
392: }
393: return false;
394: }
395:
396: /**
397: * Determines whether an AST node defines a public method.
398: * @param aAST the node to check. Normally aAST is a METHOD_DEF.
399: * @param aName the name of the method.
400: * @return true if aAST is the definition of a public method with name
401: * aName and that is void according to aIsVoid.
402: */
403: public static boolean isPublicMethod(DetailAST aAST, String aName) {
404: final DetailAST nameNode = aAST
405: .findFirstToken(TokenTypes.IDENT);
406: if (nameNode != null) {
407: final String name = nameNode.getText();
408: if (name.equals(aName) && isPublic(aAST)) {
409: return true;
410: }
411: }
412: return false;
413: }
414:
415: /**
416: * Builds the dotted name String representation of the object contained
417: * within an AST.
418: *
419: * @param aAST the AST containing the entire hierarcy of the object
420: * @return the dotted name String representation of the object contained
421: * within aAST.
422: */
423: public static String constructDottedName(DetailAST aAST) {
424: String result;
425:
426: if (aAST.getType() == TokenTypes.DOT) {
427: final DetailAST left = (DetailAST) aAST.getFirstChild();
428: final DetailAST right = (DetailAST) left.getNextSibling();
429:
430: result = constructDottedName(left) + "."
431: + constructDottedName(right);
432: } else {
433: result = aAST.getText();
434: }
435:
436: return result;
437: }
438:
439: /**
440: * Tests whether two method definition ASTs have the same parameter lists
441: * according to type.
442: * @param aMethodAST1 the first method AST to test.
443: * @param aMethodAST2 the second method AST to test.
444: * @return true if aMethodAST1 and aMethodAST2 have the same
445: * parameter lists.
446: */
447: public static boolean sameParameters(DetailAST aMethodAST1,
448: DetailAST aMethodAST2) {
449: final DetailAST params1 = aMethodAST1
450: .findFirstToken(TokenTypes.PARAMETERS);
451: final DetailAST params2 = aMethodAST2
452: .findFirstToken(TokenTypes.PARAMETERS);
453: if (params1.getChildCount() != params2.getChildCount()) {
454: return false;
455: }
456: DetailAST param1 = (DetailAST) params1.getFirstChild();
457: DetailAST param2 = (DetailAST) params2.getFirstChild();
458: while (param1 != null) {
459: if ((param1.getType() == TokenTypes.PARAMETER_DEF)
460: && (param2.getType() == TokenTypes.PARAMETER_DEF)) {
461: final DetailAST type1 = param1
462: .findFirstToken(TokenTypes.TYPE);
463: final DetailAST type2 = param2
464: .findFirstToken(TokenTypes.TYPE);
465: if (!equalTypes(type1, type2)) {
466: return false;
467: }
468: }
469: param1 = (DetailAST) param1.getNextSibling();
470: param2 = (DetailAST) param2.getNextSibling();
471: }
472: return true;
473: }
474:
475: /**
476: * Tests whether two type AST nodes have the same type.
477: * @param aTypeAST1 the first type AST to test.
478: * @param aTypeAST2 the second type AST to test.
479: * @return true if aTypeAST1 and aTypeAST2 have the same type.
480: */
481: public static boolean equalTypes(DetailAST aTypeAST1,
482: DetailAST aTypeAST2) {
483: final DetailAST child1 = (DetailAST) aTypeAST1.getFirstChild();
484: final DetailAST child2 = (DetailAST) aTypeAST2.getFirstChild();
485: final String name1 = Utils.constructDottedName(child1);
486: final String name2 = Utils.constructDottedName(child2);
487: return name1.equals(name2);
488: }
489: }
|