001: /*
002: * Hammurapi
003: * Automated Java code review system.
004: * Copyright (C) 2005 Johannes Bellert
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: CraftOfObjects@gmail.com
022:
023: * FIX 2: Added additional parameter types of add-methods
024: */
025:
026: package org.hammurapi.inspectors;
027:
028: import java.util.Hashtable;
029: import java.util.Iterator;
030: import java.util.List;
031:
032: import org.hammurapi.InspectorBase;
033:
034: import com.pavelvlasov.jsel.JselException;
035: import com.pavelvlasov.jsel.LanguageElement;
036: import com.pavelvlasov.jsel.OperationInfo;
037: import com.pavelvlasov.jsel.TypeSpecification;
038: import com.pavelvlasov.jsel.VariableDefinition;
039: import com.pavelvlasov.jsel.expressions.Dot;
040: import com.pavelvlasov.jsel.expressions.Ident;
041: import com.pavelvlasov.jsel.expressions.IndexOperation;
042: import com.pavelvlasov.jsel.expressions.IntegerConstant;
043: import com.pavelvlasov.jsel.expressions.MethodCall;
044: import com.pavelvlasov.jsel.expressions.NewObject;
045: import com.pavelvlasov.jsel.expressions.Plus;
046: import com.pavelvlasov.jsel.expressions.StringConstant;
047: import com.pavelvlasov.jsel.expressions.TypeCast;
048: import com.pavelvlasov.jsel.impl.AST;
049: import com.pavelvlasov.review.SourceMarker;
050:
051: public class HeterogenousCollection extends InspectorBase {
052:
053: private Hashtable currentCollectionInstanceVariables = new Hashtable();
054:
055: private Hashtable currentCollectionLocalVariables = new Hashtable();
056:
057: public void init() {
058: currentCollectionInstanceVariables = new Hashtable();
059: currentCollectionLocalVariables = new Hashtable();
060: }
061:
062: public void visit(com.pavelvlasov.jsel.Class type) {
063: init();
064: }
065:
066: public void visit(VariableDefinition element) {
067:
068: try {
069: TypeSpecification ts = element.getTypeSpecification();
070: if (element.getTypeSpecification().isKindOf(
071: "java.util.Collection")) {
072: // Collection: Vector implements List
073: // is this a instance or class variable?
074:
075: LanguageElement el = element.getParent();
076: if (el.getClass().equals(
077: com.pavelvlasov.jsel.impl.ClassImpl.class)) {
078: // instance variable
079: this .currentCollectionInstanceVariables.put(element
080: .getName(), new ColletionMethodAdd());
081: } else {
082: this .currentCollectionLocalVariables.put(element
083: .getName(), new ColletionMethodAdd());
084: }
085: }
086: } catch (Exception e) {
087: context.warn(element, e);
088: }
089:
090: }
091:
092: public boolean visit(MethodCall methodCall) throws JselException {
093:
094: if ("add".equals(methodCall.getMethodName())
095: || "addAll".equals(methodCall.getMethodName())) {
096: String key = fetchProviderVariable(((LanguageElement) methodCall)
097: .getAst());
098: determineHetergenousViolationFor(key, methodCall);
099: }
100: return true;
101: }
102:
103: private void determineHetergenousViolationFor(String key,
104: MethodCall methodCall) {
105: List parameterList = methodCall.getParameters();
106:
107: Iterator pit = parameterList.iterator();
108: while (pit.hasNext()) {
109: Object parameter = pit.next();
110: String typeDef = checkParameterTypeOf(parameter);
111: if ("int".equals(typeDef)) {
112: // do nothing
113: } else {
114: checkVariableRegistryFor(
115: this .currentCollectionLocalVariables, key,
116: typeDef, methodCall);
117: checkVariableRegistryFor(
118: this .currentCollectionInstanceVariables, key,
119: typeDef, methodCall);
120: }
121: }
122: }
123:
124: public void checkVariableRegistryFor(Hashtable ht, String key,
125: String typeDef, MethodCall methodCall) {
126:
127: SourceMarker srcM = (SourceMarker) methodCall;
128: LanguageElement parent = ((LanguageElement) methodCall)
129: .getParent();
130: ColletionMethodAdd value = (ColletionMethodAdd) ht.get(key);
131: if (value != null && value.isInitialize()) {
132: value.typeDef = typeDef;
133: value.callerMethodName = parent.getSignature();
134: value.lineNumber = srcM.getLine();
135: value.occurance++;
136:
137: ht.put(key, value);
138: } else if (value != null && value.occurance > 0) {
139: value.occurance++;
140: context.debug(srcM, parent.getSignature() + " >> "
141: + value.callerMethodName);
142: if ((3 > (srcM.getLine() - value.lineNumber))) {
143: context
144: .getSession()
145: .getContext("ER-215")
146: .reportViolation(
147: srcM,
148: "Collection "
149: + key
150: + " got "
151: + value.occurance
152: + " add-messages with parameter type "
153: + value.typeDef);
154:
155: }
156: }
157: if (value != null && !value.isInitialize()
158: && !typeDef.equals(value.typeDef)) {
159: // context.reportViolation(srcM);
160: context.getSession().getContext("ER-214").reportViolation(
161: srcM,
162: typeDef + " is different from " + value.typeDef);
163: } else {
164: // ignore .. probably wrong variable registry
165: }
166: }
167:
168: public String fetchProviderVariable(AST myAST) {
169: String errorRet = "<cant-determine-service-providing variable>";
170: if (myAST.getFirstToken() != null
171: && myAST.getFirstToken().getText() != null) {
172: return myAST.getFirstToken().getText();
173: } else {
174: // System.out.println(errorRet);
175: return errorRet;
176: }
177: }
178:
179: public String checkParameterTypeOf(Object parameter) {
180:
181: try {
182: if (parameter != null && parameter instanceof Ident) {
183: Ident p = (Ident) parameter;
184: return p.getTypeSpecification().getName();
185: } else if (parameter != null
186: && parameter instanceof StringConstant) {
187: return "java.lang.String";
188: } else if (parameter != null
189: && parameter instanceof MethodCall) {
190: MethodCall p = (MethodCall) parameter;
191: OperationInfo opi = p.getProvider();
192: return opi.getReturnType().getName();
193: } else if (parameter != null && parameter instanceof Dot) {
194: Dot p = (Dot) parameter;
195: return p.getTypeSpecification().getName();
196:
197: } else if (parameter != null
198: && parameter instanceof IndexOperation) {
199: IndexOperation p = (IndexOperation) parameter;
200: return p.getTypeSpecification().getName();
201:
202: } else if (parameter != null
203: && parameter instanceof TypeCast) {
204: TypeCast p = (TypeCast) parameter;
205: return p.getTypeSpecification().getName();
206:
207: } else if (parameter != null && parameter instanceof Plus) {
208: Plus plus = (Plus) parameter;
209: /*
210: Collection exprList = plus.getOperands();
211: Iterator it = exprList.iterator();
212: while ( it.hasNext()){
213: Object obj = (Object)it.next();
214: System.out.println( "++ " +obj.getClass().toString());
215: }
216: */
217: return "java.lang.String";
218:
219: } else if (parameter != null
220: && parameter instanceof NewObject) {
221: NewObject p = (NewObject) parameter;
222: return p.getTypeSpecification().getName();
223: } else if (parameter != null
224: && parameter instanceof IntegerConstant) {
225: return "int";
226: }
227: } catch (Exception e) {
228: context.warn((SourceMarker) parameter, e);
229: }
230: context.warn((SourceMarker) parameter,
231: "Problem to determine parameters type "
232: + parameter.toString());
233: return "<parameter-type-not-determined>";
234: }
235:
236: class ColletionMethodAdd {
237: public int occurance = 0;
238:
239: public String typeDef = "";
240:
241: public String callerMethodName = "";
242:
243: public int lineNumber = 0;
244:
245: public boolean isInitialize() {
246: return (occurance == 0) && "".equals(callerMethodName)
247: && (lineNumber == 0);
248: }
249:
250: }
251:
252: }
|