diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/HeaderCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/HeaderCheck.java index 8858e06a1..a447e620c 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/HeaderCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/HeaderCheck.java @@ -18,20 +18,34 @@ //////////////////////////////////////////////////////////////////////////////// package com.puppycrawl.tools.checkstyle.checks; +import java.io.FileReader; +import java.io.IOException; +import java.io.LineNumberReader; +import java.util.ArrayList; +import java.util.StringTokenizer; +import java.util.TreeSet; + import com.puppycrawl.tools.checkstyle.api.Check; +import org.apache.commons.beanutils.ConversionException; /** - * Checks that the header of the source file is correct. + * Checks the header of the source against a fixed header file. * *
* Rationale: In most projects each file must have a fixed header, - * usually the header contains copyright information. + * since usually the header contains copyright information. *
* * @author Lars Kühne */ public class HeaderCheck extends Check { + /** the lines of the header file */ + private String[] mHeaderLines = null; + + /** the header lines to ignore in the check */ + private TreeSet mIgnoreLines = new TreeSet(); + /** @see com.puppycrawl.tools.checkstyle.api.Check */ public int[] getDefaultTokens() { @@ -41,7 +55,105 @@ public class HeaderCheck extends Check /** @see com.puppycrawl.tools.checkstyle.api.Check */ public void beginTree() { - String[] lines = getLines(); - log(0, "file has " + lines.length + " lines"); + System.out.println("HeaderCheck.beginTree"); + if (mHeaderLines != null) { + + final String[] lines = getLines(); + + if (mHeaderLines.length > lines.length) { + log(1, "header.missing"); + } + else { + for (int i = 0; i < mHeaderLines.length; i++) { + // skip lines we are meant to ignore + if (isIgnoreLine(i + 1)) { + continue; + } + + if (!isMatch(i)) { + log(i + 1, "header.mismatch", mHeaderLines[i]); + break; // stop checking + } + } + } + } } + + /** + * @param aLineNo a line number + * @return ifaLineNo is one of the ignored header lines.
+ */
+ private boolean isIgnoreLine(int aLineNo)
+ {
+ return mIgnoreLines.contains(new Integer(aLineNo));
+ }
+
+ /**
+ * Checks if a code line matches the required header line.
+ * @param lineNumber the linenumber to check against the header
+ * @return true if and only if the line matches the required header line
+ * TODO: override this in RegexpHeaderCheck
+ */
+ protected boolean isMatch(int lineNumber)
+ {
+ final String[] lines = getLines();
+ return mHeaderLines[lineNumber].equals(lines[lineNumber]);
+ }
+
+ /**
+ * Set the header file to check against.
+ * @throws org.apache.commons.beanutils.ConversionException if
+ * the file cannot be loaded
+ */
+ public void setHeaderFile(String aFileName)
+ {
+ // Handle empty param
+ if ((aFileName == null) || (aFileName.trim().length() == 0)) {
+ return;
+ }
+
+ // load the file
+ try {
+ final LineNumberReader lnr =
+ new LineNumberReader(new FileReader(aFileName));
+ final ArrayList lines = new ArrayList();
+ while (true) {
+ final String l = lnr.readLine();
+ if (l == null) {
+ break;
+ }
+ lines.add(l);
+ }
+ mHeaderLines = (String[]) lines.toArray(new String[0]);
+ }
+ catch (IOException ex) {
+ throw new ConversionException(
+ "unable to load header file " + aFileName, ex);
+ }
+
+ }
+
+ /**
+ * Set the lines numbers to ignore in the header check.
+ * @param aList comma separated list of line numbers to ignore in header.
+ * TODO: This should really be of type int[]
+ * and beanutils should do the parsing for us!
+ */
+ public void setIgnoreLines(String aList)
+ {
+ mIgnoreLines.clear();
+ if (aList != null) {
+ final StringTokenizer tokens = new StringTokenizer(aList, ",");
+ while (tokens.hasMoreTokens()) {
+ final String ignoreLine = tokens.nextToken();
+ mIgnoreLines.add(new Integer(ignoreLine));
+ }
+ }
+ }
+
+ protected String[] getHeaderLines()
+ {
+ return mHeaderLines;
+ }
+
}
diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/RegexpHeaderCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/RegexpHeaderCheck.java
new file mode 100644
index 000000000..531400d0e
--- /dev/null
+++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/RegexpHeaderCheck.java
@@ -0,0 +1,57 @@
+package com.puppycrawl.tools.checkstyle.checks;
+
+import org.apache.regexp.RE;
+import org.apache.regexp.RESyntaxException;
+import org.apache.commons.beanutils.ConversionException;
+import com.puppycrawl.tools.checkstyle.api.Utils;
+
+/**
+ * Checks the header of the source against a header file that contains a
+ * regular expression for each line of the source header.
+ *
+ * + * Rationale: In some projects checking against a fixed header + * is not sufficient (see {@link HeaderCheck}), e.g. + * the header might require a copyright line where the year information + * is not static. + *
+ * + *+ * TODO: RFE 597676 + *
+ * + * @author Lars Kühne + */ +public class RegexpHeaderCheck extends HeaderCheck +{ + /** the compiled regular expressions */ + private RE[] mHeaderRegexps = null; + + /** */ + public void setHeaderFile(String aFileName) + { + super.setHeaderFile(aFileName); + final String[] headerLines = getHeaderLines(); + if (headerLines != null) { + mHeaderRegexps = new RE[headerLines.length]; + for (int i = 0; i < headerLines.length; i++) { + try { + // TODO: Not sure if chache in Utils is still necessary + mHeaderRegexps[i] = Utils.getRE(headerLines[i]); + } + catch (RESyntaxException ex) { + throw new ConversionException( + "line " + i + " in header file is not a regexp"); + } + } + } + } + + + /** @see HeaderCheck */ + protected boolean isMatch(int lineNumber) + { + final String[] lines = getLines(); + return mHeaderRegexps[lineNumber].match(lines[lineNumber]); + } +} diff --git a/src/tests/com/puppycrawl/tools/checkstyle/HeaderCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/HeaderCheckTest.java new file mode 100644 index 000000000..9f65f7059 --- /dev/null +++ b/src/tests/com/puppycrawl/tools/checkstyle/HeaderCheckTest.java @@ -0,0 +1,43 @@ +package com.puppycrawl.tools.checkstyle; + +import com.puppycrawl.tools.checkstyle.checks.HeaderCheck; +import com.puppycrawl.tools.checkstyle.checks.RegexpHeaderCheck; + +public class HeaderCheckTest extends BaseCheckTestCase +{ + public HeaderCheckTest(String aName) + { + super(aName); + } + + public void testStaticHeader() + throws Exception + { + final CheckConfiguration checkConfig = new CheckConfiguration(); + checkConfig.setClassname(HeaderCheck.class.getName()); + checkConfig.addProperty("headerFile", getPath("java.header")); + final Checker c = createChecker(checkConfig); + final String fname = getPath("inputHeader.java"); + final String[] expected = { + "1:1: Missing a header - not enough lines in file." + }; + verify(c, fname, expected); + } + + public void testRegexpHeader() + throws Exception + { + final CheckConfiguration checkConfig = new CheckConfiguration(); + checkConfig.setClassname(RegexpHeaderCheck.class.getName()); + checkConfig.addProperty("headerFile", getPath("regexp.header")); + checkConfig.addProperty("ignoreLines", "4,5"); + final Checker c = createChecker(checkConfig); + final String fname = getPath("InputScopeAnonInner.java"); + final String[] expected = { + "3:1: Line does not match expected header line of '// Created: 2002'." + }; + verify(c, fname, expected); + } + + +}