rfe #1041590, allow header specification directly in checkstyle config file

This commit is contained in:
Lars Kühne 2004-10-16 17:13:04 +00:00
parent 510bf2e6a7
commit d1a2974764
5 changed files with 212 additions and 17 deletions

View File

@ -37,6 +37,8 @@
<p class="body">
Checks that a source file begins with a specified header. Property <span class="code">
headerFile</span> specifies a file that contains the required header.
Alternatively, the header specification can be set directly in the
<span class="code">header</span> property without the need for an external file.
</p>
<p class="body">
Property <span class="code">ignoreLines</span> specifies the line numbers to
@ -70,6 +72,15 @@ line 5: ////////////////////////////////////////////////////////////////////
<td><a href="property_types.html#string">string</a></td>
<td><span class="default">null</span></td>
</tr>
<tr>
<td>header</td>
<td>the required header specified inline. Individual header lines
must be separated by the string <span class="code">&quot;\n&quot;</span>
(even on platforms with a different line separator),
see examples below.</td>
<td><a href="property_types.html#string">string</a></td>
<td><span class="default">null</span></td>
</tr>
<tr>
<td>ignoreLines</td>
<td>line numbers to ignore</td>
@ -90,6 +101,23 @@ line 5: ////////////////////////////////////////////////////////////////////
&lt;property name=&quot;ignoreLines&quot; value=&quot;2, 3, 4&quot;/&gt;
&lt;/module&gt;
</pre>
<p class="body">
To configure the check to verify that each file starts with the header
</p>
<pre class="body">
// Copyright (C) 2004 MyCompany
// All rights reserved
</pre>
<p class="body">
without the need for an external header file:
</p>
<pre class="body">
&lt;module name=&quot;Header&quot;&gt;
&lt;property name=&quot;header&quot; value=&quot;// Copyright (C) 2004 MyCompany\n// All rights reserved&quot;/&gt;
&lt;/module&gt;
</pre>
<h4>Package</h4>
<p class="body">
com.puppycrawl.tools.checkstyle.checks
@ -100,7 +128,7 @@ line 5: ////////////////////////////////////////////////////////////////////
</p>
<a name="RegexpHeader"></a> <h2>RegexpHeader</h2> <h4>Description</h4>
<p class="body">
Checks the header of a source file against a header file that contains a <a href="http://jakarta.apache.org/regexp/apidocs/org/apache/regexp/RE.html">regular
Checks the header of a source file against a header that contains a <a href="http://jakarta.apache.org/regexp/apidocs/org/apache/regexp/RE.html">regular
expression</a> for each line of the source header.
</p>
<p class="body">
@ -109,7 +137,7 @@ line 5: ////////////////////////////////////////////////////////////////////
information is not static.
</p>
<p class="body">
For example, consider the following header file:
For example, consider the following header:
</p>
<pre class="body">
line 1: ^/{71}$
@ -150,6 +178,15 @@ line 14: ^ \*/
<td><a href="property_types.html#string">string</a></td>
<td><span class="default">null</span></td>
</tr>
<tr>
<td>header</td>
<td>the required header specified inline. Individual header lines
must be separated by the string <span class="code">&quot;\n&quot;</span>
(even on platforms with a different line separator), and regular
expressions must not span multiple lines.</td>
<td><a href="property_types.html#string">string</a></td>
<td><span class="default">null</span></td>
</tr>
<tr>
<td>multiLines</td>
<td>line numbers to repeat (zero or more times)</td>
@ -169,6 +206,21 @@ line 14: ^ \*/
&lt;module name=&quot;RegexpHeader&quot;&gt;
&lt;property name=&quot;headerFile&quot; value=&quot;java.header&quot;/&gt;
&lt;property name=&quot;multiLines&quot; value=&quot;10, 13&quot;/&gt;
&lt;/module&gt;
</pre>
<p class="body">
To configure the check to verify that each file starts with the header
</p>
<pre class="body">
^// Copyright \(C\) (\d\d\d\d -)? 2004 MyCompany$
^// All rights reserved$
</pre>
<p class="body">
without the need for an external header file:
</p>
<pre class="body">
&lt;module name=&quot;RegexpHeader&quot;&gt;
&lt;property name=&quot;header&quot; value=&quot;^// Copyright \(C\) (\d\d\d\d -)? 2004 MyCompany$\n^// All rights reserved$&quot;/&gt;
&lt;/module&gt;
</pre>
<p class="body">

View File

@ -35,6 +35,7 @@
<p>Checkstyle 3</p>
<ul>
<li><a href="#release3_5">Release 3.5</a></li>
<li><a href="#release3_4">Release 3.4</a></li>
<li><a href="#release3_3">Release 3.3</a></li>
<li><a href="#release3_2">Release 3.2</a></li>
@ -68,6 +69,19 @@
</li>
</ul>
<p class="body">
New features:
</p>
<ul>
<li class="body">
Java parser supports JDK 1.5 source files (metadata,
enhanced for loops, generics, enums).
</li>
</ul>
<a name="release3_5"></a>
<h2>Release 3.5</h2>
<p class="body">
New features:
</p>
@ -125,6 +139,10 @@ checkstyle-user</a>).</li>
and abstract methods.
(request 993922 and bug 1002849).</li>
<li class="body">Header and RegexpHeader checks allow header
specification directly in the checkstyle configuration file,
not only in an external file (request 1041590).
<li class="body">com.puppycrawl.tools.checkstyle.gui.Main accepts an
optional file name in the command line.
(request 1000102).</li>

View File

@ -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]);
}
/**

View File

@ -76,8 +76,8 @@ import com.puppycrawl.tools.checkstyle.api.Utils;
* &lt;property name=&quot;multiLines&quot; value=&quot;10, 13&quot;/&gt;
*&lt;/module&gt;
* </pre>
* <p><u>Note</u>: ignoreLines property was removed you should use ^.*$ regexp
* for line to ignore it.
* <p><u>Note</u>: ignoreLines property has been removed from this check to
* simplify it. The regular expression &quot;^.*$&quot; can be used to ignore a line.
* </p>
*
* @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");
}
}
}

View File

@ -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 =