diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractTypeAwareCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractTypeAwareCheck.java index bff10abc3..b29487e2a 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractTypeAwareCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/AbstractTypeAwareCheck.java @@ -184,6 +184,27 @@ public abstract class AbstractTypeAwareCheck } } + /** + * Tries to load class. Logs error if unable. + * @param aIdent name of class which we try to load. + * @return Class for a ident. + */ + protected final Class tryLoadClass(FullIdent aIdent) + { + Class clazz = resolveClass(aIdent.getText()); + if (clazz == null) { + logLoadError(aIdent); + } + return clazz; + } + + /** + * Logs error if unable to load class information. + * Abstract, should be overrided in subclasses. + * @param aIdent class name for which we can no load class. + */ + protected abstract void logLoadError(FullIdent aIdent); + /** * Collects the details of a package. * @param aAST node containing the package details @@ -210,7 +231,7 @@ public abstract class AbstractTypeAwareCheck * Contains class's FullIdent * and Class object if we can load it. */ - protected static class ClassInfo + protected class ClassInfo { /** FullIdent associated with this class. */ private FullIdent mName; @@ -264,6 +285,9 @@ public abstract class AbstractTypeAwareCheck /** @return Class associated with an object. */ public final Class getClazz() { + if (isLoadable() && mClass == null) { + setClazz(AbstractTypeAwareCheck.this.tryLoadClass(getName())); + } return mClass; } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/RedundantThrowsCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/RedundantThrowsCheck.java index 63663d754..566a56fb3 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/RedundantThrowsCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/coding/RedundantThrowsCheck.java @@ -111,6 +111,16 @@ public class RedundantThrowsCheck } } + /** + * Logs error if unable to load class information. + * @param aIdent class name for which we can no load class. + */ + protected final void logLoadError(FullIdent aIdent) + { + log(aIdent.getLineNo(), aIdent.getColumnNo(), + "redundant.throws.classInfo", aIdent.getText()); + } + /** * Checks if an exception is already know (list of known * exceptions contains it or its superclass) and it's not @@ -125,19 +135,11 @@ public class RedundantThrowsCheck */ private void checkException(FullIdent aExc, List aKnownExcs) { - // Let's trye to load class. - Class excClass = null; - - if (!mAllowUnchecked || !mAllowSubclasses) { - excClass = resolveClass(aExc.getText()); - if (excClass == null) { - log(aExc.getLineNo(), aExc.getColumnNo(), - "redundant.throws.classInfo", aExc.getText()); - } - } + // Let's try to load class. + ClassInfo newClassInfo = new ClassInfo(aExc); if (!mAllowUnchecked) { - if (isUnchecked(excClass)) { + if (isUnchecked(newClassInfo.getClazz())) { log(aExc.getLineNo(), aExc.getColumnNo(), "redundant.throws.unchecked", aExc.getText()); } @@ -154,13 +156,13 @@ public class RedundantThrowsCheck "redundant.throws.duplicate", aExc.getText()); } else if (!mAllowSubclasses) { - if (isSubclass(ci.getClazz(), excClass)) { + if (isSubclass(ci.getClazz(), newClassInfo.getClazz())) { known.remove(); log(fi.getLineNo(), fi.getColumnNo(), "redundant.throws.subclass", fi.getText(), aExc.getText()); } - else if (isSubclass(excClass, ci.getClazz())) { + else if (isSubclass(newClassInfo.getClazz(), ci.getClazz())) { shouldAdd = false; log(aExc.getLineNo(), aExc.getColumnNo(), "redundant.throws.subclass", @@ -170,7 +172,7 @@ public class RedundantThrowsCheck } if (shouldAdd) { - aKnownExcs.add(new ClassInfo(aExc, excClass)); + aKnownExcs.add(newClassInfo); } } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocMethodCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocMethodCheck.java index 400d08b2a..c5f6b9217 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocMethodCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocMethodCheck.java @@ -572,15 +572,7 @@ public class JavadocMethodCheck final String documentedEx = tag.getArg1(); boolean found = foundThrows.contains(documentedEx); Class documentedClass = null; - if (!found - && (mAllowThrowsTagsForSubclasses || mAllowUndeclaredRTE)) - { - documentedClass = resolveClass(documentedEx); - if (documentedClass == null) { - log(tag.getLineNo(), "javadoc.classInfo", - "@throws", documentedEx); - } - } + boolean classLoaded = false; final ListIterator throwIt = aThrows.listIterator(); while (!found && throwIt.hasNext()) { @@ -592,19 +584,11 @@ public class JavadocMethodCheck ei.setFound(); foundThrows.add(documentedEx); } - else if (mAllowThrowsTagsForSubclasses - && documentedClass != null) - { - if (ei.isLoadable() && ei.getClazz() == null) { - // if the class is not loaded yet. - // try to load it. - ei.setClazz(resolveClass(declaredEx)); - if (!ei.isLoadable()) { - log(fi.getLineNo(), "javadoc.classInfo", - "@throws", declaredEx); - } + else if (mAllowThrowsTagsForSubclasses) { + if (!classLoaded) { + documentedClass = loadClassForTag(tag); + classLoaded = true; } - found = isSubclass(documentedClass, ei.getClazz()); if (found) { ei.setFound(); @@ -615,7 +599,11 @@ public class JavadocMethodCheck // Handle extra JavadocTag. if (!found) { boolean reqd = true; - if (mAllowUndeclaredRTE && documentedClass != null) { + if (mAllowUndeclaredRTE) { + if (!classLoaded) { + documentedClass = loadClassForTag(tag); + classLoaded = true; + } reqd = !isUnchecked(documentedClass); } @@ -641,8 +629,33 @@ public class JavadocMethodCheck } } + /** + * Tries to load class for throws tag. Logs error if unable. + * @param aTag name of class which we try to load. + * @return Class for the tag. + */ + private Class loadClassForTag(JavadocTag aTag) + { + Class clazz = resolveClass(aTag.getArg1()); + if (clazz == null) { + log(aTag.getLineNo(), "javadoc.classInfo", + "@throws", aTag.getArg1()); + } + return clazz; + } + + /** + * Logs error if unable to load class information. + * @param aIdent class name for which we can no load class. + */ + protected final void logLoadError(FullIdent aIdent) + { + log(aIdent.getLineNo(), "javadoc.classInfo", "@throws", + aIdent.getText()); + } + /** Stores useful information about declared exception. */ - static class ExceptionInfo extends ClassInfo + class ExceptionInfo extends ClassInfo { /** does the exception have throws tag associated with. */ private boolean mFound; diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/InputTags.java b/src/testinputs/com/puppycrawl/tools/checkstyle/InputTags.java index 5d79ff2f9..4bd8ea74e 100644 --- a/src/testinputs/com/puppycrawl/tools/checkstyle/InputTags.java +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/InputTags.java @@ -239,4 +239,11 @@ class InputTags throws IOException { } + + /** + * @exception WrongException exception w/o class info but matched by name + */ + void method23() throws WrongException + { + } } diff --git a/src/tests/com/puppycrawl/tools/checkstyle/checks/coding/RedundantThrowsCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/coding/RedundantThrowsCheckTest.java index 943c1f69d..0302cf135 100644 --- a/src/tests/com/puppycrawl/tools/checkstyle/checks/coding/RedundantThrowsCheckTest.java +++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/coding/RedundantThrowsCheckTest.java @@ -31,7 +31,6 @@ public class RedundantThrowsCheckTest final String[] expected = { "7:37: Redundant throws: 'java.io.FileNotFoundException' is subclass of 'java.io.IOException'.", "19:29: Redundant throws: 'java.io.IOException' listed more then one time.", - "25:16: Unable to get class information for WrongException.", "35:27: Unable to get class information for WrongException.", "39:27: Redundant throws: 'NullPointerException' is subclass of 'RuntimeException'.", };