ICU-10905 A new tool used for checking deprected tag/annotation consistency. Also added an ant target to run the tool. Some synthetic constructors in abstract class were added (this is our policy) and tighten status tag consistency check. Actual fix for missing @Deprecated annotation will follow.

X-SVN-Rev: 35736
This commit is contained in:
Yoshito Umaoka 2014-05-22 20:05:59 +00:00
parent 968afff8ef
commit 8e23062195
12 changed files with 585 additions and 20 deletions

1
.gitattributes vendored
View file

@ -619,6 +619,7 @@ icu4j/tools/build/icu4j51.api3.gz -text
icu4j/tools/build/icu4j52.api3.gz -text
icu4j/tools/build/icu4j53.api3.gz -text
icu4j/tools/build/manifest.stub -text
icu4j/tools/build/src/com/ibm/icu/dev/tool/docs/DeprecatedAPIChecker.java -text
icu4j/tools/misc/.settings/org.eclipse.core.resources.prefs -text
icu4j/tools/misc/manifest.stub -text
tools/currency/.classpath -text

View file

@ -1076,6 +1076,24 @@
</java>
</target>
<target name="checkDeprecated" depends="info, build-tools, gatherapi, main"
description="Check consistency between javadoc @deprecated and @Deprecated annotation">
<java classname="com.ibm.icu.dev.tool.docs.DeprecatedAPIChecker"
failonerror="true">
<arg value="${out.dir}/icu4j${api.report.version}.api3.gz" />
<classpath>
<pathelement location="${icu4j.build-tools.jar}"/>
<pathelement location="${icu4j.core.jar}"/>
<pathelement location="${icu4j.collate.jar}"/>
<pathelement location="${icu4j.charset.jar}"/>
<pathelement location="${icu4j.currdata.jar}"/>
<pathelement location="${icu4j.langdata.jar}"/>
<pathelement location="${icu4j.regiondata.jar}"/>
<pathelement location="${icu4j.translit.jar}"/>
</classpath>
</java>
</target>
<target name="draftAPIs" depends="info, gatherapi" description="Run API collector tool and generate draft API report">
<java classname="com.ibm.icu.dev.tool.docs.CollectAPI"
classpath="${icu4j.build-tools.jar}"

View file

@ -222,6 +222,14 @@ public final class Normalizer implements Cloneable {
* @stable ICU 2.8
*/
public static abstract class Mode {
/**
* Sole constructor
* @internal
* @deprecated This API is ICU internal only.
*/
protected Mode() {
}
/**
* @internal
* @deprecated This API is ICU internal only.

View file

@ -196,6 +196,14 @@ public class PluralRules implements Serializable {
*/
@Deprecated
public static abstract class Factory {
/**
* Sole constructor
* @internal
* @deprecated This API is ICU internal only.
*/
protected Factory() {
}
/**
* Provides access to the predefined <code>PluralRules</code> for a given locale and the plural type.
*
@ -1769,8 +1777,8 @@ public class PluralRules implements Serializable {
}
/**
* @deprecated This API is ICU internal only.
* @internal
* @deprecated This API is ICU internal only.
*/
@Deprecated
public enum StandardPluralCategories {
@ -2263,7 +2271,7 @@ public class PluralRules implements Serializable {
* If non null, set to the unique value.
* @return the KeywordStatus
* @internal
* @provisional This API might change or be removed in a future release.
* @deprecated This API is ICU internal only.
*/
public KeywordStatus getKeywordStatus(String keyword, int offset, Set<Double> explicits,
Output<Double> uniqueValue, SampleType sampleType) {

View file

@ -422,6 +422,7 @@ public abstract class TimeZoneNames implements Serializable {
* The super class of <code>TimeZoneNames</code> service factory classes.
*
* @internal
* @deprecated This API is ICU internal only.
*/
public static abstract class Factory {
/**
@ -431,8 +432,17 @@ public abstract class TimeZoneNames implements Serializable {
* The display locale
* @return An instance of <code>TimeZoneNames</code>.
* @internal
* @deprecated This API is ICU internal only.
*/
public abstract TimeZoneNames getTimeZoneNames(ULocale locale);
/**
* Sole constructor
* @internal
* @deprecated This API is ICU internal only.
*/
protected Factory() {
}
}
/**

View file

@ -4571,6 +4571,7 @@ public class UnicodeSet extends UnicodeFilter implements Iterable<String>, Compa
* Get the default symbol table. Null means ordinary processing. For internal use only.
* @return the symbol table
* @internal
* @deprecated This API is ICU internal only.
*/
public static XSymbolTable getDefaultXSymbolTable() {
return XSYMBOL_TABLE;
@ -4579,14 +4580,15 @@ public class UnicodeSet extends UnicodeFilter implements Iterable<String>, Compa
/**
* Set the default symbol table. Null means ordinary processing. For internal use only. Will affect all subsequent parsing
* of UnicodeSets.
* <p>
* WARNING: If this function is used with a UnicodeProperty, and the
* Unassigned characters (gc=Cn) are different than in ICU other than in ICU, you MUST call
* {@code UnicodeProperty.ResetCacheProperties} afterwards. If you then call {@code UnicodeSet.setDefaultXSymbolTable}
* with null to clear the value, you MUST also call {@code UnicodeProperty.ResetCacheProperties}.
*
* <p>
* WARNING: If this function is used with a UnicodeProperty, and the
* Unassigned characters (gc=Cn) are different than in ICU other than in ICU, you MUST call
* {@code UnicodeProperty.ResetCacheProperties} afterwards. If you then call {@code UnicodeSet.setDefaultXSymbolTable}
* with null to clear the value, you MUST also call {@code UnicodeProperty.ResetCacheProperties}.
*
* @param xSymbolTable the new default symbol table.
* @internal
* @deprecated This API is ICU internal only.
*/
public static void setDefaultXSymbolTable(XSymbolTable xSymbolTable) {
XSYMBOL_TABLE = xSymbolTable;

View file

@ -753,6 +753,7 @@ public class HebrewCalendar extends Calendar {
* Overrides {@link Calendar#validateField(int)} to provide
* special handling for month validation for Hebrew calendar.
* @internal
* @deprecated This API is ICU internal only.
*/
protected void validateField(int field) {
if (field == MONTH && !isLeapYear(handleGetExtendedYear()) && internalGet(MONTH) == ADAR_1) {

View file

@ -1629,6 +1629,7 @@ public abstract class Transliterator implements StringTransform {
* @param targetSet TODO
* @see #getTargetSet
* @internal
* @deprecated This API is ICU internal only.
*/
public void addSourceTargetSet(UnicodeSet inputFilter, UnicodeSet sourceSet, UnicodeSet targetSet) {
UnicodeSet myFilter = getFilterAsUnicodeSet(inputFilter);
@ -1649,6 +1650,7 @@ public abstract class Transliterator implements StringTransform {
* The externalFilter must be frozen (it is frozen if not).
* The result may be frozen, so don't attempt to modify.
* @internal
* @deprecated This API is ICU internal only.
*/
// TODO change to getMergedFilter
public UnicodeSet getFilterAsUnicodeSet(UnicodeSet externalFilter) {

View file

@ -1,5 +1,5 @@
#*******************************************************************************
#* Copyright (C) 2011-2014, International Business Machines Corporation and *
#* Copyright (C) 2011-2014, International Business Machines Corporation and *
#* others. All Rights Reserved. *
#*******************************************************************************
#shared.dir = ../main/shared
shared.dir = ../main/shared

View file

@ -1,6 +1,6 @@
/**
*******************************************************************************
* Copyright (C) 2004-2013, International Business Machines Corporation and *
* Copyright (C) 2004-2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -18,8 +18,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
@ -61,7 +63,7 @@ public final class APIData {
}
}
static APIData read(File file, boolean internal) {
public static APIData read(File file, boolean internal) {
String fileName = file.getName();
try {
InputStream is;
@ -135,6 +137,10 @@ public final class APIData {
pw.println("total apis: " + tt);
}
public Set<APIInfo> getAPIInfoSet() {
return Collections.unmodifiableSet(set);
}
public static void main(String[] args) {
PrintWriter pw = new PrintWriter(System.out);

View file

@ -0,0 +1,470 @@
/*
*******************************************************************************
* Copyright (C) 2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.dev.tool.docs;
import java.io.File;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
public class DeprecatedAPIChecker {
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("Illegal command argument. Specify the API signature file path.");
}
// Load the ICU4J API signature file
Set<APIInfo> apiInfoSet = APIData.read(new File(args[0]), true).getAPIInfoSet();
DeprecatedAPIChecker checker = new DeprecatedAPIChecker(apiInfoSet, new PrintWriter(System.err, true));
checker.checkDeprecated();
System.exit(checker.errCount);
}
private int errCount = 0;
private Set<APIInfo> apiInfoSet;
private PrintWriter pw;
public DeprecatedAPIChecker(Set<APIInfo> apiInfoSet, PrintWriter pw) {
this.apiInfoSet = apiInfoSet;
this.pw = pw;
}
public int errorCount() {
return errCount;
}
public void checkDeprecated() {
// Gather API class/enum names and its names that can be
// used for Class.forName()
Map<String, String> apiClassNameMap = new TreeMap<String, String>();
for (APIInfo api : apiInfoSet) {
if (!api.isPublic() && !api.isProtected()) {
continue;
}
if (!api.isClass() && !api.isEnum()) {
continue;
}
String packageName = api.getPackageName();
String className = api.getName();
// Replacing separator for nested class/enum (replacing '.' with
// '$'), so we can use the name for Class.forName(String)
String classNamePath = className.contains(".") ? className.replace('.', '$') : className;
apiClassNameMap.put(packageName + "." + classNamePath, packageName + "." + className);
}
// Walk through API classes using reflection
for (Entry<String, String> classEntry : apiClassNameMap.entrySet()) {
String classNamePath = classEntry.getKey();
try {
Class<?> cls = Class.forName(classNamePath);
if (cls.isEnum()) {
checkEnum(cls, apiClassNameMap);
} else {
checkClass(cls, apiClassNameMap);
}
} catch (ClassNotFoundException e) {
pw.println("## Error ## Class " + classNamePath + " is not found.");
errCount++;
}
}
}
private void checkClass(Class<?> cls, Map<String, String> clsNameMap) {
assert !cls.isEnum();
String clsPath = cls.getName();
String clsName = clsNameMap.get(clsPath);
APIInfo api = null;
if (clsName != null) {
api = findClassInfo(apiInfoSet, clsName);
}
if (api == null) {
pw.println("## Error ## Class " + clsName + " is not found in the API signature data.");
errCount++;
}
// check class
compareDeprecated(isAPIDeprecated(api), cls.isAnnotationPresent(Deprecated.class), clsName, null, "Class");
// check fields
for (Field f : cls.getDeclaredFields()) {
if (!isPublicOrProtected(f.getModifiers())) {
continue;
}
String fName = f.getName();
api = findFieldInfo(apiInfoSet, clsName, fName);
if (api == null) {
pw.println("## Error ## Field " + clsName + "." + fName + " is not found in the API signature data.");
errCount++;
continue;
}
compareDeprecated(isAPIDeprecated(api), f.isAnnotationPresent(Deprecated.class), clsName, fName, "Field");
}
// check constructors
for (Constructor<?> ctor : cls.getDeclaredConstructors()) {
if (!isPublicOrProtected(ctor.getModifiers())) {
continue;
}
List<String> paramNames = getParamNames(ctor);
api = findConstructorInfo(apiInfoSet, clsName, paramNames);
if (api == null) {
pw.println("## Error ## Constructor " + clsName + formatParams(paramNames)
+ " is not found in the API signature data.");
errCount++;
continue;
}
compareDeprecated(isAPIDeprecated(api), ctor.isAnnotationPresent(Deprecated.class), clsName,
api.getClassName() + formatParams(paramNames), "Constructor");
}
// check methods
for (Method mtd : cls.getDeclaredMethods()) {
// Note: We exclude synthetic method.
if (!isPublicOrProtected(mtd.getModifiers()) || mtd.isSynthetic()) {
continue;
}
String mtdName = mtd.getName();
List<String> paramNames = getParamNames(mtd);
api = findMethodInfo(apiInfoSet, clsName, mtdName, paramNames);
if (api == null) {
pw.println("## Error ## Method " + clsName + "#" + mtdName + formatParams(paramNames)
+ " is not found in the API signature data.");
errCount++;
continue;
}
compareDeprecated(isAPIDeprecated(api), mtd.isAnnotationPresent(Deprecated.class), clsName, mtdName
+ formatParams(paramNames), "Method");
}
}
private void checkEnum(Class<?> cls, Map<String, String> clsNameMap) {
assert cls.isEnum();
String enumPath = cls.getName();
String enumName = clsNameMap.get(enumPath);
APIInfo api = null;
if (enumName != null) {
api = findEnumInfo(apiInfoSet, enumName);
}
if (api == null) {
pw.println("## Error ## Enum " + enumName + " is not found in the API signature data.");
errCount++;
}
// check enum
compareDeprecated(isAPIDeprecated(api), cls.isAnnotationPresent(Deprecated.class), enumName, null, "Enum");
// check enum constants
for (Field ec : cls.getDeclaredFields()) {
if (!ec.isEnumConstant()) {
continue;
}
String ecName = ec.getName();
api = findEnumConstantInfo(apiInfoSet, enumName, ecName);
if (api == null) {
pw.println("## Error ## Enum constant " + enumName + "." + ecName
+ " is not found in the API signature data.");
errCount++;
continue;
}
compareDeprecated(isAPIDeprecated(api), ec.isAnnotationPresent(Deprecated.class), enumName, ecName,
"Enum Constant");
}
}
private void compareDeprecated(boolean depTag, boolean depAnt, String cls, String name, String type) {
if (depTag != depAnt) {
String apiName = cls;
if (name != null) {
apiName += "." + name;
}
if (depTag) {
pw.println("No @Deprecated annotation: [" + type + "] " + apiName);
} else {
pw.println("No @deprecated JavaDoc tag: [" + type + "] " + apiName);
}
errCount++;
}
}
private static boolean isPublicOrProtected(int modifier) {
return ((modifier & Modifier.PUBLIC) != 0) || ((modifier & Modifier.PROTECTED) != 0);
}
private static boolean isAPIDeprecated(APIInfo api) {
return api.isDeprecated() || api.isInternal() || api.isObsolete();
}
private static APIInfo findClassInfo(Set<APIInfo> apis, String cls) {
for (APIInfo api : apis) {
String clsName = api.getPackageName() + "." + api.getName();
if (api.isClass() && clsName.equals(cls)) {
return api;
}
}
return null;
}
private static APIInfo findFieldInfo(Set<APIInfo> apis, String cls, String field) {
for (APIInfo api : apis) {
String clsName = api.getPackageName() + "." + api.getClassName();
if (api.isField() && clsName.equals(cls) && api.getName().equals(field)) {
return api;
}
}
return null;
}
private static APIInfo findConstructorInfo(Set<APIInfo> apis, String cls, List<String> params) {
for (APIInfo api : apis) {
String clsName = api.getPackageName() + "." + api.getClassName();
if (api.isConstructor() && clsName.equals(cls)) {
// check params
List<String> paramsFromApi = getParamNames(api);
if (paramsFromApi.size() == params.size()) {
boolean match = true;
for (int i = 0; i < params.size(); i++) {
if (!params.get(i).equals(paramsFromApi.get(i))) {
match = false;
break;
}
}
if (match) {
return api;
}
}
}
}
return null;
}
private static APIInfo findMethodInfo(Set<APIInfo> apis, String cls, String method, List<String> params) {
for (APIInfo api : apis) {
String clsName = api.getPackageName() + "." + api.getClassName();
if (api.isMethod() && clsName.equals(cls) && api.getName().equals(method)) {
// check params
List<String> paramsFromApi = getParamNames(api);
if (paramsFromApi.size() == params.size()) {
boolean match = true;
for (int i = 0; i < params.size(); i++) {
if (!params.get(i).equals(paramsFromApi.get(i))) {
match = false;
break;
}
}
if (match) {
return api;
}
}
}
}
return null;
}
private static APIInfo findEnumInfo(Set<APIInfo> apis, String ecls) {
for (APIInfo api : apis) {
String clsName = api.getPackageName() + "." + api.getName();
if (api.isEnum() && clsName.equals(ecls)) {
return api;
}
}
return null;
}
private static APIInfo findEnumConstantInfo(Set<APIInfo> apis, String ecls, String econst) {
for (APIInfo api : apis) {
String clsName = api.getPackageName() + "." + api.getClassName();
if (api.isEnumConstant() && clsName.equals(ecls) && api.getName().equals(econst)) {
return api;
}
}
return null;
}
private static List<String> getParamNames(APIInfo api) {
if (!api.isMethod() && !api.isConstructor()) {
throw new IllegalArgumentException(api.toString() + " is not a constructor or a method.");
}
List<String> nameList = new ArrayList<String>();
String signature = api.getSignature();
int start = signature.indexOf('(');
int end = signature.indexOf(')');
if (start < 0 || end < 0 || start > end) {
throw new RuntimeException(api.toString() + " has bad API signature: " + signature);
}
String paramsSegment = signature.substring(start + 1, end);
// erase generic args
if (paramsSegment.indexOf('<') >= 0) {
StringBuilder buf = new StringBuilder();
boolean inGenericsParams = false;
for (int i = 0; i < paramsSegment.length(); i++) {
char c = paramsSegment.charAt(i);
if (inGenericsParams) {
if (c == '>') {
inGenericsParams = false;
}
} else {
if (c == '<') {
inGenericsParams = true;
} else {
buf.append(c);
}
}
}
paramsSegment = buf.toString();
}
if (!paramsSegment.isEmpty()) {
String[] params = paramsSegment.split("\\s*,\\s*");
for (String p : params) {
if (p.endsWith("...")) {
// varargs to array
p = p.substring(0, p.length() - 3) + "[]";
}
nameList.add(p);
}
}
return nameList;
}
private static List<String> getParamNames(Constructor<?> ctor) {
return toTypeNameList(ctor.getGenericParameterTypes());
}
private static List<String> getParamNames(Method method) {
return toTypeNameList(method.getGenericParameterTypes());
}
private static final String[] PRIMITIVES = { "byte", "short", "int", "long", "float", "double", "boolean", "char" };
private static char[] PRIMITIVE_SIGNATURES = { 'B', 'S', 'I', 'J', 'F', 'D', 'Z', 'C' };
private static List<String> toTypeNameList(Type[] types) {
List<String> nameList = new ArrayList<String>();
for (Type t : types) {
StringBuilder s = new StringBuilder();
if (t instanceof ParameterizedType) {
// throw away generics parameters
ParameterizedType prdType = (ParameterizedType) t;
Class<?> rawType = (Class<?>) prdType.getRawType();
s.append(rawType.getCanonicalName());
} else if (t instanceof WildcardType) {
// we don't need to worry about WildcardType,
// because this tool erases generics parameters
// for comparing method/constructor parameters
throw new RuntimeException("WildcardType not supported by this tool");
} else if (t instanceof TypeVariable) {
// this tool does not try to resolve actual parameter
// type - for example, "<T extends Object> void foo(T in)"
// this tool just use the type variable "T" for API signature
// comparison. This is actually not perfect, but should be
// sufficient for our purpose.
TypeVariable<?> tVar = (TypeVariable<?>) t;
s.append(tVar.getName());
} else if (t instanceof GenericArrayType) {
// same as TypeVariable. "T[]" is sufficient enough.
GenericArrayType tGenArray = (GenericArrayType) t;
s.append(tGenArray.toString());
} else if (t instanceof Class) {
Class<?> tClass = (Class<?>) t;
String tName = tClass.getCanonicalName();
if (tName.charAt(0) == '[') {
// Array type
int idx = 0;
for (; idx < tName.length(); idx++) {
if (tName.charAt(idx) != '[') {
break;
}
}
int dimension = idx;
char sigChar = tName.charAt(dimension);
String elemType = null;
if (sigChar == 'L') {
// class
elemType = tName.substring(dimension + 1, tName.length() - 1);
} else {
// primitive
for (int i = 0; i < PRIMITIVE_SIGNATURES.length; i++) {
if (sigChar == PRIMITIVE_SIGNATURES[i]) {
elemType = PRIMITIVES[i];
break;
}
}
}
if (elemType == null) {
throw new RuntimeException("Unexpected array type: " + tName);
}
s.append(elemType);
for (int i = 0; i < dimension; i++) {
s.append("[]");
}
} else {
s.append(tName);
}
} else {
throw new IllegalArgumentException("Unknown type: " + t);
}
nameList.add(s.toString());
}
return nameList;
}
private static String formatParams(List<String> paramNames) {
StringBuilder buf = new StringBuilder("(");
boolean isFirst = true;
for (String p : paramNames) {
if (isFirst) {
isFirst = false;
} else {
buf.append(", ");
}
buf.append(p);
}
buf.append(")");
return buf.toString();
}
}

View file

@ -1,6 +1,6 @@
/**
*******************************************************************************
* Copyright (C) 2004-2013, International Business Machines Corporation and *
* Copyright (C) 2004-2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -252,12 +252,18 @@ public class GatherAPIData {
// care if we didn't properly document the draft status of
// default constructors for abstract classes.
// Update: We mandate a no-arg synthetic constructor with explicit
// javadoc comments by the policy. So, we no longer ignore abstract
// class's no-arg constructor blindly. -Yoshito 2014-05-21
private boolean isAbstractClassDefaultConstructor(ProgramElementDoc doc) {
return doc.isConstructor()
&& doc.containingClass().isAbstract()
&& "()".equals(((ConstructorDoc) doc).signature());
}
private static final boolean IGNORE_NO_ARG_ABSTRACT_CTOR = false;
private boolean ignore(ProgramElementDoc doc) {
if (doc == null) return true;
if (doc.isPrivate() || doc.isPackagePrivate()) return true;
@ -268,7 +274,8 @@ public class GatherAPIData {
if (isIgnoredEnumMethod(doc)) {
return true;
}
if (isAbstractClassDefaultConstructor(doc)) {
if (IGNORE_NO_ARG_ABSTRACT_CTOR && isAbstractClassDefaultConstructor(doc)) {
return true;
}
@ -445,27 +452,59 @@ public class GatherAPIData {
private int tagStatus(final ProgramElementDoc doc, String[] version) {
class Result {
boolean deprecatedFlag = false;
int res = -1;
void set(int val) {
if (res != -1) {
boolean isValid = true;
if (val == APIInfo.STA_DEPRECATED) {
// ok to have both a 'standard' tag and deprecated
return;
} else if (res != APIInfo.STA_DEPRECATED) {
// if already not deprecated, this is an error
// @internal and @obsolete should be always used along with @deprecated.
// no change for status
isValid = (res == APIInfo.STA_INTERNAL || res == APIInfo.STA_OBSOLETE);
deprecatedFlag = true;
} else if (val == APIInfo.STA_INTERNAL) {
// @deprecated should be always used along with @internal.
// update status
if (res == APIInfo.STA_DEPRECATED) {
res = val; // APIInfo.STA_INTERNAL
} else {
isValid = false;
}
} else if (val == APIInfo.STA_OBSOLETE) {
// @deprecated should be always used along with @obsolete.
// update status
if (res == APIInfo.STA_DEPRECATED) {
res = val; // APIInfo.STA_OBSOLETE
} else {
isValid = false;
}
} else {
// two different status tags must not co-exist, except for
// following two cases:
// 1. @internal and @deprecated
// 2. @obsolete and @deprecated
isValid = false;
}
if (!isValid) {
System.err.println("bad doc: " + doc + " both: "
+ APIInfo.getTypeValName(APIInfo.STA, res) + " and: "
+ APIInfo.getTypeValName(APIInfo.STA, val));
return;
}
} else {
// ok to replace with new tag
res = val;
if (val == APIInfo.STA_DEPRECATED) {
deprecatedFlag = true;
}
}
// ok to replace with new tag
res = val;
}
int get() {
if (res == -1) {
System.err.println("warning: no tag for " + doc);
return 0;
} else if (res == APIInfo.STA_INTERNAL && !deprecatedFlag) {
System.err.println("warning: no @deprecated tag for @internal API: " + doc);
}
return res;
}