Source Code Cross Referenced for ConstructorCallsOverridableMethod.java in  » Code-Analyzer » pmd-4.2rc1 » net » sourceforge » pmd » rules » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Code Analyzer » pmd 4.2rc1 » net.sourceforge.pmd.rules 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /**
002:         * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003:         */package net.sourceforge.pmd.rules;
004:
005:        import net.sourceforge.pmd.AbstractRule;
006:        import net.sourceforge.pmd.ast.ASTArguments;
007:        import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
008:        import net.sourceforge.pmd.ast.ASTCompilationUnit;
009:        import net.sourceforge.pmd.ast.ASTConstructorDeclaration;
010:        import net.sourceforge.pmd.ast.ASTEnumDeclaration;
011:        import net.sourceforge.pmd.ast.ASTExplicitConstructorInvocation;
012:        import net.sourceforge.pmd.ast.ASTLiteral;
013:        import net.sourceforge.pmd.ast.ASTMethodDeclaration;
014:        import net.sourceforge.pmd.ast.ASTMethodDeclarator;
015:        import net.sourceforge.pmd.ast.ASTName;
016:        import net.sourceforge.pmd.ast.ASTPrimaryExpression;
017:        import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
018:        import net.sourceforge.pmd.ast.ASTPrimarySuffix;
019:        import net.sourceforge.pmd.ast.AccessNode;
020:        import net.sourceforge.pmd.ast.Node;
021:        import net.sourceforge.pmd.ast.SimpleNode;
022:
023:        import java.util.ArrayList;
024:        import java.util.Collections;
025:        import java.util.Comparator;
026:        import java.util.Iterator;
027:        import java.util.List;
028:        import java.util.Map;
029:        import java.util.Set;
030:        import java.util.TreeMap;
031:
032:        /**
033:         * Searches through all methods and constructors called from constructors.  It
034:         * marks as dangerous any call to overridable methods from non-private
035:         * constructors.  It marks as dangerous any calls to dangerous private constructors
036:         * from non-private constructors.
037:         *
038:         * @author CL Gilbert (dnoyeb@users.sourceforge.net)
039:         * @todo match parameter types.  Aggressively strips off any package names.  Normal
040:         * compares the names as is.
041:         * @todo What about interface declarations which can have internal classes
042:         */
043:        public final class ConstructorCallsOverridableMethod extends
044:                AbstractRule {
045:            /**
046:             * 2: method();
047:             * ASTPrimaryPrefix
048:             * ASTName			image = "method"
049:             * ASTPrimarySuffix
050:             * *ASTArguments
051:             * 3: a.method();
052:             * ASTPrimaryPrefix ->
053:             * ASTName			image = "a.method" ???
054:             * ASTPrimarySuffix -> ()
055:             * ASTArguments
056:             * 3: this.method();
057:             * ASTPrimaryPrefix -> this image=null
058:             * ASTPrimarySuffix -> method
059:             * ASTPrimarySuffix -> ()
060:             * ASTArguments
061:             * <p/>
062:             * super.method();
063:             * ASTPrimaryPrefix -> image = "method"
064:             * ASTPrimarySuffix -> image = null
065:             * ASTArguments ->
066:             * <p/>
067:             * super.a.method();
068:             * ASTPrimaryPrefix -> image = "a"
069:             * ASTPrimarySuffix -> image = "method"
070:             * ASTPrimarySuffix -> image = null
071:             * ASTArguments ->
072:             * <p/>
073:             * <p/>
074:             * 4: this.a.method();
075:             * ASTPrimaryPrefix -> image = null
076:             * ASTPrimarySuffix -> image = "a"
077:             * ASTPrimarySuffix -> image = "method"
078:             * ASTPrimarySuffix ->
079:             * ASTArguments
080:             * <p/>
081:             * 4: ClassName.this.method();
082:             * ASTPrimaryPrefix
083:             * ASTName	image = "ClassName"
084:             * ASTPrimarySuffix -> this image=null
085:             * ASTPrimarySuffix -> image = "method"
086:             * ASTPrimarySuffix -> ()
087:             * ASTArguments
088:             * 5: ClassName.this.a.method();
089:             * ASTPrimaryPrefix
090:             * ASTName image = "ClassName"
091:             * ASTPrimarySuffix -> this image=null
092:             * ASTPrimarySuffix -> image="a"
093:             * ASTPrimarySuffix -> image="method"
094:             * ASTPrimarySuffix -> ()
095:             * ASTArguments
096:             * 5: Package.ClassName.this.method();
097:             * ASTPrimaryPrefix
098:             * ASTName image ="Package.ClassName"
099:             * ASTPrimarySuffix -> this image=null
100:             * ASTPrimarySuffix -> image="method"
101:             * ASTPrimarySuffix -> ()
102:             * ASTArguments
103:             * 6: Package.ClassName.this.a.method();
104:             * ASTPrimaryPrefix
105:             * ASTName image ="Package.ClassName"
106:             * ASTPrimarySuffix -> this image=null
107:             * ASTPrimarySuffix -> a
108:             * ASTPrimarySuffix -> method
109:             * ASTPrimarySuffix -> ()
110:             * ASTArguments
111:             * 5: OuterClass.InnerClass.this.method();
112:             * ASTPrimaryPrefix
113:             * ASTName image = "OuterClass.InnerClass"
114:             * ASTPrimarySuffix -> this image=null
115:             * ASTPrimarySuffix -> method
116:             * ASTPrimarySuffix -> ()
117:             * ASTArguments
118:             * 6: OuterClass.InnerClass.this.a.method();
119:             * ASTPrimaryPrefix
120:             * ASTName image = "OuterClass.InnerClass"
121:             * ASTPrimarySuffix -> this image=null
122:             * ASTPrimarySuffix -> a
123:             * ASTPrimarySuffix -> method
124:             * ASTPrimarySuffix -> ()
125:             * ASTArguments
126:             * <p/>
127:             * OuterClass.InnerClass.this.a.method().method().method();
128:             * ASTPrimaryPrefix
129:             * ASTName image = "OuterClass.InnerClass"
130:             * ASTPrimarySuffix -> this		image=null
131:             * ASTPrimarySuffix -> a			image='a'
132:             * ASTPrimarySuffix -> method		image='method'
133:             * ASTPrimarySuffix -> ()			image=null
134:             * ASTArguments
135:             * ASTPrimarySuffix -> method		image='method'
136:             * ASTPrimarySuffix -> ()			image=null
137:             * ASTArguments
138:             * ASTPrimarySuffix -> method		image='method'
139:             * ASTPrimarySuffix -> ()			image=null
140:             * ASTArguments
141:             * <p/>
142:             * 3..n:	Class.InnerClass[0].InnerClass[n].this.method();
143:             * ASTPrimaryPrefix
144:             * ASTName image = "Class[0]..InnerClass[n]"
145:             * ASTPrimarySuffix -> image=null
146:             * ASTPrimarySuffix -> method
147:             * ASTPrimarySuffix -> ()
148:             * ASTArguments
149:             * <p/>
150:             * super.aMethod();
151:             * ASTPrimaryPrefix -> aMethod
152:             * ASTPrimarySuffix -> ()
153:             * <p/>
154:             * Evaluate right to left
155:             */
156:            private static class MethodInvocation {
157:                private String m_Name;
158:                private ASTPrimaryExpression m_Ape;
159:                private List<String> m_ReferenceNames;
160:                private List<String> m_QualifierNames;
161:                private int m_ArgumentSize;
162:                private boolean m_Super;
163:
164:                private MethodInvocation(ASTPrimaryExpression ape,
165:                        List<String> qualifierNames,
166:                        List<String> referenceNames, String name,
167:                        int argumentSize, boolean super Call) {
168:                    m_Ape = ape;
169:                    m_QualifierNames = qualifierNames;
170:                    m_ReferenceNames = referenceNames;
171:                    m_Name = name;
172:                    m_ArgumentSize = argumentSize;
173:                    m_Super = super Call;
174:                }
175:
176:                public boolean isSuper() {
177:                    return m_Super;
178:                }
179:
180:                public String getName() {
181:                    return m_Name;
182:                }
183:
184:                public int getArgumentCount() {
185:                    return m_ArgumentSize;
186:                }
187:
188:                public List<String> getReferenceNames() {
189:                    return m_ReferenceNames;//new ArrayList(variableNames);
190:                }
191:
192:                public List<String> getQualifierNames() {
193:                    return m_QualifierNames;
194:                }
195:
196:                public ASTPrimaryExpression getASTPrimaryExpression() {
197:                    return m_Ape;
198:                }
199:
200:                public static MethodInvocation getMethod(
201:                        ASTPrimaryExpression node) {
202:                    MethodInvocation meth = null;
203:                    int i = node.jjtGetNumChildren();
204:                    if (i > 1) {//should always be at least 2, probably can eliminate this check
205:                        //start at end which is guaranteed, work backwards
206:                        Node lastNode = node.jjtGetChild(i - 1);
207:                        if ((lastNode.jjtGetNumChildren() == 1)
208:                                && (lastNode.jjtGetChild(0) instanceof  ASTArguments)) { //could be ASTExpression for instance 'a[4] = 5';
209:                            //start putting method together
210:                            //					System.out.println("Putting method together now");
211:                            List<String> varNames = new ArrayList<String>();
212:                            List<String> packagesAndClasses = new ArrayList<String>(); //look in JLS for better name here;
213:                            String methodName = null;
214:                            ASTArguments args = (ASTArguments) lastNode
215:                                    .jjtGetChild(0);
216:                            int numOfArguments = args.getArgumentCount();
217:                            boolean super First = false;
218:                            int this Index = -1;
219:
220:                            FIND_SUPER_OR_THIS: {
221:                                //search all nodes except last for 'this' or 'super'.  will be at: (node 0 | node 1 | nowhere)
222:                                //this is an ASTPrimarySuffix with a null image and does not have child (which will be of type ASTArguments)
223:                                //this is an ASTPrimaryPrefix with a null image and an ASTName that has a null image
224:                                //super is an ASTPrimarySuffix with a null image and does not have child (which will be of type ASTArguments)
225:                                //super is an ASTPrimaryPrefix with a non-null image
226:                                for (int x = 0; x < i - 1; x++) {
227:                                    Node child = node.jjtGetChild(x);
228:                                    if (child instanceof  ASTPrimarySuffix) { //check suffix type match
229:                                        ASTPrimarySuffix child2 = (ASTPrimarySuffix) child;
230:                                        //								String name = getNameFromSuffix((ASTPrimarySuffix)child);
231:                                        //								System.out.println("found name suffix of : " + name);
232:                                        if (child2.getImage() == null
233:                                                && child2.jjtGetNumChildren() == 0) {
234:                                            this Index = x;
235:                                            break;
236:                                        }
237:                                        //could be super, could be this.  currently we cant tell difference so we miss super when
238:                                        //XYZ.ClassName.super.method();
239:                                        //still works though.
240:                                    } else if (child instanceof  ASTPrimaryPrefix) { //check prefix type match
241:                                        ASTPrimaryPrefix child2 = (ASTPrimaryPrefix) child;
242:                                        if (getNameFromPrefix(child2) == null) {
243:                                            if (child2.getImage() == null) {
244:                                                this Index = x;
245:                                                break;
246:                                            } else {//happens when super is used [super.method(): image = 'method']
247:                                                super First = true;
248:                                                this Index = x;
249:                                                //the true super is at an unusable index because super.method() has only 2 nodes [method=0,()=1]
250:                                                //as opposed to the 3 you might expect and which this.method() actually has. [this=0,method=1.()=2]
251:                                                break;
252:                                            }
253:                                        }
254:                                    }
255:                                    //							else{
256:                                    //								System.err.println("Bad Format error"); //throw exception, quit evaluating this compilation node
257:                                    //							}
258:                                }
259:                            }
260:
261:                            if (this Index != -1) {
262:                                //						System.out.println("Found this or super: " + thisIndex);
263:                                //Hack that must be removed if and when the patters of super.method() begins to logically match the rest of the patterns !!!
264:                                if (super First) { //this is when super is the first node of statement.  no qualifiers, all variables or method
265:                                    //							System.out.println("super first");
266:                                    FIRSTNODE: {
267:                                        ASTPrimaryPrefix child = (ASTPrimaryPrefix) node
268:                                                .jjtGetChild(0);
269:                                        String name = child.getImage();//special case
270:                                        if (i == 2) { //last named node = method name
271:                                            methodName = name;
272:                                        } else { //not the last named node so its only var name
273:                                            varNames.add(name);
274:                                        }
275:                                    }
276:                                    OTHERNODES: { //variables
277:                                        for (int x = 1; x < i - 1; x++) {
278:                                            Node child = node.jjtGetChild(x);
279:                                            ASTPrimarySuffix ps = (ASTPrimarySuffix) child;
280:                                            if (!ps.isArguments()) {
281:                                                String name = ((ASTPrimarySuffix) child)
282:                                                        .getImage();
283:                                                if (x == i - 2) {//last node
284:                                                    methodName = name;
285:                                                } else {//not the last named node so its only var name
286:                                                    varNames.add(name);
287:                                                }
288:                                            }
289:                                        }
290:                                    }
291:                                } else {//not super call
292:                                    FIRSTNODE: {
293:                                        if (this Index == 1) {//qualifiers in node 0
294:                                            ASTPrimaryPrefix child = (ASTPrimaryPrefix) node
295:                                                    .jjtGetChild(0);
296:                                            String toParse = getNameFromPrefix(child);
297:                                            //									System.out.println("parsing for class/package names in : " + toParse);
298:                                            java.util.StringTokenizer st = new java.util.StringTokenizer(
299:                                                    toParse, ".");
300:                                            while (st.hasMoreTokens()) {
301:                                                packagesAndClasses.add(st
302:                                                        .nextToken());
303:                                            }
304:                                        }
305:                                    }
306:                                    OTHERNODES: { //other methods called in this statement are grabbed here
307:                                        //this is at 0, then no Qualifiers
308:                                        //this is at 1, the node 0 contains qualifiers
309:                                        for (int x = this Index + 1; x < i - 1; x++) {//everything after this is var name or method name
310:                                            ASTPrimarySuffix child = (ASTPrimarySuffix) node
311:                                                    .jjtGetChild(x);
312:                                            if (!child.isArguments()) { //skip the () of method calls
313:                                                String name = child.getImage();
314:                                                //										System.out.println("Found suffix: " + suffixName);
315:                                                if (x == i - 2) {
316:                                                    methodName = name;
317:                                                } else {
318:                                                    varNames.add(name);
319:                                                }
320:                                            }
321:                                        }
322:                                    }
323:                                }
324:                            } else { //if no this or super found, everything is method name or variable
325:                                //System.out.println("no this found:");
326:                                FIRSTNODE: { //variable names are in the prefix + the first method call [a.b.c.x()]
327:                                    ASTPrimaryPrefix child = (ASTPrimaryPrefix) node
328:                                            .jjtGetChild(0);
329:                                    String toParse = getNameFromPrefix(child);
330:                                    //							System.out.println("parsing for var names in : " + toParse);
331:                                    java.util.StringTokenizer st = new java.util.StringTokenizer(
332:                                            toParse, ".");
333:                                    while (st.hasMoreTokens()) {
334:                                        String value = st.nextToken();
335:                                        if (!st.hasMoreTokens()) {
336:                                            if (i == 2) {//if this expression is 2 nodes long, then the last part of prefix is method name
337:                                                methodName = value;
338:                                            } else {
339:                                                varNames.add(value);
340:                                            }
341:                                        } else { //variable name
342:                                            varNames.add(value);
343:                                        }
344:                                    }
345:                                }
346:                                OTHERNODES: { //other methods called in this statement are grabbed here
347:                                    for (int x = 1; x < i - 1; x++) {
348:                                        ASTPrimarySuffix child = (ASTPrimarySuffix) node
349:                                                .jjtGetChild(x);
350:                                        if (!child.isArguments()) {
351:                                            String name = child.getImage();
352:                                            if (x == i - 2) {
353:                                                methodName = name;
354:                                            } else {
355:                                                varNames.add(name);
356:                                            }
357:                                        }
358:                                    }
359:                                }
360:                            }
361:                            meth = new MethodInvocation(node,
362:                                    packagesAndClasses, varNames, methodName,
363:                                    numOfArguments, super First);
364:                        }
365:                    }
366:                    return meth;
367:                }
368:
369:                public void show() {
370:                    System.out.println("<MethodInvocation>");
371:                    System.out.println("  <Qualifiers>");
372:                    for (String name : getQualifierNames()) {
373:                        System.out.println("    " + name);
374:                    }
375:                    System.out.println("  </Qualifiers>");
376:                    System.out.println("  <Super>" + isSuper() + "</Super>");
377:                    System.out.println("  <References>");
378:                    for (String name : getReferenceNames()) {
379:                        System.out.println("    " + name);
380:                    }
381:                    System.out.println("  </References>");
382:                    System.out.println("  <Name>" + getName() + "</Name>");
383:                    System.out.println("</MethodInvocation>");
384:                }
385:            }
386:
387:            private static final class ConstructorInvocation {
388:                private ASTExplicitConstructorInvocation m_Eci;
389:                private String name;
390:                private int count = 0;
391:
392:                public ConstructorInvocation(
393:                        ASTExplicitConstructorInvocation eci) {
394:                    m_Eci = eci;
395:                    List<ASTArguments> l = new ArrayList<ASTArguments>();
396:                    eci.findChildrenOfType(ASTArguments.class, l);
397:                    if (!l.isEmpty()) {
398:                        ASTArguments aa = l.get(0);
399:                        count = aa.getArgumentCount();
400:                    }
401:                    name = eci.getImage();
402:                }
403:
404:                public ASTExplicitConstructorInvocation getASTExplicitConstructorInvocation() {
405:                    return m_Eci;
406:                }
407:
408:                public int getArgumentCount() {
409:                    return count;
410:                }
411:
412:                public String getName() {
413:                    return name;
414:                }
415:            }
416:
417:            private static final class MethodHolder {
418:                private ASTMethodDeclarator amd;
419:                private boolean dangerous;
420:                private String called;
421:
422:                public MethodHolder(ASTMethodDeclarator amd) {
423:                    this .amd = amd;
424:                }
425:
426:                public void setCalledMethod(String name) {
427:                    this .called = name;
428:                }
429:
430:                public String getCalled() {
431:                    return this .called;
432:                }
433:
434:                public ASTMethodDeclarator getASTMethodDeclarator() {
435:                    return amd;
436:                }
437:
438:                public boolean isDangerous() {
439:                    return dangerous;
440:                }
441:
442:                public void setDangerous() {
443:                    dangerous = true;
444:                }
445:            }
446:
447:            private final class ConstructorHolder {
448:                private ASTConstructorDeclaration m_Cd;
449:                private boolean m_Dangerous;
450:                private ConstructorInvocation m_Ci;
451:                private boolean m_CiInitialized;
452:
453:                public ConstructorHolder(ASTConstructorDeclaration cd) {
454:                    m_Cd = cd;
455:                }
456:
457:                public ASTConstructorDeclaration getASTConstructorDeclaration() {
458:                    return m_Cd;
459:                }
460:
461:                public ConstructorInvocation getCalledConstructor() {
462:                    if (!m_CiInitialized) {
463:                        initCI();
464:                    }
465:                    return m_Ci;
466:                }
467:
468:                public ASTExplicitConstructorInvocation getASTExplicitConstructorInvocation() {
469:                    ASTExplicitConstructorInvocation eci = null;
470:                    if (!m_CiInitialized) {
471:                        initCI();
472:                    }
473:                    if (m_Ci != null) {
474:                        eci = m_Ci.getASTExplicitConstructorInvocation();
475:                    }
476:                    return eci;
477:                }
478:
479:                private void initCI() {
480:                    List<ASTExplicitConstructorInvocation> expressions = new ArrayList<ASTExplicitConstructorInvocation>();
481:                    m_Cd
482:                            .findChildrenOfType(
483:                                    ASTExplicitConstructorInvocation.class,
484:                                    expressions); //only 1...
485:                    if (!expressions.isEmpty()) {
486:                        ASTExplicitConstructorInvocation eci = expressions
487:                                .get(0);
488:                        m_Ci = new ConstructorInvocation(eci);
489:                        //System.out.println("Const call " + eci.getImage()); //super or this???
490:                    }
491:                    m_CiInitialized = true;
492:                }
493:
494:                public boolean isDangerous() {
495:                    return m_Dangerous;
496:                }
497:
498:                public void setDangerous(boolean dangerous) {
499:                    m_Dangerous = dangerous;
500:                }
501:            }
502:
503:            private static final int compareNodes(SimpleNode n1, SimpleNode n2) {
504:                int l1 = n1.getBeginLine();
505:                int l2 = n2.getBeginLine();
506:                if (l1 == l2) {
507:                    return n1.getBeginColumn() - n2.getBeginColumn();
508:                }
509:                return l1 - l2;
510:            }
511:
512:            private static class MethodHolderComparator implements 
513:                    Comparator<MethodHolder> {
514:                public int compare(MethodHolder o1, MethodHolder o2) {
515:                    return compareNodes(o1.getASTMethodDeclarator(), o2
516:                            .getASTMethodDeclarator());
517:                }
518:            }
519:
520:            private static class ConstructorHolderComparator implements 
521:                    Comparator<ConstructorHolder> {
522:                public int compare(ConstructorHolder o1, ConstructorHolder o2) {
523:                    return compareNodes(o1.getASTConstructorDeclaration(), o2
524:                            .getASTConstructorDeclaration());
525:                }
526:            }
527:
528:            /**
529:             * 1 package per class. holds info for evaluating a single class.
530:             */
531:            private static class EvalPackage {
532:                public EvalPackage() {
533:                }
534:
535:                public EvalPackage(String className) {
536:                    m_ClassName = className;
537:                    calledMethods = new ArrayList<MethodInvocation>();//meths called from constructor
538:                    allMethodsOfClass = new TreeMap<MethodHolder, List<MethodInvocation>>(
539:                            new MethodHolderComparator());
540:                    calledConstructors = new ArrayList<ConstructorInvocation>();//all constructors called from constructor
541:                    allPrivateConstructorsOfClass = new TreeMap<ConstructorHolder, List<MethodInvocation>>(
542:                            new ConstructorHolderComparator());
543:                }
544:
545:                public String m_ClassName;
546:                public List<MethodInvocation> calledMethods;
547:                public Map<MethodHolder, List<MethodInvocation>> allMethodsOfClass;
548:
549:                public List<ConstructorInvocation> calledConstructors;
550:                public Map<ConstructorHolder, List<MethodInvocation>> allPrivateConstructorsOfClass;
551:            }
552:
553:            private static final class NullEvalPackage extends EvalPackage {
554:                public NullEvalPackage() {
555:                    m_ClassName = "";
556:                    calledMethods = Collections.emptyList();
557:                    allMethodsOfClass = Collections.emptyMap();
558:                    calledConstructors = Collections.emptyList();
559:                    allPrivateConstructorsOfClass = Collections.emptyMap();
560:                }
561:            }
562:
563:            private static final NullEvalPackage nullEvalPackage = new NullEvalPackage();
564:
565:            /**
566:             * 1 package per class.
567:             */
568:            private final List<EvalPackage> evalPackages = new ArrayList<EvalPackage>();//could use java.util.Stack
569:
570:            private EvalPackage getCurrentEvalPackage() {
571:                return evalPackages.get(evalPackages.size() - 1);
572:            }
573:
574:            /**
575:             * Adds and evaluation package and makes it current
576:             */
577:            private void putEvalPackage(EvalPackage ep) {
578:                evalPackages.add(ep);
579:            }
580:
581:            private void removeCurrentEvalPackage() {
582:                evalPackages.remove(evalPackages.size() - 1);
583:            }
584:
585:            private void clearEvalPackages() {
586:                evalPackages.clear();
587:            }
588:
589:            /**
590:             * This check must be evaluated independently for each class. Inner classes
591:             * get their own EvalPackage in order to perform independent evaluation.
592:             */
593:            private Object visitClassDec(ASTClassOrInterfaceDeclaration node,
594:                    Object data) {
595:                String className = node.getImage();
596:                if (!node.isFinal()) {
597:                    putEvalPackage(new EvalPackage(className));
598:                } else {
599:                    putEvalPackage(nullEvalPackage);
600:                }
601:                //store any errors caught from other passes.
602:                super .visit(node, data);
603:
604:                //skip this class if it has no evaluation package
605:                if (!(getCurrentEvalPackage() instanceof  NullEvalPackage)) {
606:                    //evaluate danger of all methods in class, this method will return false when all methods have been evaluated
607:                    while (evaluateDangerOfMethods(getCurrentEvalPackage().allMethodsOfClass)) {
608:                    } //NOPMD
609:                    //evaluate danger of constructors
610:                    evaluateDangerOfConstructors1(
611:                            getCurrentEvalPackage().allPrivateConstructorsOfClass,
612:                            getCurrentEvalPackage().allMethodsOfClass.keySet());
613:                    while (evaluateDangerOfConstructors2(getCurrentEvalPackage().allPrivateConstructorsOfClass)) {
614:                    } //NOPMD
615:
616:                    //get each method called on this object from a non-private constructor, if its dangerous flag it
617:                    for (MethodInvocation meth : getCurrentEvalPackage().calledMethods) {
618:                        //check against each dangerous method in class
619:                        for (MethodHolder h : getCurrentEvalPackage().allMethodsOfClass
620:                                .keySet()) {
621:                            if (h.isDangerous()) {
622:                                String methName = h.getASTMethodDeclarator()
623:                                        .getImage();
624:                                int count = h.getASTMethodDeclarator()
625:                                        .getParameterCount();
626:                                if (methName.equals(meth.getName())
627:                                        && meth.getArgumentCount() == count) {
628:                                    addViolation(data, meth
629:                                            .getASTPrimaryExpression(),
630:                                            "method '" + h.getCalled() + "'");
631:                                }
632:                            }
633:                        }
634:                    }
635:                    //get each unsafe private constructor, and check if its called from any non private constructors
636:                    for (ConstructorHolder ch : getCurrentEvalPackage().allPrivateConstructorsOfClass
637:                            .keySet()) {
638:                        if (ch.isDangerous()) { //if its dangerous check if its called from any non-private constructors
639:                            //System.out.println("visitClassDec Evaluating dangerous constructor with " + ch.getASTConstructorDeclaration().getParameterCount() + " params");
640:                            int paramCount = ch.getASTConstructorDeclaration()
641:                                    .getParameterCount();
642:                            for (ConstructorInvocation ci : getCurrentEvalPackage().calledConstructors) {
643:                                if (ci.getArgumentCount() == paramCount) {
644:                                    //match name  super / this !?
645:                                    addViolation(
646:                                            data,
647:                                            ci
648:                                                    .getASTExplicitConstructorInvocation(),
649:                                            "constructor");
650:                                }
651:                            }
652:                        }
653:                    }
654:                }
655:                //finished evaluating this class, move up a level
656:                removeCurrentEvalPackage();
657:                return data;
658:            }
659:
660:            /**
661:             * Check the methods called on this class by each of the methods on this
662:             * class.  If a method calls an unsafe method, mark the calling method as
663:             * unsafe.  This changes the list of unsafe methods which necessitates
664:             * another pass.  Keep passing until you make a clean pass in which no
665:             * methods are changed to unsafe.
666:             * For speed it is possible to limit the number of passes.
667:             * <p/>
668:             * Impossible to tell type of arguments to method, so forget method matching
669:             * on types.  just use name and num of arguments.  will be some false hits,
670:             * but oh well.
671:             *
672:             * @todo investigate limiting the number of passes through config.
673:             */
674:            private boolean evaluateDangerOfMethods(
675:                    Map<MethodHolder, List<MethodInvocation>> classMethodMap) {
676:                //check each method if it calls overridable method
677:                boolean found = false;
678:                for (Map.Entry<MethodHolder, List<MethodInvocation>> entry : classMethodMap
679:                        .entrySet()) {
680:                    MethodHolder h = entry.getKey();
681:                    List<MethodInvocation> calledMeths = entry.getValue();
682:                    for (Iterator<MethodInvocation> calledMethsIter = calledMeths
683:                            .iterator(); calledMethsIter.hasNext()
684:                            && !h.isDangerous();) {
685:                        //if this method matches one of our dangerous methods, mark it dangerous
686:                        MethodInvocation meth = calledMethsIter.next();
687:                        //System.out.println("Called meth is " + meth);
688:                        for (MethodHolder h3 : classMethodMap.keySet()) { //need to skip self here h == h3
689:                            if (h3.isDangerous()) {
690:                                String matchMethodName = h3
691:                                        .getASTMethodDeclarator().getImage();
692:                                int matchMethodParamCount = h3
693:                                        .getASTMethodDeclarator()
694:                                        .getParameterCount();
695:                                //System.out.println("matching " + matchMethodName + " to " + meth.getName());
696:                                if (matchMethodName.equals(meth.getName())
697:                                        && matchMethodParamCount == meth
698:                                                .getArgumentCount()) {
699:                                    h.setDangerous();
700:                                    h.setCalledMethod(matchMethodName);
701:                                    found = true;
702:                                    break;
703:                                }
704:                            }
705:                        }
706:                    }
707:                }
708:                return found;
709:            }
710:
711:            /**
712:             * marks constructors dangerous if they call any dangerous methods
713:             * Requires only a single pass as methods are already marked
714:             *
715:             * @todo optimize by having methods already evaluated somehow!?
716:             */
717:            private void evaluateDangerOfConstructors1(
718:                    Map<ConstructorHolder, List<MethodInvocation>> classConstructorMap,
719:                    Set<MethodHolder> evaluatedMethods) {
720:                //check each constructor in the class
721:                for (Map.Entry<ConstructorHolder, List<MethodInvocation>> entry : classConstructorMap
722:                        .entrySet()) {
723:                    ConstructorHolder ch = entry.getKey();
724:                    if (!ch.isDangerous()) {//if its not dangerous then evaluate if it should be
725:                        //if it calls dangerous method mark it as dangerous
726:                        List<MethodInvocation> calledMeths = entry.getValue();
727:                        //check each method it calls
728:                        for (Iterator<MethodInvocation> calledMethsIter = calledMeths
729:                                .iterator(); calledMethsIter.hasNext()
730:                                && !ch.isDangerous();) {//but thee are diff objects which represent same thing but were never evaluated, they need reevaluation
731:                            MethodInvocation meth = calledMethsIter.next();//CCE
732:                            String methName = meth.getName();
733:                            int methArgCount = meth.getArgumentCount();
734:                            //check each of the already evaluated methods: need to optimize this out
735:                            for (MethodHolder h : evaluatedMethods) {
736:                                if (h.isDangerous()) {
737:                                    String matchName = h
738:                                            .getASTMethodDeclarator()
739:                                            .getImage();
740:                                    int matchParamCount = h
741:                                            .getASTMethodDeclarator()
742:                                            .getParameterCount();
743:                                    if (methName.equals(matchName)
744:                                            && (methArgCount == matchParamCount)) {
745:                                        ch.setDangerous(true);
746:                                        //System.out.println("evaluateDangerOfConstructors1 setting dangerous constructor with " + ch.getASTConstructorDeclaration().getParameterCount() + " params");
747:                                        break;
748:                                    }
749:                                }
750:
751:                            }
752:                        }
753:                    }
754:                }
755:            }
756:
757:            /**
758:             * Constructor map should contain a key for each private constructor, and
759:             * maps to a List which contains all called constructors of that key.
760:             * marks dangerous if call dangerous private constructor
761:             * we ignore all non-private constructors here.  That is, the map passed in
762:             * should not contain any non-private constructors.
763:             * we return boolean in order to limit the number of passes through this method
764:             * but it seems as if we can forgo that and just process it till its done.
765:             */
766:            private boolean evaluateDangerOfConstructors2(
767:                    Map<ConstructorHolder, List<MethodInvocation>> classConstructorMap) {
768:                boolean found = false;//triggers on danger state change
769:                //check each constructor in the class
770:                for (ConstructorHolder ch : classConstructorMap.keySet()) {
771:                    ConstructorInvocation calledC = ch.getCalledConstructor();
772:                    if (calledC == null || ch.isDangerous()) {
773:                        continue;
774:                    }
775:                    //if its not dangerous then evaluate if it should be
776:                    //if it calls dangerous constructor mark it as dangerous
777:                    int cCount = calledC.getArgumentCount();
778:                    for (Iterator<ConstructorHolder> innerConstIter = classConstructorMap
779:                            .keySet().iterator(); innerConstIter.hasNext()
780:                            && !ch.isDangerous();) { //forget skipping self because that introduces another check for each, but only 1 hit
781:                        ConstructorHolder h2 = innerConstIter.next();
782:                        if (h2.isDangerous()) {
783:                            int matchConstArgCount = h2
784:                                    .getASTConstructorDeclaration()
785:                                    .getParameterCount();
786:                            if (matchConstArgCount == cCount) {
787:                                ch.setDangerous(true);
788:                                found = true;
789:                                //System.out.println("evaluateDangerOfConstructors2 setting dangerous constructor with " + ch.getASTConstructorDeclaration().getParameterCount() + " params");
790:                            }
791:                        }
792:                    }
793:                }
794:                return found;
795:            }
796:
797:            public Object visit(ASTCompilationUnit node, Object data) {
798:                clearEvalPackages();
799:                return super .visit(node, data);
800:            }
801:
802:            public Object visit(ASTEnumDeclaration node, Object data) {
803:                // just skip Enums
804:                return data;
805:            }
806:
807:            /**
808:             * This check must be evaluated independelty for each class.  Inner classses
809:             * get their own EvalPackage in order to perform independent evaluation.
810:             */
811:            public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
812:                if (!node.isInterface()) {
813:                    return visitClassDec(node, data);
814:                } else {
815:                    putEvalPackage(nullEvalPackage);
816:                    Object o = super .visit(node, data);//interface may have inner classes, possible? if not just skip whole interface
817:                    removeCurrentEvalPackage();
818:                    return o;
819:                }
820:            }
821:
822:            /**
823:             * Non-private constructor's methods are added to a list for later safety
824:             * evaluation.  Non-private constructor's calls on private constructors
825:             * are added to a list for later safety evaluation.  Private constructors
826:             * are added to a list so their safety to be called can be later evaluated.
827:             * <p/>
828:             * Note: We are not checking private constructor's calls on non-private
829:             * constructors because all non-private constructors will be evaluated for
830:             * safety anyway.  This means we wont flag a private constructor as unsafe
831:             * just because it calls an unsafe public constructor.  We want to show only
832:             * 1 instance of an error, and this would be 2 instances of the same error.
833:             *
834:             * @todo eliminate the redundency
835:             */
836:            public Object visit(ASTConstructorDeclaration node, Object data) {
837:                if (!(getCurrentEvalPackage() instanceof  NullEvalPackage)) {//only evaluate if we have an eval package for this class
838:                    List<MethodInvocation> calledMethodsOfConstructor = new ArrayList<MethodInvocation>();
839:                    ConstructorHolder ch = new ConstructorHolder(node);
840:                    addCalledMethodsOfNode(node, calledMethodsOfConstructor,
841:                            getCurrentEvalPackage().m_ClassName);
842:                    if (!node.isPrivate()) {
843:                        //these calledMethods are what we will evaluate for being called badly
844:                        getCurrentEvalPackage().calledMethods
845:                                .addAll(calledMethodsOfConstructor);
846:                        //these called private constructors are what we will evaluate for being called badly
847:                        //we add all constructors invoked by non-private constructors
848:                        //but we are only interested in the private ones.  We just can't tell the difference here
849:                        ASTExplicitConstructorInvocation eci = ch
850:                                .getASTExplicitConstructorInvocation();
851:                        if (eci != null && eci.isThis()) {
852:                            getCurrentEvalPackage().calledConstructors.add(ch
853:                                    .getCalledConstructor());
854:                        }
855:                    } else {
856:                        //add all private constructors to list for later evaluation on if they are safe to call from another constructor
857:                        //store this constructorHolder for later evaluation
858:                        getCurrentEvalPackage().allPrivateConstructorsOfClass
859:                                .put(ch, calledMethodsOfConstructor);
860:                    }
861:                }
862:                return super .visit(node, data);
863:            }
864:
865:            /**
866:             * Create a MethodHolder to hold the method.
867:             * Store the MethodHolder in the Map as the key
868:             * Store each method called by the current method as a List in the Map as the Object
869:             */
870:            public Object visit(ASTMethodDeclarator node, Object data) {
871:                if (!(getCurrentEvalPackage() instanceof  NullEvalPackage)) {//only evaluate if we have an eval package for this class
872:                    AccessNode parent = (AccessNode) node.jjtGetParent();
873:                    MethodHolder h = new MethodHolder(node);
874:                    if (!parent.isAbstract() && !parent.isPrivate()
875:                            && !parent.isStatic() && !parent.isFinal()) { //Skip abstract methods, have a separate rule for that
876:                        h.setDangerous();//this method is overridable
877:                        ASTMethodDeclaration decl = node
878:                                .getFirstParentOfType(ASTMethodDeclaration.class);
879:                        h.setCalledMethod(decl.getMethodName());
880:                    }
881:                    List<MethodInvocation> l = new ArrayList<MethodInvocation>();
882:                    addCalledMethodsOfNode((SimpleNode) parent, l,
883:                            getCurrentEvalPackage().m_ClassName);
884:                    getCurrentEvalPackage().allMethodsOfClass.put(h, l);
885:                }
886:                return super .visit(node, data);
887:            }
888:
889:            private static void addCalledMethodsOfNode(AccessNode node,
890:                    List<MethodInvocation> calledMethods, String className) {
891:                List<ASTPrimaryExpression> expressions = new ArrayList<ASTPrimaryExpression>();
892:                node.findChildrenOfType(ASTPrimaryExpression.class,
893:                        expressions, false);
894:                addCalledMethodsOfNodeImpl(expressions, calledMethods,
895:                        className);
896:            }
897:
898:            /**
899:             * Adds all methods called on this instance from within this Node.
900:             */
901:            private static void addCalledMethodsOfNode(SimpleNode node,
902:                    List<MethodInvocation> calledMethods, String className) {
903:                List<ASTPrimaryExpression> expressions = new ArrayList<ASTPrimaryExpression>();
904:                node
905:                        .findChildrenOfType(ASTPrimaryExpression.class,
906:                                expressions);
907:                addCalledMethodsOfNodeImpl(expressions, calledMethods,
908:                        className);
909:            }
910:
911:            private static void addCalledMethodsOfNodeImpl(
912:                    List<ASTPrimaryExpression> expressions,
913:                    List<MethodInvocation> calledMethods, String className) {
914:                for (ASTPrimaryExpression ape : expressions) {
915:                    MethodInvocation meth = findMethod(ape, className);
916:                    if (meth != null) {
917:                        //System.out.println("Adding call " + methName);
918:                        calledMethods.add(meth);
919:                    }
920:                }
921:            }
922:
923:            /**
924:             * @return A method call on the class passed in, or null if no method call
925:             *         is found.
926:             * @todo Need a better way to match the class and package name to the actual
927:             * method being called.
928:             */
929:            private static MethodInvocation findMethod(
930:                    ASTPrimaryExpression node, String className) {
931:                if (node.jjtGetNumChildren() > 0
932:                        && node.jjtGetChild(0).jjtGetNumChildren() > 0
933:                        && node.jjtGetChild(0).jjtGetChild(0) instanceof  ASTLiteral) {
934:                    return null;
935:                }
936:                MethodInvocation meth = MethodInvocation.getMethod(node);
937:                boolean found = false;
938:                //		if(meth != null){
939:                //			meth.show();
940:                //		}
941:                if (meth != null) {
942:                    //if it's a call on a variable, or on its superclass ignore it.
943:                    if ((meth.getReferenceNames().size() == 0)
944:                            && !meth.isSuper()) {
945:                        //if this list does not contain our class name, then its not referencing our class
946:                        //this is a cheezy test... but it errs on the side of less false hits.
947:                        List<String> packClass = meth.getQualifierNames();
948:                        if (!packClass.isEmpty()) {
949:                            for (String name : packClass) {
950:                                if (name.equals(className)) {
951:                                    found = true;
952:                                    break;
953:                                }
954:                            }
955:                        } else {
956:                            found = true;
957:                        }
958:                    }
959:                }
960:
961:                return found ? meth : null;
962:            }
963:
964:            /**
965:             * ASTPrimaryPrefix has name in child node of ASTName
966:             */
967:            private static String getNameFromPrefix(ASTPrimaryPrefix node) {
968:                String name = null;
969:                //should only be 1 child, if more I need more knowledge
970:                if (node.jjtGetNumChildren() == 1) { //safety check
971:                    Node nnode = node.jjtGetChild(0);
972:                    if (nnode instanceof  ASTName) { //just as easy as null check and it should be an ASTName anyway
973:                        name = ((ASTName) nnode).getImage();
974:                    }
975:                }
976:                return name;
977:            }
978:
979:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.