001: /*
002: * Hammurapi
003: * Automated Java code review system.
004: * Copyright (C) 2004 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.org
021: * e-Mail: support@hammurapi.biz
022: */
023: package org.hammurapi.inspectors;
024:
025: import org.hammurapi.InspectorBase;
026: import org.hammurapi.HammurapiException;
027:
028: import com.pavelvlasov.jsel.JselException;
029: import com.pavelvlasov.jsel.Method;
030: import com.pavelvlasov.jsel.TypeSpecification;
031: import com.pavelvlasov.jsel.VariableDefinition;
032: import com.pavelvlasov.jsel.expressions.NewObject;
033: import com.pavelvlasov.jsel.statements.CompoundStatement;
034: import com.pavelvlasov.jsel.statements.Statement;
035: import com.pavelvlasov.util.AccumulatingVisitorExceptionSink;
036: import com.pavelvlasov.util.DispatchingVisitor;
037:
038: /**
039: * ER-089
040: * Avoid using constructors in the 'clone ()' method
041: * @author Janos Czako
042: * @version $Revision: 1.4 $
043: */
044: public class ConstructorsInCloneRule extends InspectorBase {
045:
046: /**
047: * The chained visitor class which searches after calling new on the
048: * visited class.
049: */
050: public static class NewSnooper {
051:
052: /**
053: * The name of the class (not full quailified), the reviewed clone()
054: * method belongs to.
055: */
056: private String classNameToReview;
057:
058: /**
059: * Constructor which takes the name of the visited class.
060: * @param theClassName the name of the class to be reviewed.
061: */
062: NewSnooper(String theClassName) {
063: classNameToReview = theClassName;
064: }
065:
066: /**
067: * The list of the new calls found.
068: */
069: java.util.List returns = new java.util.ArrayList();
070:
071: /**
072: * Reviews the calls to new, if they are referred to the class to be
073: * reviewed.
074: *
075: * @param newCall the calls to new.
076: */
077: public void visit(NewObject newCall) throws JselException {
078: TypeSpecification ts = newCall.getTypeSpecification();
079: if (classNameToReview.equals(ts.getType().getName())) {
080: returns.add(newCall);
081: }
082: }
083: }
084:
085: /**
086: * The name of the "clone" method.
087: */
088: private static final String CLONE_NAME = "clone";
089:
090: /**
091: * The error text for exceptions in the chained visitor.
092: */
093: private static final String CHAINED_ERRS = "There have been exceptions (see above)";
094:
095: /**
096: * Reviews the method definitions, if they are "clone()" and call
097: * constructor.
098: *
099: * @param element the method definition to be reviewed.
100: * @throws HammurapiException In case of any exception in the chained visitor.
101: */
102: public void visit(Method element) throws HammurapiException {
103: if (CLONE_NAME.equals(element.getName())
104: && element.getParameters().isEmpty()) {
105: CompoundStatement compoundStatement = element
106: .getCompoundStatement();
107: if (compoundStatement != null) {
108: java.util.Iterator statements = compoundStatement
109: .getStatements().iterator();
110:
111: while (statements.hasNext()) {
112: Statement statement = (Statement) statements.next();
113: if (statement instanceof VariableDefinition) {
114: AccumulatingVisitorExceptionSink es = new AccumulatingVisitorExceptionSink();
115: NewSnooper rs = new NewSnooper(element
116: .getEnclosingType().getFcn());
117: element.accept(new DispatchingVisitor(rs, es));
118:
119: if (!rs.returns.isEmpty()) {
120: context.reportViolation(element);
121: }
122: if (!es.getExceptions().isEmpty()) {
123: es.dump();
124: throw new HammurapiException(CHAINED_ERRS);
125: }
126: }
127: }
128: }
129: }
130: }
131: }
|