public boolean isDeprecated() { boolean deprecated = false; if (!mDeprecatedKnown) { boolean commentDeprecated = comment().isDeprecated(); boolean annotationDeprecated = false; for (AnnotationInstanceInfo annotation : annotations()) { if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) { annotationDeprecated = true; break; } } if (commentDeprecated != annotationDeprecated) { Errors.error( Errors.DEPRECATION_MISMATCH, position(), "Method " + mContainingClass.qualifiedName() + "." + name() + ": @Deprecated annotation and @deprecated doc tag do not match"); } mIsDeprecated = commentDeprecated | annotationDeprecated; mDeprecatedKnown = true; } return mIsDeprecated; }
public boolean isConsistent(MethodInfo mInfo) { boolean consistent = true; if (this.mReturnType != mInfo.mReturnType && !this.mReturnType.equals(mInfo.mReturnType)) { if (!mReturnType.isPrimitive() && !mInfo.mReturnType.isPrimitive()) { // Check to see if our class extends the old class. ApiInfo infoApi = mInfo.containingClass().containingPackage().containingApi(); ClassInfo infoReturnClass = infoApi.findClass(mInfo.mReturnType.qualifiedTypeName()); // Find the classes. consistent = infoReturnClass != null && infoReturnClass.isAssignableTo(mReturnType.qualifiedTypeName()); } else { consistent = false; } if (!consistent) { Errors.error( Errors.CHANGED_TYPE, mInfo.position(), "Method " + mInfo.qualifiedName() + " has changed return type from " + mReturnType + " to " + mInfo.mReturnType); } } if (mIsAbstract != mInfo.mIsAbstract) { consistent = false; Errors.error( Errors.CHANGED_ABSTRACT, mInfo.position(), "Method " + mInfo.qualifiedName() + " has changed 'abstract' qualifier"); } if (mIsNative != mInfo.mIsNative) { consistent = false; Errors.error( Errors.CHANGED_NATIVE, mInfo.position(), "Method " + mInfo.qualifiedName() + " has changed 'native' qualifier"); } if (!mIsStatic) { // Compiler-generated methods vary in their 'final' qualifier between versions of // the compiler, so this check needs to be quite narrow. A change in 'final' // status of a method is only relevant if (a) the method is not declared 'static' // and (b) the method is not already inferred to be 'final' by virtue of its class. if (!isEffectivelyFinal() && mInfo.isEffectivelyFinal()) { consistent = false; Errors.error( Errors.ADDED_FINAL, mInfo.position(), "Method " + mInfo.qualifiedName() + " has added 'final' qualifier"); } else if (isEffectivelyFinal() && !mInfo.isEffectivelyFinal()) { consistent = false; Errors.error( Errors.REMOVED_FINAL, mInfo.position(), "Method " + mInfo.qualifiedName() + " has removed 'final' qualifier"); } } if (mIsStatic != mInfo.mIsStatic) { consistent = false; Errors.error( Errors.CHANGED_STATIC, mInfo.position(), "Method " + mInfo.qualifiedName() + " has changed 'static' qualifier"); } if (!scope().equals(mInfo.scope())) { consistent = false; Errors.error( Errors.CHANGED_SCOPE, mInfo.position(), "Method " + mInfo.qualifiedName() + " changed scope from " + scope() + " to " + mInfo.scope()); } if (!isDeprecated() == mInfo.isDeprecated()) { Errors.error( Errors.CHANGED_DEPRECATED, mInfo.position(), "Method " + mInfo.qualifiedName() + " has changed deprecation state " + isDeprecated() + " --> " + mInfo.isDeprecated()); consistent = false; } // see JLS 3 13.4.20 "Adding or deleting a synchronized modifier of a method does not break " // "compatibility with existing binaries." /* if (mIsSynchronized != mInfo.mIsSynchronized) { Errors.error(Errors.CHANGED_SYNCHRONIZED, mInfo.position(), "Method " + mInfo.qualifiedName() + " has changed 'synchronized' qualifier from " + mIsSynchronized + " to " + mInfo.mIsSynchronized); consistent = false; } */ for (ClassInfo exception : thrownExceptions()) { if (!mInfo.throwsException(exception)) { // exclude 'throws' changes to finalize() overrides with no arguments if (!name().equals("finalize") || (!mParameters.isEmpty())) { Errors.error( Errors.CHANGED_THROWS, mInfo.position(), "Method " + mInfo.qualifiedName() + " no longer throws exception " + exception.qualifiedName()); consistent = false; } } } for (ClassInfo exec : mInfo.thrownExceptions()) { // exclude 'throws' changes to finalize() overrides with no arguments if (!throwsException(exec)) { if (!name().equals("finalize") || (!mParameters.isEmpty())) { Errors.error( Errors.CHANGED_THROWS, mInfo.position(), "Method " + mInfo.qualifiedName() + " added thrown exception " + exec.qualifiedName()); consistent = false; } } } return consistent; }
public ParamTagInfo[] paramTags() { if (mParamTags == null) { final int N = mParameters.size(); String[] names = new String[N]; String[] comments = new String[N]; SourcePositionInfo[] positions = new SourcePositionInfo[N]; // get the right names so we can handle our names being different from // our parent's names. int i = 0; for (ParameterInfo param : mParameters) { names[i] = param.name(); comments[i] = ""; positions[i] = param.position(); i++; } // gather our comments, and complain about misnamed @param tags for (ParamTagInfo tag : comment().paramTags()) { int index = indexOfParam(tag.parameterName(), names); if (index >= 0) { comments[index] = tag.parameterComment(); positions[index] = tag.position(); } else { Errors.error( Errors.UNKNOWN_PARAM_TAG_NAME, tag.position(), "@param tag with name that doesn't match the parameter list: '" + tag.parameterName() + "'"); } } // get our parent's tags to fill in the blanks MethodInfo overridden = this.findOverriddenMethod(name(), signature()); if (overridden != null) { ParamTagInfo[] maternal = overridden.paramTags(); for (i = 0; i < N; i++) { if (comments[i].equals("")) { comments[i] = maternal[i].parameterComment(); positions[i] = maternal[i].position(); } } } // construct the results, and cache them for next time mParamTags = new ParamTagInfo[N]; for (i = 0; i < N; i++) { mParamTags[i] = new ParamTagInfo( "@param", "@param", names[i] + " " + comments[i], parent(), positions[i]); // while we're here, if we find any parameters that are still undocumented at this // point, complain. (this warning is off by default, because it's really, really // common; but, it's good to be able to enforce it) if (comments[i].equals("")) { Errors.error( Errors.UNDOCUMENTED_PARAMETER, positions[i], "Undocumented parameter '" + names[i] + "' on method '" + name() + "'"); } } } return mParamTags; }