[Clirr-devel] CVS: clirr/src/java/net/sf/clirr/checks ClassModifierCheck.java,1.9,1.10
Status: Alpha
Brought to you by:
lkuehne
From: Simon K. <s_k...@us...> - 2004-06-21 07:27:07
|
Update of /cvsroot/clirr/clirr/src/java/net/sf/clirr/checks In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14085 Modified Files: ClassModifierCheck.java Log Message: Implemented TODO item: it is not an error to add final to a class if that class previously had no public or protected constructors. Index: ClassModifierCheck.java =================================================================== RCS file: /cvsroot/clirr/clirr/src/java/net/sf/clirr/checks/ClassModifierCheck.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- ClassModifierCheck.java 18 Jun 2004 06:52:10 -0000 1.9 +++ ClassModifierCheck.java 21 Jun 2004 07:26:58 -0000 1.10 @@ -23,7 +23,11 @@ import net.sf.clirr.framework.AbstractDiffReporter; import net.sf.clirr.framework.ApiDiffDispatcher; import net.sf.clirr.framework.ClassChangeCheck; +import net.sf.clirr.framework.CheckerException; +import net.sf.clirr.event.ScopeSelector; + import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; /** * Detects changes in class modifiers (abstract, final). @@ -46,6 +50,25 @@ /** {@inheritDoc} */ public boolean check(JavaClass compatBaseLine, JavaClass currentVersion) { + final String className = compatBaseLine.getClassName(); + + try + { + ScopeSelector.Scope currentScope = ScopeSelector.getClassScope(currentVersion); + if (currentScope == ScopeSelector.SCOPE_PRIVATE) + { + // for private classes, we don't care if they are now final, + // or now abstract, or now an interface. + return true; + } + } + catch (CheckerException ex) + { + log("Unable to determine whether class is private", + Severity.ERROR, className, null, null); + return true; + } + final boolean currentIsFinal = currentVersion.isFinal(); final boolean compatIsFinal = compatBaseLine.isFinal(); final boolean currentIsAbstract = currentVersion.isAbstract(); @@ -53,13 +76,6 @@ final boolean currentIsInterface = currentVersion.isInterface(); final boolean compatIsInterface = compatBaseLine.isInterface(); - final String className = compatBaseLine.getClassName(); - - // TODO: There are cases when nonfinal classes are effectively final - // because they do not have public or protected ctors. For such - // classes we should not emit errors when a final modifier is - // introduced. - if (compatIsFinal && !currentIsFinal) { log("Removed final modifier in class " + className, @@ -67,8 +83,17 @@ } else if (!compatIsFinal && currentIsFinal) { - log("Added final modifier in class " + className, - Severity.ERROR, className, null, null); + if (isEffectivelyFinal(compatBaseLine)) + { + log("Added final modifier in class " + className + + " (but class was effectively final anyway)", + Severity.INFO, className, null, null); + } + else + { + log("Added final modifier in class " + className, + Severity.ERROR, className, null, null); + } } // interfaces are always abstract, don't report gender change here @@ -86,4 +111,36 @@ return true; } + /** + * There are cases where nonfinal classes are effectively final + * because they do not have public or protected ctors. For such + * classes we should not emit errors when a final modifier is + * introduced. + */ + private boolean isEffectivelyFinal(JavaClass clazz) + { + if (clazz.isFinal()) + { + return true; + } + + // iterate over all constructors, and detect whether any are + // public or protected. If so, return false. + Method[] methods = clazz.getMethods(); + for (int i = 0; i < methods.length; ++i) + { + Method method = methods[i]; + final String methodName = method.getName(); + if (methodName.equals("<init>")) + { + if (method.isPublic() || method.isProtected()) + { + return false; + } + } + } + + // no public or protected constructor found + return true; + } } |