From 4880b50a3a89db93e7e7c1b8bae8036ec06e186b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20K=C3=BChne?= Date: Wed, 18 Sep 2002 05:08:34 +0000 Subject: [PATCH] improved resource bundle handling: - plugins can use their own bundle (location determined automatically) - return the message key if ResourceBundle is not available - added log helper methods in Check.java --- .../puppycrawl/tools/checkstyle/Checker.java | 10 +- .../tools/checkstyle/api/Check.java | 124 ++++++++++++++++-- .../checkstyle/api/LocalizedMessage.java | 47 +++++-- .../checkstyle/api/LocalizedMessages.java | 34 ++++- .../puppycrawl/tools/checkstyle/java_new.g | 33 ++++- 5 files changed, 216 insertions(+), 32 deletions(-) diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java index 3252ea5f4..bf75cf428 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/Checker.java @@ -224,21 +224,21 @@ public class Checker } catch (FileNotFoundException fnfe) { errors = new LocalizedMessage[] { - new LocalizedMessage(0, "general.fileNotFound", null)}; + new LocalizedMessage(0, "general.fileNotFound", null, null)}; } catch (IOException ioe) { errors = new LocalizedMessage[] { - new LocalizedMessage(0, "general.exception", + new LocalizedMessage(0, "general.exception", null, new String[] {ioe.getMessage()})}; } catch (RecognitionException re) { errors = new LocalizedMessage[] { - new LocalizedMessage(0, "general.exception", + new LocalizedMessage(0, "general.exception", null, new String[] {re.getMessage()})}; } catch (TokenStreamException te) { errors = new LocalizedMessage[] { - new LocalizedMessage(0, "general.exception", + new LocalizedMessage(0, "general.exception", null, new String[] {te.getMessage()})}; } @@ -276,7 +276,7 @@ public class Checker fireFileStarted(docFile); if (!packageDoc.exists()) { final LocalizedMessage error = - new LocalizedMessage(0, "javadoc.packageHtml", null); + new LocalizedMessage(0, "javadoc.packageHtml", null, null); fireErrors(docFile, new LocalizedMessage[]{error}); packageHtmlErrors++; } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java index 8fcbbd6d7..0c70585e4 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/Check.java @@ -28,6 +28,9 @@ import java.util.Map; */ public abstract class Check { + /** resuable constant for message formating */ + private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + /** name to store lines under */ private static final String LINES_ATTRIBUTE = "lines"; /** name to store filename under */ @@ -170,7 +173,7 @@ public abstract class Check * Set the lines associated with the tree. * @param aLines the file contents */ - public void setLines(String[] aLines) + public final void setLines(String[] aLines) { getTreeContext().put(LINES_ATTRIBUTE, aLines); } @@ -179,7 +182,7 @@ public abstract class Check * Returns the lines associated with the tree. * @return the file contents */ - public String[] getLines() + protected final String[] getLines() { return (String[]) getTreeContext().get(LINES_ATTRIBUTE); } @@ -188,7 +191,7 @@ public abstract class Check * Set the name of the file associated with the tree. * @param aFilename the file name */ - public void setFilename(String aFilename) + public final void setFilename(String aFilename) { getTreeContext().put(FILENAME_ATTRIBUTE, aFilename); } @@ -197,15 +200,120 @@ public abstract class Check * Returns the filename associated with the tree. * @return the file name */ - public String getFilename() + protected final String getFilename() { return (String) getTreeContext().get(FILENAME_ATTRIBUTE); } - /** @see needs to be fixed */ - public void log(int aLine, String aMessage) + /** + * Log an error message. + * + * @param aLine the line number where the error was found + * @param aKey the message that describes the error + */ + protected final void log(int aLine, String aKey) { - final String fname = (String) getTreeContext().get(FILENAME_ATTRIBUTE); - System.out.println(fname + ":" + aLine + ": " + aMessage); + log(aLine, aKey, EMPTY_OBJECT_ARRAY); + } + + /** + * Log an error message. + * + * @param aLine the line number where the error was found + * @param aKey the message that describes the error + * @param aArgs the details of the message + * + * @see java.text.MessageFormat + */ + protected final void log(int aLine, String aKey, Object aArgs[]) + { + log(aLine, 0, aKey, aArgs); + } + + + /** + * Helper method to log a LocalizedMessage. Column defaults to 0. + * + * @param aLineNo line number to associate with the message + * @param aKey key to locale message format + * @param aArg0 first argument + */ + public void log(int aLineNo, String aKey, Object aArg0) + { + log(aLineNo, aKey, new Object[] {aArg0}); + } + + /** + * Helper method to log a LocalizedMessage. Column defaults to 0. + * + * @param aLineNo line number to associate with the message + * @param aKey key to locale message format + * @param aArg0 first argument + * @param aArg1 second argument + */ + public void log(int aLineNo, String aKey, Object aArg0, Object aArg1) + { + log(aLineNo, aKey, new Object[] {aArg0, aArg1}); + } + + /** + * Helper method to log a LocalizedMessage. Column defaults to 0. + * + * @param aLineNo line number to associate with the message + * @param aKey key to locale message format + * @param aArg0 first argument + * @param aArg1 second argument + * @param aArg2 third argument + */ + public void log(int aLineNo, String aKey, + Object aArg0, Object aArg1, Object aArg2) + { + log(aLineNo, aKey, new Object[] {aArg0, aArg1, aArg2}); + } + + + /** + * Helper method to log a LocalizedMessage. + * + * @param aLineNo line number to associate with the message + * @param aColNo column number to associate with the message + * @param aKey key to locale message format + * @param aArgs arguments for message + */ + public void log(int aLineNo, int aColNo, String aKey, Object[] aArgs) + { + final String fname = getFilename(); + System.out.println(fname + ":" + aLineNo + ": " + aKey); + + final int col = aColNo + 1; +// final int col = 1 + Utils.lengthExpandedTabs( +// mLines[aLineNo - 1], aColNo, mTabWidth); + mMessages.add(new LocalizedMessage( + aLineNo, col, getResourceBundle(), aKey, aArgs)); + } + + + /** + * TODO: Should this method be protected or should we keep the api simple? + * Returns the name of a a resource bundle that contains the messages + * used by this check. + * + * The default implementation expects the resource files to be named + * messages.properties, messages_de.properties, etc. The file should + * be placed in the same package as the Check implementation. + * + * Example: If you write com/foo/MyCoolCheck, create resource files + * com/foo/messages.properties, com/foo/messages_de.properties, etc. + * + * @return name of a resource bundle that contains the messages + * used by this check + */ + private String getResourceBundle() + { + // PERF: check perf impact, maybe cache result + final String className = this.getClass().getName(); + final String packageName = + className.substring(className.lastIndexOf('.') + 1); + return packageName + "." + "messages"; } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/LocalizedMessage.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/LocalizedMessage.java index 24225b530..9bcae5f28 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/LocalizedMessage.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/LocalizedMessage.java @@ -18,8 +18,13 @@ //////////////////////////////////////////////////////////////////////////////// package com.puppycrawl.tools.checkstyle.api; +// TODO: check that this class is in the right package +// as soon as architecture has settled. At the time of writing +// this class is not necessary as a part of the public api + import java.util.ResourceBundle; import java.util.Locale; +import java.util.MissingResourceException; import java.text.MessageFormat; /** @@ -33,10 +38,6 @@ import java.text.MessageFormat; public class LocalizedMessage implements Comparable { - /** name of the resource bundle to get messages from **/ - private static final String MESSAGE_BUNDLE = - "com.puppycrawl.tools.checkstyle.messages"; - /** the locale to localise messages to **/ private static Locale sLocale = Locale.getDefault(); @@ -51,16 +52,22 @@ public class LocalizedMessage /** arguments for MessageFormat **/ private final Object[] mArgs; + /** name of the resource bundle to get messages from **/ + private final String mBundle; + + /** * Creates a new LocalizedMessage instance. * * @param aLineNo line number associated with the message * @param aColNo column number associated with the message + * @param aBundle resource bundle name * @param aKey the key to locate the translation * @param aArgs arguments for the translation */ public LocalizedMessage(int aLineNo, int aColNo, + String aBundle, String aKey, Object[] aArgs) { @@ -68,6 +75,7 @@ public class LocalizedMessage mColNo = aColNo; mKey = aKey; mArgs = aArgs; + mBundle = aBundle; } /** @@ -75,25 +83,36 @@ public class LocalizedMessage * defaults to 0. * * @param aLineNo line number associated with the message + * @param aBundle name of a resource bundle that contains error messages * @param aKey the key to locate the translation * @param aArgs arguments for the translation */ - public LocalizedMessage(int aLineNo, String aKey, Object[] aArgs) + public LocalizedMessage( + int aLineNo, String aBundle, String aKey, Object[] aArgs) { - this(aLineNo, 0, aKey, aArgs); + this(aLineNo, 0, aBundle, aKey, aArgs); } /** @return the translated message **/ public String getMessage() { - // Very simple approach - wait for performance problems. - // Important to use the default class loader, and not the one in the - // Configuration object. This is because the class loader in the - // Configuration is specified by the user for resolving custom classes. - final ResourceBundle bundle = - ResourceBundle.getBundle(MESSAGE_BUNDLE, sLocale); - final String pattern = bundle.getString(mKey); - return MessageFormat.format(pattern, mArgs); + try { + // PERF: Very simple approach - wait for performance problems. + // Important to use the default class loader, and not the one in the + // Configuration object. This is because the class loader in the + // Configuration is specified by the user for resolving custom + // classes. + final ResourceBundle bundle = + ResourceBundle.getBundle(mBundle, sLocale); + final String pattern = bundle.getString(mKey); + return MessageFormat.format(pattern, mArgs); + } + catch (MissingResourceException ex) { + // If the Check author didn't provide i18n resource bundles + // and logs error messages directly, this will return + // the author's original message + return MessageFormat.format(mKey, mArgs); + } } /** @return the line number **/ diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/LocalizedMessages.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/LocalizedMessages.java index de0209a32..ec20e6e09 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/api/LocalizedMessages.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/api/LocalizedMessages.java @@ -18,6 +18,10 @@ //////////////////////////////////////////////////////////////////////////////// package com.puppycrawl.tools.checkstyle.api; +// TODO: check that this class is in the right package +// as soon as architecture has settled. At the time of writing +// this class is not necessary as a part of the public api + import java.util.Collections; import java.util.ArrayList; @@ -34,6 +38,8 @@ public class LocalizedMessages private final int mTabWidth; /** the lines of the file being checked **/ private String[] mLines; + private static final String OLD_BUNDLE = + "com.puppycrawl.tools.checkstyle.messages"; /** * Creates a new LocalizedMessages instance. @@ -75,16 +81,21 @@ public class LocalizedMessages mMessages.add(aMsg); } + // TODO: remove the add() methods below and the OLD_BUNDLE constant + // this has to wait until they are not referenced by Verifier any more + /** * Helper method to log a LocalizedMessage. Column defaults to 0. * * @param aLineNo line number to associate with the message * @param aKey key to locale message format * @param aArgs arguments for message + * + * @deprecated replaced by Check.log() */ public void add(int aLineNo, String aKey, Object[] aArgs) { - add(new LocalizedMessage(aLineNo, 0, aKey, aArgs)); + add(new LocalizedMessage(aLineNo, 0, OLD_BUNDLE, aKey, aArgs)); } /** @@ -92,6 +103,8 @@ public class LocalizedMessages * * @param aLineNo line number to associate with the message * @param aKey key to locale message format + * + * @deprecated replaced by Check.log() */ public void add(int aLineNo, String aKey) { @@ -104,6 +117,8 @@ public class LocalizedMessages * @param aLineNo line number to associate with the message * @param aKey key to locale message format * @param aArg0 first argument + * + * @deprecated replaced by Check.log() */ public void add(int aLineNo, String aKey, Object aArg0) { @@ -117,6 +132,8 @@ public class LocalizedMessages * @param aKey key to locale message format * @param aArg0 first argument * @param aArg1 second argument + * + * @deprecated replaced by Check.log() */ public void add(int aLineNo, String aKey, Object aArg0, Object aArg1) { @@ -131,6 +148,8 @@ public class LocalizedMessages * @param aArg0 first argument * @param aArg1 second argument * @param aArg2 third argument + * + * @deprecated replaced by Check.log() */ public void add(int aLineNo, String aKey, Object aArg0, Object aArg1, Object aArg2) @@ -145,12 +164,15 @@ public class LocalizedMessages * @param aColNo column number to associate with the message * @param aKey key to locale message format * @param aArgs arguments for message + * + * @deprecated replaced by Check.log() */ public void add(int aLineNo, int aColNo, String aKey, Object[] aArgs) { final int col = 1 + Utils.lengthExpandedTabs( mLines[aLineNo - 1], aColNo, mTabWidth); - mMessages.add(new LocalizedMessage(aLineNo, col, aKey, aArgs)); + mMessages.add( + new LocalizedMessage(aLineNo, col, OLD_BUNDLE, aKey, aArgs)); } /** @@ -159,6 +181,8 @@ public class LocalizedMessages * @param aLineNo line number to associate with the message * @param aColNo column number to associate with the message * @param aKey key to locale message format + * + * @deprecated replaced by Check.log() */ public void add(int aLineNo, int aColNo, String aKey) { @@ -172,6 +196,8 @@ public class LocalizedMessages * @param aColNo column number to associate with the message * @param aKey key to locale message format * @param aArg0 first argument + * + * @deprecated replaced by Check.log() */ public void add(int aLineNo, int aColNo, String aKey, Object aArg0) { @@ -186,6 +212,8 @@ public class LocalizedMessages * @param aKey key to locale message format * @param aArg0 first argument * @param aArg1 second argument + * + * @deprecated replaced by Check.log() */ public void add(int aLineNo, int aColNo, String aKey, Object aArg0, Object aArg1) @@ -202,6 +230,8 @@ public class LocalizedMessages * @param aArg0 first argument * @param aArg1 second argument * @param aArg2 third argument + * + * @deprecated replaced by Check.log() */ void add(int aLineNo, int aColNo, String aKey, Object aArg0, Object aArg1, Object aArg2) diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/java_new.g b/src/checkstyle/com/puppycrawl/tools/checkstyle/java_new.g index 8cf10ddaa..e0b9bb67a 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/java_new.g +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/java_new.g @@ -51,6 +51,7 @@ tokens { STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL; } + // Compilation Unit: In Java, this is a single file. This is the start // rule for this parser compilationUnit @@ -927,6 +928,24 @@ options { codeGenBitsetTestThreshold=20; } +// JavaLexer verbatim source code +{ + + // explicitly set tab width to 1 (default in ANTLR 2.7.1) + // in ANTLR 2.7.2a2 the default has changed from 1 to 8 + public void tab() + { + setColumn( getColumn() + 1 ); + } + + private CommentManager mCommentManager = null; + + void setCommentManager(CommentManager aCommentManager) + { + mCommentManager = aCommentManager; + } + +} // OPERATORS @@ -995,14 +1014,18 @@ WS : ( ' ' // Single-line comments SL_COMMENT - : "//" + : "//" { mCommentManager.reportCPPComment(getLine(), getColumn() - 3); } (~('\n'|'\r'))* ('\n'|'\r'('\n')?) {$setType(Token.SKIP); newline();} ; // multiple-line comments ML_COMMENT - : "/*" +{ + int startLine; + int startCol; +} + : "/*" { startLine = getLine(); startCol = getColumn() - 3; } ( /* '\r' '\n' can be matched in one alternative or by matching '\r' in one iteration and '\n' in another. I am trying to handle any flavor of newline that comes in, but the language @@ -1021,7 +1044,11 @@ ML_COMMENT | ~('*'|'\n'|'\r') )* "*/" - {$setType(Token.SKIP);} + { + mCommentManager.reportCComment(startLine, startCol, + getLine(), getColumn() - 2); + $setType(Token.SKIP); + } ;