diff --git a/docs/config_header.html b/docs/config_header.html
index 3ef89759f..5453916ff 100644
--- a/docs/config_header.html
+++ b/docs/config_header.html
@@ -37,6 +37,8 @@
Checks that a source file begins with a specified header. Property
headerFile specifies a file that contains the required header.
+ Alternatively, the header specification can be set directly in the
+ header property without the need for an external file.
Property ignoreLines specifies the line numbers to
@@ -70,6 +72,15 @@ line 5: ////////////////////////////////////////////////////////////////////
string |
null |
+
+ | header |
+ the required header specified inline. Individual header lines
+ must be separated by the string "\n"
+ (even on platforms with a different line separator),
+ see examples below. |
+ string |
+ null |
+
| ignoreLines |
line numbers to ignore |
@@ -90,6 +101,23 @@ line 5: ////////////////////////////////////////////////////////////////////
<property name="ignoreLines" value="2, 3, 4"/>
</module>
+
+
+ To configure the check to verify that each file starts with the header
+
+
+// Copyright (C) 2004 MyCompany
+// All rights reserved
+
+
+ without the need for an external header file:
+
+
+<module name="Header">
+ <property name="header" value="// Copyright (C) 2004 MyCompany\n// All rights reserved"/>
+</module>
+
+
Package
com.puppycrawl.tools.checkstyle.checks
@@ -100,7 +128,7 @@ line 5: ////////////////////////////////////////////////////////////////////
RegexpHeader
Description
- Checks the header of a source file against a header file that contains a regular
+ Checks the header of a source file against a header that contains a regular
expression for each line of the source header.
@@ -109,7 +137,7 @@ line 5: ////////////////////////////////////////////////////////////////////
information is not static.
- For example, consider the following header file:
+ For example, consider the following header:
line 1: ^/{71}$
@@ -150,6 +178,15 @@ line 14: ^ \*/
| string |
null |
+
+ | header |
+ the required header specified inline. Individual header lines
+ must be separated by the string "\n"
+ (even on platforms with a different line separator), and regular
+ expressions must not span multiple lines. |
+ string |
+ null |
+
| multiLines |
line numbers to repeat (zero or more times) |
@@ -169,6 +206,21 @@ line 14: ^ \*/
<module name="RegexpHeader">
<property name="headerFile" value="java.header"/>
<property name="multiLines" value="10, 13"/>
+</module>
+
+
+ To configure the check to verify that each file starts with the header
+
+
+^// Copyright \(C\) (\d\d\d\d -)? 2004 MyCompany$
+^// All rights reserved$
+
+
+ without the need for an external header file:
+
+
+<module name="RegexpHeader">
+ <property name="header" value="^// Copyright \(C\) (\d\d\d\d -)? 2004 MyCompany$\n^// All rights reserved$"/>
</module>
diff --git a/docs/releasenotes.html b/docs/releasenotes.html
index f40876a49..bffc187e1 100644
--- a/docs/releasenotes.html
+++ b/docs/releasenotes.html
@@ -35,6 +35,7 @@
Checkstyle 3
+
+ New features:
+
+
+ -
+ Java parser supports JDK 1.5 source files (metadata,
+ enhanced for loops, generics, enums).
+
+
+
+
+ Release 3.5
+
New features:
@@ -125,6 +139,10 @@ checkstyle-user).
and abstract methods.
(request 993922 and bug 1002849).
+ Header and RegexpHeader checks allow header
+ specification directly in the checkstyle configuration file,
+ not only in an external file (request 1041590).
+
com.puppycrawl.tools.checkstyle.gui.Main accepts an
optional file name in the command line.
(request 1000102).
diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractHeaderCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractHeaderCheck.java
index 99b9a347b..ef7afed1a 100644
--- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractHeaderCheck.java
+++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractHeaderCheck.java
@@ -22,12 +22,16 @@ package com.puppycrawl.tools.checkstyle.checks;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
+import java.io.Reader;
+import java.io.StringReader;
import java.util.ArrayList;
import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
+import com.puppycrawl.tools.checkstyle.api.Utils;
import org.apache.commons.beanutils.ConversionException;
+import org.apache.regexp.RE;
/**
* Abstract super class for header checks.
@@ -61,25 +65,100 @@ public abstract class AbstractHeaderCheck extends Check
return;
}
+ checkHeaderNotInitialized();
+
// load the file
+ Reader headerReader = null;
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]);
+ headerReader = new FileReader(aFileName);
+ loadHeader(headerReader);
}
catch (IOException ex) {
throw new ConversionException(
"unable to load header file " + aFileName, ex);
}
+ finally {
+ if (headerReader != null) {
+ try {
+ headerReader.close();
+ }
+ catch (IOException ex) {
+ throw new ConversionException(
+ "unable to close header file " + aFileName, ex);
+ }
+ }
+ }
+ }
+ /**
+ * Set the header to check against. Individual lines in the header
+ * must be separated by '\n' characters.
+ * @param aHeader header content to check against.
+ * @throws ConversionException if the header cannot be interpreted
+ */
+ public void setHeader(String aHeader)
+ {
+ if ((aHeader == null) || (aHeader.trim().length() == 0)) {
+ return;
+ }
+
+ checkHeaderNotInitialized();
+
+ // in JDK 1.4 we'd simply do aHeader.replaceAll("\\\\n", "\n");
+ final RE re = Utils.getRE("\\\\n");
+ final String headerExpandedNewLines = re.subst(aHeader, "\n");
+
+ final Reader headerReader = new StringReader(headerExpandedNewLines);
+ try {
+ loadHeader(headerReader);
+ }
+ catch (IOException ex) {
+ throw new ConversionException(
+ "unable to load header", ex);
+ }
+ finally {
+ try {
+ headerReader.close();
+ }
+ catch (IOException ex) {
+ // shouldn't happen with StringReader
+ throw new ConversionException(
+ "unable to close header", ex);
+ }
+ }
+
+ }
+
+ /**
+ * Called before initializing the header.
+ * @throws ConversionException if header has already been set
+ */
+ private void checkHeaderNotInitialized()
+ {
+ if (mHeaderLines != null) {
+ throw new ConversionException(
+ "header has already been set - "
+ + "set either header or headerFile, not both");
+ }
+ }
+
+ /**
+ * Load header to check against from a Reader into mHeaderLines.
+ * @param aHeaderReader delivers the header to check against
+ * @throws IOException if
+ */
+ private void loadHeader(final Reader aHeaderReader) throws IOException
+ {
+ final LineNumberReader lnr = new LineNumberReader(aHeaderReader);
+ 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]);
}
/**
diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/RegexpHeaderCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/RegexpHeaderCheck.java
index 762a0a48f..0ebc15e09 100644
--- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/RegexpHeaderCheck.java
+++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/RegexpHeaderCheck.java
@@ -76,8 +76,8 @@ import com.puppycrawl.tools.checkstyle.api.Utils;
* <property name="multiLines" value="10, 13"/>
*</module>
*
- * Note: ignoreLines property was removed you should use ^.*$ regexp
- * for line to ignore it.
+ *
Note: ignoreLines property has been removed from this check to
+ * simplify it. The regular expression "^.*$" can be used to ignore a line.
*
*
* @author Lars Kühne
@@ -129,6 +129,25 @@ public class RegexpHeaderCheck extends AbstractHeaderCheck
throws ConversionException
{
super.setHeaderFile(aFileName);
+ initHeaderRegexps();
+ }
+
+ /**
+ * Set the header to check against. Individual lines in the header
+ * must be separated by '\n' characters.
+ * @param aHeader header content to check against.
+ * @throws ConversionException if the header cannot be loaded or one line
+ * is not a regexp.
+ */
+ public void setHeader(String aHeader)
+ {
+ super.setHeader(aHeader);
+ initHeaderRegexps();
+ }
+
+ /** Initializes {@link #mHeaderRegexps} from {@link #mHeaderLines}. */
+ private void initHeaderRegexps()
+ {
final String[] headerLines = getHeaderLines();
if (headerLines != null) {
mHeaderRegexps = new RE[headerLines.length];
@@ -139,7 +158,7 @@ public class RegexpHeaderCheck extends AbstractHeaderCheck
}
catch (RESyntaxException ex) {
throw new ConversionException(
- "line " + i + " in header file is not a regexp");
+ "line " + i + " in header specification is not a regular expression");
}
}
}
diff --git a/src/tests/com/puppycrawl/tools/checkstyle/checks/HeaderCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/HeaderCheckTest.java
index e3e14567e..a1322db70 100644
--- a/src/tests/com/puppycrawl/tools/checkstyle/checks/HeaderCheckTest.java
+++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/HeaderCheckTest.java
@@ -30,6 +30,33 @@ public class HeaderCheckTest extends BaseCheckTestCase
verify(checkConfig, getPath("InputScopeAnonInner.java"), expected);
}
+ public void testInlineRegexpHeader()
+ throws Exception
+ {
+ final DefaultConfiguration checkConfig =
+ createCheckConfig(RegexpHeaderCheck.class);
+ checkConfig.addAttribute("header", "^/*$\\n// .*\\n// Created: 2002\\n^//.*\\n^//.*");
+ final String[] expected = {
+ "3: Line does not match expected header line of '// Created: 2002'."
+ };
+ verify(checkConfig, getPath("InputScopeAnonInner.java"), expected);
+ }
+
+ public void testFailureForMultilineRegexp()
+ throws Exception
+ {
+ final DefaultConfiguration checkConfig =
+ createCheckConfig(RegexpHeaderCheck.class);
+ checkConfig.addAttribute("header", "^(.*\\n.*)");
+ try {
+ createChecker(checkConfig);
+ fail("Checker creation should not succeed when regexp spans multiple lines");
+ }
+ catch (CheckstyleException ex) {
+ // expected exception
+ }
+ }
+
public void testRegexpHeaderIgnore() throws Exception
{
final DefaultConfiguration checkConfig =
@@ -122,7 +149,7 @@ public class HeaderCheckTest extends BaseCheckTestCase
}
}
- public void testIllegalArgs()
+ public void testNonExistingHeaderFile()
throws Exception
{
final DefaultConfiguration checkConfig =