DCD xref

View Javadoc
1 /**
2  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html 
3  */
4 package net.sourceforge.pmd.dcd;
5 
6 import java.io.File;
7 import java.io.FilenameFilter;
8 import java.util.ArrayList;
9 import java.util.Arrays;
10 import java.util.List;
11 
12 import net.sourceforge.pmd.dcd.graph.UsageGraph;
13 import net.sourceforge.pmd.dcd.graph.UsageGraphBuilder;
14 import net.sourceforge.pmd.util.FileFinder;
15 import net.sourceforge.pmd.util.filter.Filter;
16 import net.sourceforge.pmd.util.filter.Filters;
17 
18 /**
19  * The Dead Code Detector is used to find dead code. What is dead code?
20  * Dead code is code which is not used by other code? It exists, but it not
21  * used. Unused code is clutter, which can generally be a candidate for
22  * removal.
23  * <p>
24  * When performing dead code detection, there are various sets of files/classes
25  * which must be identified. An analogy of the dead code analysis as
26  * a <em>foot race</em> is used to help clarify each of these sets:
27  * <ol>
28  * <li>The <em>direct users</em> is the set of Classes which will always be
29  * parsed to determine what code they use. This set is the starting point of
30  * the race.</li>
31  * <li>The <em>indirect users</em> is the set of Classes which will only be
32  * parsed if they are accessed by code in the <em>direct users</em> set, or
33  * in the <em>indirect users</em> set. This set is the course of the race.</li>
34  * <li>The <em>dead code candidates</em> are the set of Classes which are the
35  * focus of the dead code detection. This set is the finish line of the
36  * race.</li>
37  * </ol>
38  * <p>
39  * Typically there is intersection between the set of <em>direct users</em>,
40  * <em>indirect users</em> and <em>dead code candidates</em>, although it is
41  * not required. If the sets are defined too tightly, there the potential for
42  * a lot of code to be considered as dead code. You may need to expand the
43  * <em>direct users</em> or <em>indirect users</em> sets, or explore using
44  * different options.
45  *
46  * @author Ryan Gustafson <ryan.gustafson@gmail.com>,
47  */
48 public class DCD {
49 	//
50 	// TODO Implement the direct users, indirect users, and dead code
51 	// candidate sets. Use the pmd.util.filter.Filter APIs. Need to come up
52 	// with something like Ant's capabilities for <fileset>, it's a decent way
53 	// to describe a collection of files in a directory structure. That or we
54 	// just adopt Ant, and screw command line/external configuration?
55 	//
56 	// TODO Better yet, is there a way to enumerate all available classes using
57 	// ClassLoaders instead of having to specify Java file names as surrogates
58 	// for the Classes we truly desire?
59 	//
60 	// TODO Methods defined on classes/interfaces not within the scope of
61 	// analysis which are implemented/overridden, are not usage violations.
62 	//
63 	// TODO Static final String and primitive types are often inlined by the
64 	// compiler, so there may actually be no explicit usages.
65 	//
66 	// TODO Ignore "public static void main(String[])"
67 	//
68 	// TODO Check for method which is always overridden, and never called
69 	// directly.
70 	//
71 	// TODO For methods, record which classes/interfaces methods they are
72 	// overriding/implementing.
73 	//
74 	// TODO Allow recognition of indirect method patterns, like those used by
75 	// EJB Home and Remote interfaces with corresponding implementation classes.
76 	//
77 	// TODO
78 	// 1) For each class/member, a set of other class/members which reference.
79 	// 2) For every class/member which is part of an interface or super-class,
80 	// allocate those references to the interface/super-class.
81 	//
82 
83 	public static void dump(UsageGraph usageGraph, boolean verbose) {
84 		usageGraph.accept(new DumpNodeVisitor(), Boolean.valueOf(verbose));
85 	}
86 
87 	public static void report(UsageGraph usageGraph, boolean verbose) {
88 		usageGraph.accept(new UsageNodeVisitor(), Boolean.valueOf(verbose));
89 	}
90 
91 	public static void main(String[] args) throws Exception {
92 		// 1) Directories
93 		List<File> directories = new ArrayList<File>();
94 		directories.add(new File("C:/pmd/workspace/pmd-trunk/src"));
95 
96 		// Basic filter
97 		FilenameFilter javaFilter = new FilenameFilter() {
98 			public boolean accept(File dir, String name) {
99 				// Recurse on directories
100 				if (new File(dir, name).isDirectory()) {
101 					return true;
102 				} else {
103 					return name.endsWith(".java");
104 				}
105 			}
106 		};
107 
108 		// 2) Filename filters
109 		List<FilenameFilter> filters = new ArrayList<FilenameFilter>();
110 		filters.add(javaFilter);
111 
112 		assert directories.size() == filters.size();
113 
114 		// Find all files, convert to class names
115 		List<String> classes = new ArrayList<String>();
116 		for (int i = 0; i < directories.size(); i++) {
117 			File directory = directories.get(i);
118 			FilenameFilter filter = filters.get(i);
119 			List<File> files = new FileFinder().findFilesFrom(directory.getPath(), filter, true);
120 			for (File file : files) {
121 				String name = file.getPath();
122 
123 				// Chop off directory
124 				name = name.substring(directory.getPath().length() + 1);
125 
126 				// Drop extension
127 				name = name.replaceAll("\\.java$", "");
128 
129 				// Trim path separators
130 				name = name.replace('\\', '.');
131 				name = name.replace('/', '.');
132 
133 				classes.add(name);
134 			}
135 		}
136 
137 		long start = System.currentTimeMillis();
138 
139 		// Define filter for "indirect users" and "dead code candidates".
140 		// TODO Need to support these are different concepts.
141 		List<String> includeRegexes = Arrays.asList(new String[] { "net\\.sourceforge\\.pmd\\.dcd.*", "us\\..*" });
142 		List<String> excludeRegexes = Arrays.asList(new String[] { "java\\..*", "javax\\..*", ".*\\.twa\\..*" });
143 		Filter<String> classFilter = Filters.buildRegexFilterExcludeOverInclude(includeRegexes, excludeRegexes);
144 		System.out.println("Class filter: " + classFilter);
145 
146 		// Index each of the "direct users"
147 		UsageGraphBuilder builder = new UsageGraphBuilder(classFilter);
148 		int total = 0;
149 		for (String clazz : classes) {
150 			System.out.println("indexing class: " + clazz);
151 			builder.index(clazz);
152 			total++;
153 			if (total % 20 == 0) {
154 				System.out.println(total + " : " + total / ((System.currentTimeMillis() - start) / 1000.0));
155 			}
156 		}
157 
158 		// Reporting
159 		boolean dump = true;
160 		boolean deadCode = true;
161 		UsageGraph usageGraph = builder.getUsageGraph();
162 		if (dump) {
163 			System.out.println("--- Dump ---");
164 			dump(usageGraph, true);
165 		}
166 		if (deadCode) {
167 			System.out.println("--- Dead Code ---");
168 			report(usageGraph, true);
169 		}
170 		long end = System.currentTimeMillis();
171 		System.out.println("Time: " + (end - start) / 1000.0);
172 	}
173 }

AltStyle によって変換されたページ (->オリジナル) /