001: /*
002: * JFolder, Copyright 2001-2006 Gary Steinmetz
003: *
004: * Distributable under LGPL license.
005: * See terms of license at gnu.org.
006: */
007:
008: package org.jfolder.common.utils.misc;
009:
010: //base classes
011: import java.io.File;
012: import java.io.FileReader;
013: import java.io.LineNumberReader;
014: import java.util.ArrayList;
015: import java.util.Collections;
016: import java.util.HashMap;
017:
018: //project specific classes
019:
020: //other classes
021:
022: public class FindBadCode {
023:
024: public static void main(String args[]) throws Exception {
025: String startDirName = args[0];
026: int totalLines = processFile(new File(startDirName));
027: System.out.println(" TOTAL LINES = " + totalLines);
028: }
029:
030: private static int processFile(File inFile) throws Exception {
031:
032: int outValue = 0;
033:
034: if (inFile.isDirectory() && inFile.getName().equals("CVS")) {
035: //do nothing
036: } else if (inFile.isDirectory()) {
037: File files[] = inFile.listFiles();
038: for (int i = 0; i < files.length; i++) {
039: outValue = outValue + processFile(files[i]);
040: }
041: } else if (inFile.getName().endsWith(".java")) {
042: ArrayList errorMessages = new ArrayList();
043: outValue = outValue
044: + processJavaFile(inFile, errorMessages);
045: if (errorMessages.size() > 0) {
046: print(errorMessages, inFile);
047: }
048: } else {
049: //do nothing
050: }
051:
052: return outValue;
053: }
054:
055: private static int processJavaFile(File inFile, ArrayList inMessages)
056: throws Exception {
057:
058: int outValue = 0;
059: //ArrayList outValue = new ArrayList();
060:
061: FileReader fr = new FileReader(inFile);
062: LineNumberReader lnr = new LineNumberReader(fr);
063:
064: //
065: boolean baseClassesFound = false;
066: HashMap baseClassesImports = new HashMap();
067: boolean projectSpecificClassesFound = false;
068: HashMap projectSpecificClassesImports = new HashMap();
069: boolean otherClassesFound = false;
070: HashMap otherClassesImports = new HashMap();
071: //
072: String nextLine = null;
073: int currentLine = 0;
074: boolean afterDeclare = false;
075: boolean lastLineTooLong = false;
076: while ((nextLine = lnr.readLine()) != null) {
077:
078: boolean currentLineImportHeader = false;
079:
080: if (lastLineTooLong) {
081:
082: inMessages.add("No padding at line "
083: + lnr.getLineNumber());
084: lastLineTooLong = false;
085: }
086:
087: currentLine++;
088:
089: if (nextLine.endsWith("}") && !nextLine.trim().equals("}")
090: && !nextLine.trim().startsWith("//")) {
091: inMessages.add("Dangling start brace at line "
092: + lnr.getLineNumber());
093: }
094:
095: if (nextLine.trim().equals("{")) {
096: inMessages.add("Dangling start brace at line "
097: + lnr.getLineNumber());
098: }
099: //if (nextLine.trim().startsWith("return ")
100: // && nextLine.endsWith(";")
101: // && (nextLine.indexOf("outValue") == -1
102: // && nextLine.indexOf("this") == -1)) {
103: // //
104: // inMessages.add(
105: // "Malformed return at line " + lnr.getLineNumber());
106: //}
107:
108: if (nextLine.indexOf('\t') != -1) {
109: inMessages.add("Tab at line " + lnr.getLineNumber());
110: }
111: if (nextLine.length() > 80) {
112: inMessages.add("More than 80 chars line "
113: + lnr.getLineNumber());
114: }
115: int spacePad = 0;
116: while (spacePad < nextLine.length()
117: && nextLine.charAt(spacePad) == ' ') {
118: spacePad++;
119: }
120: //if (((spacePad%4) != 0) && (currentLine > 6)) {
121: if (((spacePad % 4) != 0)) {
122: inMessages.add("Non-mod-4 spacing line "
123: + lnr.getLineNumber());
124: }
125: if (nextLine.trim().length() > 0
126: && nextLine.charAt(nextLine.length() - 1) == ' '
127: && (nextLine.indexOf("//") == -1)) {
128: //
129: inMessages.add("Post padding at line "
130: + lnr.getLineNumber());
131: }
132: if (spacePad == 0 && afterDeclare) {
133: lastLineTooLong = true;
134: }
135: if (!afterDeclare) {
136: if (nextLine.equals("//base classes")) {
137: if (!baseClassesFound) {
138: if (projectSpecificClassesFound
139: || otherClassesFound) {
140: //
141: inMessages
142: .add("'//base classes' out of place");
143: }
144: baseClassesFound = true;
145: currentLineImportHeader = true;
146: } else {
147: inMessages.add("Base classes listed twice");
148: }
149: } else if (nextLine
150: .equals("//project specific classes")) {
151: if (!projectSpecificClassesFound) {
152: if (otherClassesFound) {
153: //
154: inMessages
155: .add("'//project specific classes' out of place");
156: }
157: projectSpecificClassesFound = true;
158: currentLineImportHeader = true;
159: } else {
160: inMessages
161: .add("Project specific classes listed twice");
162: }
163: } else if (nextLine.equals("//other classes")) {
164: if (!otherClassesFound) {
165: otherClassesFound = true;
166: currentLineImportHeader = true;
167: } else {
168: inMessages.add("Other classes listed twice");
169: }
170: }
171: }
172: //
173: afterDeclare |= (nextLine.indexOf("interface ") != -1);
174: afterDeclare |= (nextLine.indexOf("class ") != -1);
175: //
176: if (!afterDeclare && !currentLineImportHeader
177: && nextLine.length() > 0) {
178: if (otherClassesFound) {
179: otherClassesImports.put(new Integer(lnr
180: .getLineNumber()), nextLine);
181: } else if (projectSpecificClassesFound) {
182: projectSpecificClassesImports.put(new Integer(lnr
183: .getLineNumber()), nextLine);
184: } else if (baseClassesFound) {
185: baseClassesImports.put(new Integer(lnr
186: .getLineNumber()), nextLine);
187: }
188: }
189:
190: }
191:
192: if (currentLine > 0) {
193: //
194: if (!baseClassesFound) {
195: inMessages.add("'//base classes' never listed");
196: } else {
197: validateImports(baseClassesImports, new String[] {
198: "import java.", "import javax.",
199: "import org.w3c.", "import org.xml." },
200: new String[] {}, inMessages);
201: }
202: //
203: if (!projectSpecificClassesFound) {
204: inMessages
205: .add("'//project specific classes' never listed");
206: } else {
207: validateImports(projectSpecificClassesImports,
208: new String[] { "import org.jfolder." },
209: new String[] {}, inMessages);
210: }
211: //
212: if (!otherClassesFound) {
213: inMessages.add("'//other classes' never listed");
214: } else {
215: validateImports(projectSpecificClassesImports,
216: new String[] { "import " }, new String[] {},
217: inMessages);
218: }
219: }
220:
221: lnr.close();
222: fr.close();
223:
224: outValue = currentLine;
225:
226: return outValue;
227: }
228:
229: private final static void validateImports(HashMap inImports,
230: String inValidPrefixes[], String inInvalidPrefixes[],
231: ArrayList inMessages) {
232:
233: ArrayList lineNumbers = new ArrayList(inImports.keySet());
234: Collections.sort(lineNumbers);
235: for (int i = 0; i < lineNumbers.size(); i++) {
236: Integer currLineNum = (Integer) lineNumbers.get(i);
237: String currImport = (String) inImports.get(currLineNum);
238: if (currImport.endsWith(";")) {
239: currImport = currImport.substring(0, currImport
240: .length() - 1);
241: }
242: if (i != 0) {
243: Integer prevLineNum = (Integer) lineNumbers.get(i - 1);
244: //
245: String prevImport = (String) inImports.get(prevLineNum);
246: if (prevImport.endsWith(";")) {
247: prevImport = prevImport.substring(0, prevImport
248: .length() - 1);
249: }
250: if (prevImport.compareTo(currImport) == 0) {
251: inMessages.add(currLineNum + " is out of order");
252: } else if (prevImport.compareTo(currImport) > 0) {
253: inMessages.add(currLineNum + " is out of order");
254: }
255: }
256: boolean validImport = false;
257: for (int j = 0; j < inValidPrefixes.length; j++) {
258: validImport |= currImport
259: .startsWith(inValidPrefixes[j]);
260: }
261: if (!validImport && inValidPrefixes.length > 0) {
262: inMessages.add(currLineNum
263: + " - not a valid import prefix");
264:
265: }
266: //
267: boolean invalidImport = false;
268: for (int j = 0; j < inInvalidPrefixes.length; j++) {
269: invalidImport |= currImport
270: .startsWith(inValidPrefixes[j]);
271: }
272: if (invalidImport) {
273: inMessages.add(currLineNum
274: + " - not a valid import prefix");
275:
276: }
277: }
278: }
279:
280: private final static void print(ArrayList inMessages, File inFile) {
281: MiscHelper.println();
282: MiscHelper.println("<!-- " + inFile.getAbsoluteFile() + " -->");
283: for (int i = 0; i < inMessages.size(); i++) {
284: MiscHelper.println(inMessages.get(i));
285: }
286: MiscHelper.println("<!-- -------------------------------- -->");
287: }
288: }
|