| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.apicheck; |
| import java.util.*; |
| |
| public class MethodInfo implements AbstractMethodInfo { |
| |
| private String mName; |
| private String mReturn; |
| private boolean mIsAbstract; |
| private boolean mIsNative; |
| private boolean mIsSynchronized; |
| private boolean mIsStatic; |
| private boolean mIsFinal; |
| private String mDeprecated; |
| private String mScope; |
| private boolean mExistsInBoth; |
| private List<ParameterInfo> mParameters; |
| private List<String> mExceptions; |
| private SourcePositionInfo mSourcePosition; |
| private ClassInfo mClass; |
| |
| public MethodInfo (String name, String returnType, boolean isAbstract, boolean isNative, |
| boolean isSynchronized, boolean isStatic, boolean isFinal, String deprecated |
| , String scope, SourcePositionInfo source, ClassInfo parent) { |
| |
| mName = name; |
| mReturn = returnType; |
| mIsAbstract = isAbstract; |
| mIsNative = isNative; |
| mIsSynchronized = isSynchronized; |
| mIsStatic = isStatic; |
| mIsFinal = isFinal; |
| mDeprecated = deprecated; |
| mScope = scope; |
| mParameters = new ArrayList<ParameterInfo>(); |
| mExceptions = new ArrayList<String>(); |
| mExistsInBoth = false; |
| mSourcePosition = source; |
| mClass = parent; |
| } |
| |
| |
| public String name() { |
| return mName; |
| } |
| |
| public String qualifiedName() { |
| String parentQName = (mClass != null) |
| ? (mClass.qualifiedName() + ".") |
| : ""; |
| return parentQName + name(); |
| } |
| |
| public String prettySignature() { |
| String params = ""; |
| for (ParameterInfo pInfo : mParameters) { |
| if (params.length() > 0) { |
| params += ", "; |
| } |
| params += pInfo.getType(); |
| } |
| return qualifiedName() + '(' + params + ')'; |
| } |
| |
| public SourcePositionInfo position() { |
| return mSourcePosition; |
| } |
| |
| public ClassInfo containingClass() { |
| return mClass; |
| } |
| |
| public boolean matches(MethodInfo other) { |
| return getSignature().equals(other.getSignature()); |
| } |
| |
| public boolean isConsistent(MethodInfo mInfo) { |
| mInfo.mExistsInBoth = true; |
| mExistsInBoth = true; |
| boolean consistent = true; |
| if (!mReturn.equals(mInfo.mReturn)) { |
| consistent = false; |
| Errors.error(Errors.CHANGED_TYPE, mInfo.position(), |
| "Method " + mInfo.qualifiedName() + " has changed return type from " |
| + mReturn + " to " + mInfo.mReturn); |
| } |
| |
| 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 (mIsFinal != mInfo.mIsFinal) { |
| // Compiler-generated methods vary in their 'final' qual 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's class is not itself 'final'. |
| if (!mIsStatic) { |
| if ((mClass == null) || (!mClass.isFinal())) { |
| consistent = false; |
| Errors.error(Errors.CHANGED_FINAL, mInfo.position(), |
| "Method " + mInfo.qualifiedName() + " has changed 'final' qualifier"); |
| } |
| } |
| } |
| |
| if (mIsStatic != mInfo.mIsStatic) { |
| consistent = false; |
| Errors.error(Errors.CHANGED_STATIC, mInfo.position(), |
| "Method " + mInfo.qualifiedName() + " has changed 'static' qualifier"); |
| } |
| |
| if (!mScope.equals(mInfo.mScope)) { |
| consistent = false; |
| Errors.error(Errors.CHANGED_SCOPE, mInfo.position(), |
| "Method " + mInfo.qualifiedName() + " changed scope from " |
| + mScope + " to " + mInfo.mScope); |
| } |
| |
| if (!mDeprecated.equals(mInfo.mDeprecated)) { |
| Errors.error(Errors.CHANGED_DEPRECATED, mInfo.position(), |
| "Method " + mInfo.qualifiedName() + " has changed deprecation state"); |
| consistent = false; |
| } |
| |
| 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 (String exec : mExceptions) { |
| if (!mInfo.mExceptions.contains(exec)) { |
| // exclude 'throws' changes to finalize() overrides with no arguments |
| if (!name().equals("finalize") || (mParameters.size() > 0)) { |
| Errors.error(Errors.CHANGED_THROWS, mInfo.position(), |
| "Method " + mInfo.qualifiedName() + " no longer throws exception " |
| + exec); |
| consistent = false; |
| } |
| } |
| } |
| |
| for (String exec : mInfo.mExceptions) { |
| // exclude 'throws' changes to finalize() overrides with no arguments |
| if (!mExceptions.contains(exec)) { |
| if (!name().equals("finalize") || (mParameters.size() > 0)) { |
| Errors.error(Errors.CHANGED_THROWS, mInfo.position(), |
| "Method " + mInfo.qualifiedName() + " added thrown exception " |
| + exec); |
| consistent = false; |
| } |
| } |
| } |
| |
| return consistent; |
| } |
| |
| public void addParameter(ParameterInfo pInfo) { |
| mParameters.add(pInfo); |
| } |
| |
| public void addException(String exc) { |
| mExceptions.add(exc); |
| } |
| |
| public String getParameterHash() { |
| String hash = ""; |
| for (ParameterInfo pInfo : mParameters) { |
| hash += ":" + pInfo.getType(); |
| } |
| return hash; |
| } |
| |
| public String getHashableName() { |
| return name() + getParameterHash(); |
| } |
| |
| public String getSignature() { |
| return name() + getParameterHash(); |
| } |
| |
| public boolean isInBoth() { |
| return mExistsInBoth; |
| } |
| |
| } |