KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > detect > CloneIdiom


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2003-2005, University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs.detect;
21
22 import org.apache.bcel.Repository;
23 import org.apache.bcel.classfile.Code;
24 import org.apache.bcel.classfile.ConstantNameAndType;
25 import org.apache.bcel.classfile.JavaClass;
26 import org.apache.bcel.classfile.Method;
27
28 import edu.umd.cs.findbugs.BugInstance;
29 import edu.umd.cs.findbugs.BugReporter;
30 import edu.umd.cs.findbugs.Detector;
31 import edu.umd.cs.findbugs.MethodAnnotation;
32 import edu.umd.cs.findbugs.StatelessDetector;
33 import edu.umd.cs.findbugs.ba.ClassContext;
34 import edu.umd.cs.findbugs.ba.PruneInfeasibleExceptionEdges;
35 import edu.umd.cs.findbugs.ba.PruneUnconditionalExceptionThrowerEdges;
36 import edu.umd.cs.findbugs.ba.XFactory;
37 import edu.umd.cs.findbugs.visitclass.DismantleBytecode;
38
39 public class CloneIdiom extends DismantleBytecode implements Detector, StatelessDetector {
40
41     boolean /*isCloneable,*/ hasCloneMethod;
42     MethodAnnotation cloneMethodAnnotation;
43     boolean referencesCloneMethod;
44     boolean invokesSuperClone;
45     boolean isFinal;
46     boolean cloneOnlyThrowsException;
47
48     boolean check;
49     //boolean throwsExceptions;
50
boolean implementsCloneableDirectly;
51     private BugReporter bugReporter;
52
53     public CloneIdiom(BugReporter bugReporter) {
54         this.bugReporter = bugReporter;
55     }
56     
57     
58
59     public void visitClassContext(ClassContext classContext) {
60         classContext.getJavaClass().accept(this);
61     }
62
63
64     public void report() {
65     }
66
67     @Override JavaDoc
68          public void visit(Code obj) {
69         if (getMethodName().equals("clone") &&
70                 getMethodSig().startsWith("()"))
71             super.visit(obj);
72     }
73
74     @Override JavaDoc
75          public void sawOpcode(int seen) {
76         if (seen == INVOKESPECIAL
77                 && getNameConstantOperand().equals("clone")
78                 && getSigConstantOperand().startsWith("()")) {
79             /*
80             System.out.println("Saw call to " + nameConstant
81                         + ":" + sigConstant
82                         + " in " + betterMethodName);
83             */

84             invokesSuperClone = true;
85         }
86     }
87
88     @Override JavaDoc
89          public void visit(JavaClass obj) {
90         implementsCloneableDirectly = false;
91         invokesSuperClone = false;
92         cloneOnlyThrowsException = false;
93         //isCloneable = false;
94
check = false;
95         isFinal = obj.isFinal();
96         if (obj.isInterface()) return;
97         if (obj.isAbstract()) return;
98         // Does this class directly implement Cloneable?
99
String JavaDoc[] interface_names = obj.getInterfaceNames();
100         for (String JavaDoc interface_name : interface_names) {
101             if (interface_name.equals("java.lang.Cloneable")) {
102                 implementsCloneableDirectly = true;
103                 //isCloneable = true;
104
break;
105             }
106         }
107
108         try {
109             //isCloneable = Repository.implementationOf(obj, "java.lang.Cloneable");
110
JavaClass superClass = obj.getSuperClass();
111             if (superClass != null && Repository.implementationOf(superClass, "java.lang.Cloneable"))
112                 implementsCloneableDirectly = false;
113         } catch (ClassNotFoundException JavaDoc e) {
114             // ignore
115
}
116         hasCloneMethod = false;
117         referencesCloneMethod = false;
118         check = true;
119         super.visit(obj);
120     }
121
122     @Override JavaDoc
123          public void visitAfter(JavaClass obj) {
124         if (!check) return;
125         if (cloneOnlyThrowsException) return;
126         if (implementsCloneableDirectly && !hasCloneMethod) {
127             if (!referencesCloneMethod)
128                 bugReporter.reportBug(new BugInstance(this, "CN_IDIOM", NORMAL_PRIORITY)
129                         .addClass(this));
130         }
131
132         if (hasCloneMethod && !invokesSuperClone && !isFinal && obj.isPublic()) {
133             bugReporter.reportBug(new BugInstance(this, "CN_IDIOM_NO_SUPER_CALL", (obj.isPublic() || obj.isProtected()) ?
134                     NORMAL_PRIORITY : LOW_PRIORITY)
135                     .addClass(this)
136                     .addMethod(cloneMethodAnnotation));
137         }
138
139         /*
140         if (!isCloneable && hasCloneMethod) {
141             if (throwsExceptions)
142             System.out.println("has public clone method that throws exceptions and class is not Cloneable: " + betterClassName) ;
143             else System.out.println("has public clone method but is not Cloneable: " + betterClassName) ;
144             }
145         */

146     }
147
148     @Override JavaDoc
149          public void visit(ConstantNameAndType obj) {
150         String JavaDoc methodName = obj.getName(getConstantPool());
151         String JavaDoc methodSig = obj.getSignature(getConstantPool());
152         if (!methodName.equals("clone")) return;
153         if (!methodSig.startsWith("()")) return;
154         referencesCloneMethod = true;
155     }
156
157     @Override JavaDoc
158          public void visit(Method obj) {
159         if (obj.isAbstract()) return;
160         if (!obj.isPublic()) return;
161         if (!getMethodName().equals("clone")) return;
162         if (!getMethodSig().startsWith("()")) return;
163         hasCloneMethod = true;
164         cloneMethodAnnotation = MethodAnnotation.fromVisitedMethod(this);
165         cloneOnlyThrowsException =
166             PruneUnconditionalExceptionThrowerEdges.doesMethodUnconditionallyThrowException(XFactory.createXMethod(this), getThisClass(), obj);
167         //ExceptionTable tbl = obj.getExceptionTable();
168
//throwsExceptions = tbl != null && tbl.getNumberOfExceptions() > 0;
169
}
170 }
171
Popular Tags