Change formatter to use 100 col. comments and add a checkstyle check for it
Review at http://gwt-code-reviews.appspot.com/1465803
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10381 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/build-tools/customchecks/src/com/google/gwt/checkstyle/CustomRegexpHeaderCheck.java b/build-tools/customchecks/src/com/google/gwt/checkstyle/CustomRegexpHeaderCheck.java
new file mode 100644
index 0000000..f08a2bd
--- /dev/null
+++ b/build-tools/customchecks/src/com/google/gwt/checkstyle/CustomRegexpHeaderCheck.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+// //////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2005 Oliver Burn
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+// //////////////////////////////////////////////////////////////////////////////
+package com.google.gwt.checkstyle;
+
+import com.puppycrawl.tools.checkstyle.checks.header.RegexpHeaderCheck;
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+import com.puppycrawl.tools.checkstyle.api.Utils;
+
+import org.apache.commons.beanutils.ConversionException;
+
+import java.util.Arrays;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * Custom version of {@link RegexpHeaderCheck} that has hooks for a custom log handler (see
+ * {@link CustomLogHandler}).
+ * <p>
+ * This is an exact copy of {@link RegexpHeaderCheck} with three exceptions:
+ * <ol>
+ * <li>{@link CustomLogHandler} has been added for custom log callbacks.</li>
+ * <li>{@link #doChecks(CustomLogHandler)} has been added for custom checks. This method is an exact
+ * copy of {@link RegexpHeaderCheck#beginTree(DetailAST)} except all log calls have been replaced
+ * with a call to a custom log handler.</li>
+ * <li>{@link #beginTree(DetailAST)} has been refactored to call
+ * {@link #doChecks(CustomLogHandler)}.
+ * </ol>
+ */
+public class CustomRegexpHeaderCheck extends RegexpHeaderCheck {
+ /**
+ * Custom log handler callback.
+ */
+ abstract static class CustomLogHandler {
+ abstract void log(int aLine, String aKey);
+
+ abstract void log(int aLine, String aKey, Object aObject);
+ }
+
+ // empty array to avoid instantiations.
+ private static final int[] EMPTY_INT_ARRAY = new int[0];
+
+ // the header lines to repeat (0 or more) in the check, sorted.
+ private int[] mMultiLines = EMPTY_INT_ARRAY;
+
+ // the compiled regular expressions
+ private Pattern[] mHeaderRegexps;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void beginTree(DetailAST aRootAST) {
+ doChecks(new CustomLogHandler() {
+ @Override
+ void log(int aLine, String aKey) {
+ CustomRegexpHeaderCheck.this.log(aLine, aKey);
+ }
+ @Override
+ void log(int aLine, String aKey, Object aObject) {
+ CustomRegexpHeaderCheck.this.log(aLine, aKey, aObject);
+ }
+ });
+ }
+
+ /**
+ * Check the current file using the same method as {@link RegexpHeaderCheck#beginTree(DetailAST)}
+ * but pass all logging calls through a custom log handler (@see {@link CustomLogHandler}).
+ *
+ * @param logHandler the custom log handler, or <code>null</code> to suppress logging.
+ */
+ public void doChecks(CustomLogHandler logHandler) {
+ // With the exception of the logging hooks, the following is copied from
+ // RegexpHeaderCheck.beginTree().
+
+ final int headerSize = getHeaderLines().length;
+ final int fileSize = getLines().length;
+
+ if (headerSize - mMultiLines.length > fileSize) {
+ if (logHandler != null) {
+ logHandler.log(1, "gwtheader.missing", null);
+ }
+ } else {
+ int headerLineNo = 0;
+ int i;
+ for (i = 0; (headerLineNo < headerSize) && (i < fileSize); i++) {
+ boolean isMatch = isMatch(i, headerLineNo);
+ while (!isMatch && isMultiLine(headerLineNo)) {
+ headerLineNo++;
+ isMatch = (headerLineNo == headerSize) || isMatch(i, headerLineNo);
+ }
+ if (!isMatch) {
+ if (logHandler != null) {
+ logHandler.log(i + 1, "gwtheader.mismatch", getHeaderLines()[headerLineNo]);
+ }
+ break; // stop checking
+ }
+ if (!isMultiLine(headerLineNo)) {
+ headerLineNo++;
+ }
+ }
+ if (i == fileSize) {
+ // if file finished, but we have at least one non-multi-line
+ // header isn't completed
+ for (; headerLineNo < headerSize; headerLineNo++) {
+ if (!isMultiLine(headerLineNo)) {
+ if (logHandler != null) {
+ logHandler.log(1, "gwtheader.missing");
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setHeader(String aHeader) {
+ super.setHeader(aHeader);
+ initHeaderRegexps();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setHeaderFile(String aFileName) throws ConversionException {
+ super.setHeaderFile(aFileName);
+ initHeaderRegexps();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setMultiLines(int[] aList) {
+ if ((aList == null) || (aList.length == 0)) {
+ mMultiLines = EMPTY_INT_ARRAY;
+ return;
+ }
+
+ mMultiLines = new int[aList.length];
+ System.arraycopy(aList, 0, mMultiLines, 0, aList.length);
+ Arrays.sort(mMultiLines);
+ }
+
+ /**
+ * Initializes {@link #mHeaderRegexps} from {@link AbstractHeaderCheck#getHeaderLines()}.
+ */
+ private void initHeaderRegexps() {
+ final String[] headerLines = getHeaderLines();
+ if (headerLines != null) {
+ mHeaderRegexps = new Pattern[headerLines.length];
+ for (int i = 0; i < headerLines.length; i++) {
+ try {
+ // todo: Not sure if chache in Utils is still necessary
+ mHeaderRegexps[i] = Utils.getPattern(headerLines[i]);
+ } catch (final PatternSyntaxException ex) {
+ throw new ConversionException("line " + i + " in header specification"
+ + " is not a regular expression");
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if a code line matches the required header line.
+ *
+ * @param aLineNo the line number to check against the header
+ * @param aHeaderLineNo the header line number.
+ * @return true if and only if the line matches the required header line.
+ */
+ private boolean isMatch(int aLineNo, int aHeaderLineNo) {
+ final String line = getLines()[aLineNo];
+ return mHeaderRegexps[aHeaderLineNo].matcher(line).find();
+ }
+
+ /**
+ * @param aLineNo a line number
+ * @return if <code>aLineNo</code> is one of the repeat header lines.
+ */
+ private boolean isMultiLine(int aLineNo) {
+ return (Arrays.binarySearch(mMultiLines, aLineNo + 1) >= 0);
+ }
+}
\ No newline at end of file
diff --git a/build-tools/customchecks/src/com/google/gwt/checkstyle/GwtHeaderCheck.java b/build-tools/customchecks/src/com/google/gwt/checkstyle/GwtHeaderCheck.java
new file mode 100644
index 0000000..0457136
--- /dev/null
+++ b/build-tools/customchecks/src/com/google/gwt/checkstyle/GwtHeaderCheck.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.checkstyle;
+
+import com.google.gwt.checkstyle.CustomRegexpHeaderCheck.CustomLogHandler;
+
+import com.puppycrawl.tools.checkstyle.api.Check;
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+
+/**
+ * Checks the header against one of two header options, to support GWT's 80 and 100 column headers.
+ * <p>
+ * To use, set <code><property name="header" value="[regular expression]" /></code> and
+ * <code><property name="headerAlt" value="[alternate regular expression]" /></code>
+ */
+public class GwtHeaderCheck extends Check {
+ private CustomRegexpHeaderCheck regexpChecker = new CustomRegexpHeaderCheck();
+ private CustomRegexpHeaderCheck regexpCheckerAlt = new CustomRegexpHeaderCheck();
+
+ public void beginTree(DetailAST aRootAST) {
+ final boolean[] passedChecks = new boolean[]{true};
+ regexpChecker.setFileContents(this.getFileContents());
+ regexpChecker.doChecks(new CustomLogHandler() {
+ @Override
+ void log(int aLine, String aKey) {
+ passedChecks[0] = false;
+ }
+
+ @Override
+ void log(int aLine, String aKey, Object aObject) {
+ passedChecks[0] = false;
+ }
+ });
+ if (passedChecks[0]) {
+ // regexpChecker passed, no need to run alternate checker
+ return;
+ }
+
+ regexpCheckerAlt.setFileContents(this.getFileContents());
+ regexpCheckerAlt.doChecks(new CustomLogHandler() {
+ @Override
+ void log(int aLine, String aKey) {
+ GwtHeaderCheck.this.log(aLine, aKey);
+ }
+
+ @Override
+ void log(int aLine, String aKey, Object aObject) {
+ GwtHeaderCheck.this.log(aLine, aKey, aObject);
+ }
+ });
+ }
+
+ @Override
+ public int[] getDefaultTokens() {
+ return new int[0];
+ }
+
+ /**
+ * Set the header to check against. Individual lines in the header must be separated by '\n'
+ * characters.
+ *
+ * @param aHeader header content to check against.
+ */
+ public void setHeader(String aHeader) {
+ regexpChecker.setHeader(aHeader);
+ }
+
+ /**
+ * Set the alternate header to check against. Individual lines in the header must be separated by
+ * '\n' characters.
+ *
+ * @param aHeader header content to check against.
+ */
+ public void setHeaderAlt(String aHeader) {
+ regexpCheckerAlt.setHeader(aHeader);
+ }
+}
\ No newline at end of file
diff --git a/build-tools/customchecks/src/com/google/gwt/checkstyle/messages.properties b/build-tools/customchecks/src/com/google/gwt/checkstyle/messages.properties
new file mode 100644
index 0000000..149391c
--- /dev/null
+++ b/build-tools/customchecks/src/com/google/gwt/checkstyle/messages.properties
@@ -0,0 +1,2 @@
+gwtheader.missing=Missing a header - not enough lines in file.
+gwtheader.mismatch=Line does not match expected header line of ''{0}''.
\ No newline at end of file
diff --git a/eclipse/settings/code-style/gwt-checkstyle-tests.xml b/eclipse/settings/code-style/gwt-checkstyle-tests.xml
index 34ad279..d27c8e2 100644
--- a/eclipse/settings/code-style/gwt-checkstyle-tests.xml
+++ b/eclipse/settings/code-style/gwt-checkstyle-tests.xml
@@ -87,10 +87,11 @@
<property name="logLoadErrors" value="true"/>
<property name="tokens" value="METHOD_DEF"/>
</module>
- <module name="RegexpHeader">
- <property name="severity" value="error"/>
- <property name="header" value="/\*\n \* Copyright 20(0[6789]|[12][0-9]) Google Inc\.\n \*[ ]*\n \* Licensed under the Apache License, Version 2\.0 \(the "License"\); you may not\n \* use this file except in compliance with the License\. You may obtain a copy of\n \* the License at\n \*[ ]*\n \* http://www\.apache\.org/licenses/LICENSE-2\.0\n \*[ ]*\n \* Unless required by applicable law or agreed to in writing, software\n \* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n \* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\. See the\n \* License for the specific language governing permissions and limitations under\n \* the License\.\n \*/"/>
- </module>
+ <module name="com.google.gwt.checkstyle.GwtHeaderCheck">
+ <property name="severity" value="error"/>
+ <property name="header" value="/\*\n \* Copyright 20(0[6789]|[12][0-9]) Google Inc\.\n \*[ ]*\n \* Licensed under the Apache License, Version 2\.0 \(the "License"\); you may not\n \* use this file except in compliance with the License\. You may obtain a copy of\n \* the License at\n \*[ ]*\n \* http://www\.apache\.org/licenses/LICENSE-2\.0\n \*[ ]*\n \* Unless required by applicable law or agreed to in writing, software\n \* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n \* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\. See the\n \* License for the specific language governing permissions and limitations under\n \* the License\.\n \*/"/>
+ <property name="headerAlt" value="/\*\n \* Copyright 20(0[6789]|[12][0-9]) Google Inc\.\n \*[ ]*\n \* Licensed under the Apache License, Version 2\.0 \(the "License"\); you may not use this file except\n \* in compliance with the License\. You may obtain a copy of the License at\n \*[ ]*\n \* http://www\.apache\.org/licenses/LICENSE-2\.0\n \*[ ]*\n \* Unless required by applicable law or agreed to in writing, software distributed under the License\n \* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express\n \* or implied\. See the License for the specific language governing permissions and limitations under\n \* the License\.\n \*/"/>
+ </module>
<module name="ImportOrder">
<property name="severity" value="error"/>
<property name="groups" value="com.google, com, junit, net,org, java,javax"/>
diff --git a/eclipse/settings/code-style/gwt-checkstyle.xml b/eclipse/settings/code-style/gwt-checkstyle.xml
index 74607bb..c3c30d3 100644
--- a/eclipse/settings/code-style/gwt-checkstyle.xml
+++ b/eclipse/settings/code-style/gwt-checkstyle.xml
@@ -80,10 +80,11 @@
<property name="logLoadErrors" value="true"/>
<property name="tokens" value="METHOD_DEF"/>
</module>
- <module name="RegexpHeader">
- <property name="severity" value="error"/>
- <property name="header" value="/\*\n \* Copyright 20(0[6789]|[12][0-9]) Google Inc\.\n \*[ ]*\n \* Licensed under the Apache License, Version 2\.0 \(the "License"\); you may not\n \* use this file except in compliance with the License\. You may obtain a copy of\n \* the License at\n \*[ ]*\n \* http://www\.apache\.org/licenses/LICENSE-2\.0\n \*[ ]*\n \* Unless required by applicable law or agreed to in writing, software\n \* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n \* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\. See the\n \* License for the specific language governing permissions and limitations under\n \* the License\.\n \*/"/>
- </module>
+ <module name="com.google.gwt.checkstyle.GwtHeaderCheck">
+ <property name="severity" value="error"/>
+ <property name="header" value="/\*\n \* Copyright 20(0[6789]|[12][0-9]) Google Inc\.\n \*[ ]*\n \* Licensed under the Apache License, Version 2\.0 \(the "License"\); you may not\n \* use this file except in compliance with the License\. You may obtain a copy of\n \* the License at\n \*[ ]*\n \* http://www\.apache\.org/licenses/LICENSE-2\.0\n \*[ ]*\n \* Unless required by applicable law or agreed to in writing, software\n \* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n \* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\. See the\n \* License for the specific language governing permissions and limitations under\n \* the License\.\n \*/"/>
+ <property name="headerAlt" value="/\*\n \* Copyright 20(0[6789]|[12][0-9]) Google Inc\.\n \*[ ]*\n \* Licensed under the Apache License, Version 2\.0 \(the "License"\); you may not use this file except\n \* in compliance with the License\. You may obtain a copy of the License at\n \*[ ]*\n \* http://www\.apache\.org/licenses/LICENSE-2\.0\n \*[ ]*\n \* Unless required by applicable law or agreed to in writing, software distributed under the License\n \* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express\n \* or implied\. See the License for the specific language governing permissions and limitations under\n \* the License\.\n \*/"/>
+ </module>
<module name="ImportOrder">
<property name="severity" value="error"/>
<property name="groups" value="com.google, com, junit, net,org, java,javax"/>
diff --git a/eclipse/settings/code-style/gwt-customchecks.jar b/eclipse/settings/code-style/gwt-customchecks.jar
index b344d4c..1b51aa7 100644
--- a/eclipse/settings/code-style/gwt-customchecks.jar
+++ b/eclipse/settings/code-style/gwt-customchecks.jar
Binary files differ
diff --git a/eclipse/settings/code-style/gwt-format.xml b/eclipse/settings/code-style/gwt-format.xml
index e3b7569..b13daa7 100644
--- a/eclipse/settings/code-style/gwt-format.xml
+++ b/eclipse/settings/code-style/gwt-format.xml
@@ -64,7 +64,7 @@
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
-<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>