diff --git a/docs/releasenotes.html b/docs/releasenotes.html
index e558129a3..c867c6744 100644
--- a/docs/releasenotes.html
+++ b/docs/releasenotes.html
@@ -286,8 +286,9 @@
Changed HideUtiliyConstructor behaviour for classes
that do not extend java.lang.Object directly (partial fix for bug 824754)
- Added Checker.removeListener() (fix for
- 834367)
+ False alarms for abstract classes from FinalClass (bug 837012)
+
+ Added Checker.removeListener() (fix for 834367)
diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/FinalClassCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/FinalClassCheck.java
index be4c22c55..746934ade 100644
--- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/FinalClassCheck.java
+++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/design/FinalClassCheck.java
@@ -54,10 +54,11 @@ public class FinalClassCheck
final DetailAST modifiers = aAST.findFirstToken(TokenTypes.MODIFIERS);
if (aAST.getType() == TokenTypes.CLASS_DEF) {
- final boolean isFinal =
- (modifiers != null)
+ final boolean isFinal = (modifiers != null)
&& modifiers.branchContains(TokenTypes.FINAL);
- mClasses.push(new ClassDesc(isFinal));
+ final boolean isAbstract = (modifiers != null)
+ && modifiers.branchContains(TokenTypes.ABSTRACT);
+ mClasses.push(new ClassDesc(isFinal, isAbstract));
}
else {
final ClassDesc desc = (ClassDesc) mClasses.peek();
@@ -81,6 +82,7 @@ public class FinalClassCheck
final ClassDesc desc = (ClassDesc) mClasses.pop();
if (!desc.isDeclaredAsFinal()
+ && !desc.isDeclaredAsAbstract()
&& desc.hasPrivateCtor()
&& !desc.hasNonPrivateCtor())
{
@@ -96,6 +98,9 @@ public class FinalClassCheck
/** is class declared as final */
private final boolean mDeclaredAsFinal;
+ /** is class declared as abstract */
+ private final boolean mDeclaredAsAbstract;
+
/** does class have non-provate ctors */
private boolean mHasNonPrivateCtor;
@@ -103,29 +108,32 @@ public class FinalClassCheck
private boolean mHasPrivateCtor;
/**
- * create a new ClassDesc instance
+ * create a new ClassDesc instance.
* @param aDeclaredAsFinal indicates if the
* class declared as final
+ * @param aDeclaredAsAbstract indicates if the
+ * class declared as abstract
*/
- ClassDesc(boolean aDeclaredAsFinal)
+ ClassDesc(boolean aDeclaredAsFinal, boolean aDeclaredAsAbstract)
{
mDeclaredAsFinal = aDeclaredAsFinal;
+ mDeclaredAsAbstract = aDeclaredAsAbstract;
}
- /** adds private ctor */
+ /** adds private ctor. */
void reportPrivateCtor()
{
mHasPrivateCtor = true;
}
- /** adds non-private ctor */
+ /** adds non-private ctor. */
void reportNonPrivateCtor()
{
mHasNonPrivateCtor = true;
}
/**
- * does class have private ctors
+ * does class have private ctors.
* @return true if class has private ctors
*/
boolean hasPrivateCtor()
@@ -134,7 +142,7 @@ public class FinalClassCheck
}
/**
- * does class have non-private ctors
+ * does class have non-private ctors.
* @return true if class has non-private ctors
*/
boolean hasNonPrivateCtor()
@@ -143,7 +151,7 @@ public class FinalClassCheck
}
/**
- * is class declared as final
+ * is class declared as final.
* @return true if class is declared as final
*/
boolean isDeclaredAsFinal()
@@ -151,14 +159,28 @@ public class FinalClassCheck
return mDeclaredAsFinal;
}
+ /**
+ * is class declared as abstract.
+ * @return true if class is declared as final
+ */
+ boolean isDeclaredAsAbstract()
+ {
+ return mDeclaredAsAbstract;
+ }
+
/**
* Returns a string representation of the object.
* @return a string representation of the object
*/
public String toString()
{
- return "decl=" + mDeclaredAsFinal + "; pctor=" + mHasPrivateCtor
- + "; ctor=" + mHasNonPrivateCtor;
+ return this.getClass().getName()
+ + "["
+ + "final=" + mDeclaredAsFinal
+ + " abstract=" + mDeclaredAsAbstract
+ + " pctor=" + mHasPrivateCtor
+ + " ctor=" + mHasNonPrivateCtor
+ + "]";
}
}
}
diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/InputFinalClass.java b/src/testinputs/com/puppycrawl/tools/checkstyle/InputFinalClass.java
index b80c3be7e..92dda2745 100644
--- a/src/testinputs/com/puppycrawl/tools/checkstyle/InputFinalClass.java
+++ b/src/testinputs/com/puppycrawl/tools/checkstyle/InputFinalClass.java
@@ -28,3 +28,70 @@ class test6
{
public test6() {}
}
+
+// Typesafe enum with operation
+// abstract classes cannot be final, see bug #837012
+abstract class Operation
+{
+ abstract double eval(double a, double b);
+
+ public static final Operation PLUS =
+ new Operation("+")
+ {
+ double eval(double a, double b)
+ {
+ return a + b;
+ }
+ };
+
+ public static final Operation MINUS =
+ new Operation("-")
+ {
+ double eval(double a, double b)
+ {
+ return a - b;
+ }
+ };
+
+ private String _name;
+ private Operation(String name)
+ {
+ this._name = name;
+ }
+}
+
+// Typesafe enum with operation
+// abstract classes cannot be final, see bug #837012
+interface Evaluatable
+{
+ double eval(double a, double b);
+}
+
+// abstract class without it's own abstract method decl
+abstract class Operation2 implements Evaluatable
+{
+
+ public static final Operation2 PLUS =
+ new Operation2("+")
+ {
+ double eval(double a, double b)
+ {
+ return a + b;
+ }
+ };
+
+ public static final Operation2 MINUS =
+ new Operation2("-")
+ {
+ double eval(double a, double b)
+ {
+ return a - b;
+ }
+ };
+
+ private String _name;
+ private Operation2(String name)
+ {
+ this._name = name;
+ }
+}