summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Paul Duffin <paulduffin@google.com> 2020-12-10 15:26:03 +0000
committer Treehugger Robot <treehugger-gerrit@google.com> 2020-12-10 17:19:30 +0000
commit0b8b5a731f37491e1b135f577b16a5376bf4b753 (patch)
tree01326421b20f18a730b9fc5a6a6fee6239246d76
parent0615dd9138d273567da6cca17176bdf560377418 (diff)
Move art/tools/class2nonsdklist to tools/platform-compat
Test: m droid Bug: 175299477 Change-Id: I36bf4200c1caa8ce155ebb8283215498271b2faf
-rw-r--r--tools/class2nonsdklist/Android.bp35
-rw-r--r--tools/class2nonsdklist/src/class2nonsdklist.mf1
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/AlternativeNotFoundError.java20
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedClassContext.java62
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedMemberContext.java67
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationConsumer.java18
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationContext.java45
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationHandler.java27
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationPropertyWriter.java71
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationVisitor.java96
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiComponents.java327
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiResolver.java111
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/Class2NonSdkList.java262
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/ClassAlternativeNotFoundError.java30
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/CovariantReturnTypeHandler.java104
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/HiddenapiFlagsWriter.java40
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/JarReader.java65
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/JavadocLinkSyntaxError.java31
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/MemberAlternativeNotFoundError.java30
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/MemberDumpingVisitor.java48
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/MultipleAlternativesFoundWarning.java39
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/NoAlternativesSpecifiedError.java30
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/PackageAndClassName.java67
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/RepeatedAnnotationHandler.java57
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/RequiredAlternativeNotSpecifiedError.java26
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/SignatureSyntaxError.java29
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/Status.java62
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/StatusReporter.java31
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/StringCursor.java131
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/StringCursorOutOfBoundsException.java21
-rw-r--r--tools/class2nonsdklist/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandler.java207
-rw-r--r--tools/class2nonsdklist/test/Android.bp29
-rw-r--r--tools/class2nonsdklist/test/AndroidTest.xml21
-rw-r--r--tools/class2nonsdklist/test/src/com/android/class2nonsdklist/AnnotationHandlerTestBase.java55
-rw-r--r--tools/class2nonsdklist/test/src/com/android/class2nonsdklist/AnnotationPropertyWriterTest.java74
-rw-r--r--tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiComponentsTest.java143
-rw-r--r--tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiResolverTest.java143
-rw-r--r--tools/class2nonsdklist/test/src/com/android/class2nonsdklist/CovariantReturnTypeHandlerTest.java153
-rw-r--r--tools/class2nonsdklist/test/src/com/android/class2nonsdklist/RepeatedAnnotationHandlerTest.java95
-rw-r--r--tools/class2nonsdklist/test/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandlerTest.java614
40 files changed, 0 insertions, 3517 deletions
diff --git a/tools/class2nonsdklist/Android.bp b/tools/class2nonsdklist/Android.bp
deleted file mode 100644
index 507673460c..0000000000
--- a/tools/class2nonsdklist/Android.bp
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// Copyright (C) 2018 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.
-//
-
-java_library_host {
- name: "class2nonsdklistlib",
- srcs: ["src/**/*.java"],
- static_libs: [
- "commons-cli-1.2",
- "apache-bcel",
- "guava",
- "testng",
- "hamcrest-library",
- ],
-}
-
-java_binary_host {
- name: "class2nonsdklist",
- manifest: "src/class2nonsdklist.mf",
- static_libs: [
- "class2nonsdklistlib",
- ],
-}
diff --git a/tools/class2nonsdklist/src/class2nonsdklist.mf b/tools/class2nonsdklist/src/class2nonsdklist.mf
deleted file mode 100644
index 5bd80d94f7..0000000000
--- a/tools/class2nonsdklist/src/class2nonsdklist.mf
+++ /dev/null
@@ -1 +0,0 @@
-Main-Class: com.android.class2nonsdklist.Class2NonSdkList
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AlternativeNotFoundError.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AlternativeNotFoundError.java
deleted file mode 100644
index 37f1f51a7d..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AlternativeNotFoundError.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-public class AlternativeNotFoundError extends Exception {
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedClassContext.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedClassContext.java
deleted file mode 100644
index 8b5a8e1ca0..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedClassContext.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2018 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.class2nonsdklist;
-
-import java.util.Formatter;
-import java.util.Locale;
-import org.apache.bcel.Const;
-import org.apache.bcel.classfile.FieldOrMethod;
-import org.apache.bcel.classfile.JavaClass;
-
-/**
- * Encapsulates context for a single annotation on a class.
- */
-public class AnnotatedClassContext extends AnnotationContext {
-
- public final String signatureFormatString;
-
- public AnnotatedClassContext(
- Status status,
- JavaClass definingClass,
- String signatureFormatString) {
- super(status, definingClass);
- this.signatureFormatString = signatureFormatString;
- }
-
- @Override
- public String getMemberDescriptor() {
- return String.format(Locale.US, signatureFormatString, getClassDescriptor());
- }
-
- private String buildReportString(String message, Object... args) {
- Formatter error = new Formatter();
- error
- .format("%s: %s: ", definingClass.getSourceFileName(), definingClass.getClassName())
- .format(Locale.US, message, args);
- return error.toString();
- }
-
- @Override
- public void reportError(String message, Object... args) {
- status.error(buildReportString(message, args));
- }
-
- @Override
- public void reportWarning(String message, Object... args) {
- status.warning(buildReportString(message, args));
- }
-
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedMemberContext.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedMemberContext.java
deleted file mode 100644
index 6276040fd7..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotatedMemberContext.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 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.class2nonsdklist;
-
-import java.util.Formatter;
-import org.apache.bcel.Const;
-import org.apache.bcel.classfile.FieldOrMethod;
-import org.apache.bcel.classfile.JavaClass;
-
-import java.util.Locale;
-
-/**
- * Encapsulates context for a single annotation on a class member.
- */
-public class AnnotatedMemberContext extends AnnotationContext {
-
- public final FieldOrMethod member;
- public final String signatureFormatString;
-
- public AnnotatedMemberContext(
- Status status,
- JavaClass definingClass,
- FieldOrMethod member,
- String signatureFormatString) {
- super(status, definingClass);
- this.member = member;
- this.signatureFormatString = signatureFormatString;
- }
-
- @Override
- public String getMemberDescriptor() {
- return String.format(Locale.US, signatureFormatString,
- getClassDescriptor(), member.getName(), member.getSignature());
- }
-
- private String buildReportString(String message, Object... args) {
- Formatter error = new Formatter();
- error
- .format("%s: %s.%s: ", definingClass.getSourceFileName(),
- definingClass.getClassName(), member.getName())
- .format(Locale.US, message, args);
- return error.toString();
- }
-
- @Override
- public void reportError(String message, Object... args) {
- status.error(buildReportString(message, args));
- }
-
- @Override
- public void reportWarning(String message, Object... args) {
- status.warning(buildReportString(message, args));
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationConsumer.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationConsumer.java
deleted file mode 100644
index f527f61f1a..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationConsumer.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.android.class2nonsdklist;
-
-import java.util.Map;
-import java.util.Set;
-
-public interface AnnotationConsumer {
- /**
- * Handle a parsed annotation for a class member.
- *
- * @param apiSignature Signature of the class member.
- * @param annotationProperties Map of stringified properties of this annotation.
- * @param parsedFlags Array of flags parsed from the annotation for this member.
- */
- public void consume(String apiSignature, Map<String, String> annotationProperties,
- Set<String> parsedFlags);
-
- public void close();
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationContext.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationContext.java
deleted file mode 100644
index 7ea6807eb1..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationContext.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2018 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.class2nonsdklist;
-
-import org.apache.bcel.Const;
-import org.apache.bcel.classfile.JavaClass;
-
-/**
- */
-public abstract class AnnotationContext implements StatusReporter {
-
- public final Status status;
- public final JavaClass definingClass;
-
- public AnnotationContext(Status status, JavaClass definingClass) {
- this.status = status;
- this.definingClass = definingClass;
- }
-
- public String getClassDescriptor() {
- // JavaClass.getName() returns the Java-style name (with . not /), so we must fetch
- // the original class name from the constant pool.
- return definingClass.getConstantPool().getConstantString(
- definingClass.getClassNameIndex(), Const.CONSTANT_Class);
- }
-
- /**
- * @return the full descriptor of this member, in the format expected in
- * the greylist.
- */
- public abstract String getMemberDescriptor();
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationHandler.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationHandler.java
deleted file mode 100644
index 0f7c00bb38..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationHandler.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.android.class2nonsdklist;
-
-import java.util.Map;
-import java.util.HashMap;
-
-import org.apache.bcel.classfile.AnnotationEntry;
-import org.apache.bcel.classfile.ElementValuePair;
-
-
-/**
- * Base class for an annotation handler, which handle individual annotations on
- * class members.
- */
-public abstract class AnnotationHandler {
- abstract void handleAnnotation(AnnotationEntry annotation, AnnotationContext context);
-
- protected Map<String, String> stringifyAnnotationProperties(AnnotationEntry annotation) {
- Map<String, String> content = new HashMap<String, String>();
-
- // Stringify all annotation properties.
- for (ElementValuePair prop : annotation.getElementValuePairs()) {
- content.put(prop.getNameString(), prop.getValue().stringifyValue());
- }
-
- return content;
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationPropertyWriter.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationPropertyWriter.java
deleted file mode 100644
index 5cf01c76ef..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationPropertyWriter.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.android.class2nonsdklist;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-public class AnnotationPropertyWriter implements AnnotationConsumer {
-
- private final PrintStream mOutput;
- private final List<Map<String, String>> mContents;
- private final Set<String> mColumns;
-
- public AnnotationPropertyWriter(String csvFile) throws FileNotFoundException {
- mOutput = new PrintStream(new FileOutputStream(new File(csvFile)));
- mContents = new ArrayList<>();
- mColumns = new HashSet<>();
- }
-
- public AnnotationPropertyWriter(OutputStream output) {
- mOutput = new PrintStream(output);
- mContents = new ArrayList<>();
- mColumns = new HashSet<>();
- }
-
- public void consume(String apiSignature, Map<String, String> annotationProperties,
- Set<String> parsedFlags) {
- // Clone properties map.
- Map<String, String> contents = new HashMap(annotationProperties);
-
- // Append the member signature.
- contents.put("signature", apiSignature);
-
- // Store data.
- mColumns.addAll(contents.keySet());
- mContents.add(contents);
- }
-
- private static String escapeCsvColumn(String column) {
- // Using '|' as a quote character, as in frameworks/base/tools/hiddenapi/merge_csv.py
- // Escape '|' characters in the column, then wrap the column in '|' characters.
- column = column.replace("|", "||");
- return "|" + column + "|";
- }
-
- public void close() {
- // Sort columns by name and print header row.
- List<String> columns = new ArrayList<>(mColumns);
- columns.sort(Comparator.naturalOrder());
- mOutput.println(columns.stream().collect(Collectors.joining(",")));
-
- // Sort contents according to columns and print.
- for (Map<String, String> row : mContents) {
- mOutput.println(columns.stream().map(column -> row.getOrDefault(column, ""))
- .map(column -> escapeCsvColumn(column))
- .collect(Collectors.joining(",")));
- }
-
- // Close output.
- mOutput.close();
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationVisitor.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationVisitor.java
deleted file mode 100644
index 64e5f4b6bf..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/AnnotationVisitor.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2018 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.class2nonsdklist;
-
-import org.apache.bcel.classfile.AnnotationEntry;
-import org.apache.bcel.classfile.DescendingVisitor;
-import org.apache.bcel.classfile.EmptyVisitor;
-import org.apache.bcel.classfile.Field;
-import org.apache.bcel.classfile.FieldOrMethod;
-import org.apache.bcel.classfile.JavaClass;
-import org.apache.bcel.classfile.Method;
-
-import java.util.Map;
-
-/**
- * Visits a JavaClass instance and passes any annotated members to a {@link AnnotationHandler}
- * according to the map provided.
- */
-public class AnnotationVisitor extends EmptyVisitor {
-
- private final JavaClass mClass;
- private final Status mStatus;
- private final DescendingVisitor mDescendingVisitor;
- private final Map<String, AnnotationHandler> mAnnotationHandlers;
-
- /**
- * Creates a visitor for a class.
- *
- * @param clazz Class to visit
- * @param status For reporting debug information
- * @param handlers Map of {@link AnnotationHandler}. The keys should be annotation names, as
- * class descriptors.
- */
- public AnnotationVisitor(JavaClass clazz, Status status,
- Map<String, AnnotationHandler> handlers) {
- mClass = clazz;
- mStatus = status;
- mAnnotationHandlers = handlers;
- mDescendingVisitor = new DescendingVisitor(clazz, this);
- }
-
- public void visit() {
- mStatus.debug("Visit class %s", mClass.getClassName());
- AnnotationContext context = new AnnotatedClassContext(mStatus, mClass, "L%s;");
- AnnotationEntry[] annotationEntries = mClass.getAnnotationEntries();
- handleAnnotations(context, annotationEntries);
-
- mDescendingVisitor.visit();
- }
-
- @Override
- public void visitMethod(Method method) {
- visitMember(method, "L%s;->%s%s");
- }
-
- @Override
- public void visitField(Field field) {
- visitMember(field, "L%s;->%s:%s");
- }
-
- private void visitMember(FieldOrMethod member, String signatureFormatString) {
- mStatus.debug("Visit member %s : %s", member.getName(), member.getSignature());
- AnnotationContext context = new AnnotatedMemberContext(mStatus,
- (JavaClass) mDescendingVisitor.predecessor(), member,
- signatureFormatString);
- AnnotationEntry[] annotationEntries = member.getAnnotationEntries();
- handleAnnotations(context, annotationEntries);
- }
-
- private void handleAnnotations(AnnotationContext context, AnnotationEntry[] annotationEntries) {
- for (AnnotationEntry a : annotationEntries) {
- if (mAnnotationHandlers.containsKey(a.getAnnotationType())) {
- mStatus.debug("Member has annotation %s for which we have a handler",
- a.getAnnotationType());
- mAnnotationHandlers.get(a.getAnnotationType()).handleAnnotation(a, context);
- } else {
- mStatus.debug("Member has annotation %s for which we do not have a handler",
- a.getAnnotationType());
- }
- }
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiComponents.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiComponents.java
deleted file mode 100644
index f1f42f0c19..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiComponents.java
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Class which can parse either dex style signatures (e.g. Lfoo/bar/baz$bat;->foo()V) or javadoc
- * links to class members (e.g. {@link #toString()} or {@link java.util.List#clear()}).
- */
-public class ApiComponents {
- private static final String PRIMITIVE_TYPES = "ZBCSIJFD";
- private final PackageAndClassName mPackageAndClassName;
- // The reference can be just to a class, in which case mMemberName should be empty.
- private final String mMemberName;
- // If the member being referenced is a field, this will always be empty.
- private final String mMethodParameterTypes;
-
- private ApiComponents(PackageAndClassName packageAndClassName, String memberName,
- String methodParameterTypes) {
- mPackageAndClassName = packageAndClassName;
- mMemberName = memberName;
- mMethodParameterTypes = methodParameterTypes;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder()
- .append(mPackageAndClassName.packageName)
- .append(".")
- .append(mPackageAndClassName.className);
- if (!mMemberName.isEmpty()) {
- sb.append("#").append(mMemberName).append("(").append(mMethodParameterTypes).append(
- ")");
- }
- return sb.toString();
- }
-
- public PackageAndClassName getPackageAndClassName() {
- return mPackageAndClassName;
- }
-
- public String getMemberName() {
- return mMemberName;
- }
-
- public String getMethodParameterTypes() {
- return mMethodParameterTypes;
- }
-
- /**
- * Parse a JNI class descriptor. e.g. Lfoo/bar/Baz;
- *
- * @param sc Cursor over string assumed to contain a JNI class descriptor.
- * @return The fully qualified class, in 'dot notation' (e.g. foo.bar.Baz for a class named Baz
- * in the foo.bar package). The cursor will be placed after the semicolon.
- */
- private static String parseJNIClassDescriptor(StringCursor sc)
- throws SignatureSyntaxError, StringCursorOutOfBoundsException {
- if (sc.peek() != 'L') {
- throw new SignatureSyntaxError(
- "Expected JNI class descriptor to start with L, but instead got " + sc.peek(),
- sc);
- }
- // Consume the L.
- sc.next();
- int semiColonPos = sc.find(';');
- if (semiColonPos == -1) {
- throw new SignatureSyntaxError("Expected semicolon at the end of JNI class descriptor",
- sc);
- }
- String jniClassDescriptor = sc.next(semiColonPos);
- // Consume the semicolon.
- sc.next();
- return jniClassDescriptor.replace("/", ".");
- }
-
- /**
- * Parse a primitive JNI type
- *
- * @param sc Cursor over a string assumed to contain a primitive JNI type.
- * @return String containing parsed primitive JNI type.
- */
- private static String parseJNIPrimitiveType(StringCursor sc)
- throws SignatureSyntaxError, StringCursorOutOfBoundsException {
- char c = sc.next();
- switch (c) {
- case 'Z':
- return "boolean";
- case 'B':
- return "byte";
- case 'C':
- return "char";
- case 'S':
- return "short";
- case 'I':
- return "int";
- case 'J':
- return "long";
- case 'F':
- return "float";
- case 'D':
- return "double";
- default:
- throw new SignatureSyntaxError(c + " is not a primitive type!", sc);
- }
- }
-
- /**
- * Parse a JNI type; can be either a primitive or object type. Arrays are handled separately.
- *
- * @param sc Cursor over the string assumed to contain a JNI type.
- * @return String containing parsed JNI type.
- */
- private static String parseJniTypeWithoutArrayDimensions(StringCursor sc)
- throws SignatureSyntaxError, StringCursorOutOfBoundsException {
- char c = sc.peek();
- if (PRIMITIVE_TYPES.indexOf(c) != -1) {
- return parseJNIPrimitiveType(sc);
- } else if (c == 'L') {
- return parseJNIClassDescriptor(sc);
- }
- throw new SignatureSyntaxError("Illegal token " + c + " within signature", sc);
- }
-
- /**
- * Parse a JNI type.
- *
- * This parameter can be an array, in which case it will be preceded by a number of open square
- * brackets (corresponding to its dimensionality)
- *
- * @param sc Cursor over the string assumed to contain a JNI type.
- * @return Same as {@link #parseJniTypeWithoutArrayDimensions}, but also handle arrays.
- */
- private static String parseJniType(StringCursor sc)
- throws SignatureSyntaxError, StringCursorOutOfBoundsException {
- int arrayDimension = 0;
- while (sc.peek() == '[') {
- ++arrayDimension;
- sc.next();
- }
- StringBuilder sb = new StringBuilder();
- sb.append(parseJniTypeWithoutArrayDimensions(sc));
- for (int i = 0; i < arrayDimension; ++i) {
- sb.append("[]");
- }
- return sb.toString();
- }
-
- /**
- * Converts the parameters of method from JNI notation to Javadoc link notation. e.g.
- * "(IILfoo/bar/Baz;)V" turns into "int, int, foo.bar.Baz". The parentheses and return type are
- * discarded.
- *
- * @param sc Cursor over the string assumed to contain a JNI method parameters.
- * @return Comma separated list of parameter types.
- */
- private static String convertJNIMethodParametersToJavadoc(StringCursor sc)
- throws SignatureSyntaxError, StringCursorOutOfBoundsException {
- List<String> methodParameterTypes = new ArrayList<>();
- if (sc.next() != '(') {
- throw new IllegalArgumentException("Trying to parse method params of an invalid dex " +
- "signature: " + sc.getOriginalString());
- }
- while (sc.peek() != ')') {
- methodParameterTypes.add(parseJniType(sc));
- }
- return String.join(", ", methodParameterTypes);
- }
-
- /**
- * Generate ApiComponents from a dex signature.
- *
- * This is used to extract the necessary context for an alternative API to try to infer missing
- * information.
- *
- * @param signature Dex signature.
- * @return ApiComponents instance with populated package, class name, and parameter types if
- * applicable.
- */
- public static ApiComponents fromDexSignature(String signature) throws SignatureSyntaxError {
- StringCursor sc = new StringCursor(signature);
- try {
- String fullyQualifiedClass = parseJNIClassDescriptor(sc);
-
- PackageAndClassName packageAndClassName =
- PackageAndClassName.splitClassName(fullyQualifiedClass);
- if (!sc.peek(2).equals("->")) {
- throw new SignatureSyntaxError("Expected '->'", sc);
- }
- // Consume "->"
- sc.next(2);
- String memberName = "";
- String methodParameterTypes = "";
- int leftParenPos = sc.find('(');
- if (leftParenPos != -1) {
- memberName = sc.next(leftParenPos);
- methodParameterTypes = convertJNIMethodParametersToJavadoc(sc);
- } else {
- int colonPos = sc.find(':');
- if (colonPos == -1) {
- throw new IllegalArgumentException("Expected : or -> beyond position "
- + sc.position() + " in " + signature);
- } else {
- memberName = sc.next(colonPos);
- // Consume the ':'.
- sc.next();
- // Consume the type.
- parseJniType(sc);
- }
- }
- return new ApiComponents(packageAndClassName, memberName, methodParameterTypes);
- } catch (StringCursorOutOfBoundsException e) {
- throw new SignatureSyntaxError(
- "Unexpectedly reached end of string while trying to parse signature ", sc);
- }
- }
-
- /**
- * Generate ApiComponents from a link tag.
- *
- * @param linkTag The contents of a link tag.
- * @param contextSignature The signature of the private API that this is an alternative for.
- * Used to infer unspecified components.
- */
- public static ApiComponents fromLinkTag(String linkTag, String contextSignature)
- throws JavadocLinkSyntaxError {
- ApiComponents contextAlternative;
- try {
- contextAlternative = fromDexSignature(contextSignature);
- } catch (SignatureSyntaxError e) {
- throw new RuntimeException(
- "Failed to parse the context signature for public alternative!");
- }
- StringCursor sc = new StringCursor(linkTag);
- try {
-
- String memberName = "";
- String methodParameterTypes = "";
-
- int tagPos = sc.find('#');
- String fullyQualifiedClassName = sc.next(tagPos);
-
- PackageAndClassName packageAndClassName =
- PackageAndClassName.splitClassName(fullyQualifiedClassName);
-
- if (packageAndClassName.packageName.isEmpty()) {
- packageAndClassName.packageName = contextAlternative.getPackageAndClassName()
- .packageName;
- }
-
- if (packageAndClassName.className.isEmpty()) {
- packageAndClassName.className = contextAlternative.getPackageAndClassName()
- .className;
- }
-
- if (tagPos == -1) {
- // This suggested alternative is just a class. We can allow that.
- return new ApiComponents(packageAndClassName, "", "");
- } else {
- // Consume the #.
- sc.next();
- }
-
- int leftParenPos = sc.find('(');
- memberName = sc.next(leftParenPos);
- if (leftParenPos != -1) {
- // Consume the '('.
- sc.next();
- int rightParenPos = sc.find(')');
- if (rightParenPos == -1) {
- throw new JavadocLinkSyntaxError(
- "Linked method is missing a closing parenthesis", sc);
- } else {
- methodParameterTypes = sc.next(rightParenPos);
- }
- }
-
- return new ApiComponents(packageAndClassName, memberName, methodParameterTypes);
- } catch (StringCursorOutOfBoundsException e) {
- throw new JavadocLinkSyntaxError(
- "Unexpectedly reached end of string while trying to parse javadoc link", sc);
- }
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof ApiComponents)) {
- return false;
- }
- ApiComponents other = (ApiComponents) obj;
- return mPackageAndClassName.equals(other.mPackageAndClassName) && mMemberName.equals(
- other.mMemberName) && mMethodParameterTypes.equals(other.mMethodParameterTypes);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mPackageAndClassName, mMemberName, mMethodParameterTypes);
- }
-
- /**
- * Less restrictive comparator to use in case a link tag is missing a method's parameters.
- * e.g. foo.bar.Baz#foo will be considered the same as foo.bar.Baz#foo(int, int) and
- * foo.bar.Baz#foo(long, long). If the class only has one method with that name, then specifying
- * its parameter types is optional within the link tag.
- */
- public boolean equalsIgnoringParam(ApiComponents other) {
- return mPackageAndClassName.equals(other.mPackageAndClassName) &&
- mMemberName.equals(other.mMemberName);
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiResolver.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiResolver.java
deleted file mode 100644
index 461bb69e3a..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/ApiResolver.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-import com.google.common.base.Strings;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-public class ApiResolver {
- private final List<ApiComponents> mPotentialPublicAlternatives;
- private final Set<PackageAndClassName> mPublicApiClasses;
-
- private static final Pattern LINK_TAG_PATTERN = Pattern.compile("\\{@link ([^\\}]+)\\}");
- private static final Pattern CODE_TAG_PATTERN = Pattern.compile("\\{@code ([^\\}]+)\\}");
- private static final Integer MIN_SDK_REQUIRING_PUBLIC_ALTERNATIVES = 29;
-
- public ApiResolver() {
- mPotentialPublicAlternatives = null;
- mPublicApiClasses = null;
- }
-
- public ApiResolver(Set<String> publicApis) {
- mPotentialPublicAlternatives = publicApis.stream()
- .map(api -> {
- try {
- return ApiComponents.fromDexSignature(api);
- } catch (SignatureSyntaxError e) {
- throw new RuntimeException("Could not parse public API signature:", e);
- }
- })
- .collect(Collectors.toList());
- mPublicApiClasses = mPotentialPublicAlternatives.stream()
- .map(api -> api.getPackageAndClassName())
- .collect(Collectors.toCollection(HashSet::new));
- }
-
- /**
- * Verify that all public alternatives are valid.
- *
- * @param publicAlternativesString String containing public alternative explanations.
- * @param signature Signature of the member that has the annotation.
- */
- public void resolvePublicAlternatives(String publicAlternativesString, String signature,
- Integer maxSdkVersion)
- throws JavadocLinkSyntaxError, AlternativeNotFoundError,
- RequiredAlternativeNotSpecifiedError, MultipleAlternativesFoundWarning {
- if (Strings.isNullOrEmpty(publicAlternativesString) && maxSdkVersion != null
- && maxSdkVersion >= MIN_SDK_REQUIRING_PUBLIC_ALTERNATIVES) {
- throw new RequiredAlternativeNotSpecifiedError();
- }
- if (publicAlternativesString != null && mPotentialPublicAlternatives != null) {
- // Grab all instances of type {@link foo}
- Matcher matcher = LINK_TAG_PATTERN.matcher(publicAlternativesString);
- boolean hasLinkAlternative = false;
- // Validate all link tags
- while (matcher.find()) {
- hasLinkAlternative = true;
- String alternativeString = matcher.group(1);
- ApiComponents alternative = ApiComponents.fromLinkTag(alternativeString,
- signature);
- if (alternative.getMemberName().isEmpty()) {
- // Provided class as alternative
- if (!mPublicApiClasses.contains(alternative.getPackageAndClassName())) {
- throw new ClassAlternativeNotFoundError(alternative);
- }
- } else if (!mPotentialPublicAlternatives.contains(alternative)) {
- // If the link is not a public alternative, it must because the link does not
- // contain the method parameter types, e.g. {@link foo.bar.Baz#foo} instead of
- // {@link foo.bar.Baz#foo(int)}. If the method name is unique within the class,
- // we can handle it.
- if (!Strings.isNullOrEmpty(alternative.getMethodParameterTypes())) {
- throw new MemberAlternativeNotFoundError(alternative);
- }
- List<ApiComponents> almostMatches = mPotentialPublicAlternatives.stream()
- .filter(api -> api.equalsIgnoringParam(alternative))
- .collect(Collectors.toList());
- if (almostMatches.size() == 0) {
- throw new MemberAlternativeNotFoundError(alternative);
- } else if (almostMatches.size() > 1) {
- throw new MultipleAlternativesFoundWarning(alternative, almostMatches);
- }
- }
- }
- // No {@link ...} alternatives exist; try looking for {@code ...}
- if (!hasLinkAlternative) {
- if (!CODE_TAG_PATTERN.matcher(publicAlternativesString).find()) {
- throw new NoAlternativesSpecifiedError();
- }
- }
- }
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/Class2NonSdkList.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/Class2NonSdkList.java
deleted file mode 100644
index 9be1e9b56a..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/Class2NonSdkList.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2018 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.class2nonsdklist;
-
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMap.Builder;
-import com.google.common.io.Files;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.GnuParser;
-import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.OptionBuilder;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Build time tool for extracting a list of members from jar files that have the
- * @UnsupportedAppUsage annotation, for building the non SDK API lists.
- */
-public class Class2NonSdkList {
-
- private static final String UNSUPPORTED_APP_USAGE_ANNOTATION =
- "android.compat.annotation.UnsupportedAppUsage";
-
- private static final String FLAG_UNSUPPORTED = "unsupported";
- private static final String FLAG_BLOCKED = "blocked";
- private static final String FLAG_MAX_TARGET_O = "max-target-o";
- private static final String FLAG_MAX_TARGET_P = "max-target-p";
- private static final String FLAG_MAX_TARGET_Q = "max-target-q";
- private static final String FLAG_MAX_TARGET_R = "max-target-r";
-
- private static final String FLAG_PUBLIC_API = "public-api";
-
- private static final Map<Integer, String> TARGET_SDK_TO_LIST_MAP;
- static {
- Map<Integer, String> map = new HashMap<>();
- map.put(null, FLAG_UNSUPPORTED);
- map.put(0, FLAG_BLOCKED);
- map.put(26, FLAG_MAX_TARGET_O);
- map.put(28, FLAG_MAX_TARGET_P);
- map.put(29, FLAG_MAX_TARGET_Q);
- map.put(30, FLAG_MAX_TARGET_R);
- TARGET_SDK_TO_LIST_MAP = Collections.unmodifiableMap(map);
- }
-
- private final Status mStatus;
- private final String[] mJarFiles;
- private final AnnotationConsumer mOutput;
- private final Set<String> mPublicApis;
-
- public static void main(String[] args) {
- Options options = new Options();
- options.addOption(OptionBuilder
- .withLongOpt("stub-api-flags")
- .hasArgs(1)
- .withDescription("CSV file with API flags generated from public API stubs. " +
- "Used to de-dupe bridge methods.")
- .create("s"));
- options.addOption(OptionBuilder
- .withLongOpt("write-flags-csv")
- .hasArgs(1)
- .withDescription("Specify file to write hiddenapi flags to.")
- .create('w'));
- options.addOption(OptionBuilder
- .withLongOpt("debug")
- .hasArgs(0)
- .withDescription("Enable debug")
- .create("d"));
- options.addOption(OptionBuilder
- .withLongOpt("dump-all-members")
- .withDescription("Dump all members from jar files to stdout. Ignore annotations. " +
- "Do not use in conjunction with any other arguments.")
- .hasArgs(0)
- .create('m'));
- options.addOption(OptionBuilder
- .withLongOpt("write-metadata-csv")
- .hasArgs(1)
- .withDescription("Specify a file to write API metaadata to. This is a CSV file " +
- "containing any annotation properties for all members. Do not use in " +
- "conjunction with --write-flags-csv.")
- .create('c'));
- options.addOption(OptionBuilder
- .withLongOpt("help")
- .hasArgs(0)
- .withDescription("Show this help")
- .create('h'));
-
- CommandLineParser parser = new GnuParser();
- CommandLine cmd;
-
- try {
- cmd = parser.parse(options, args);
- } catch (ParseException e) {
- System.err.println(e.getMessage());
- help(options);
- return;
- }
- if (cmd.hasOption('h')) {
- help(options);
- }
-
-
- String[] jarFiles = cmd.getArgs();
- if (jarFiles.length == 0) {
- System.err.println("Error: no jar files specified.");
- help(options);
- }
-
- Status status = new Status(cmd.hasOption('d'));
-
- if (cmd.hasOption('m')) {
- dumpAllMembers(status, jarFiles);
- } else {
- try {
- Class2NonSdkList c2nsl = new Class2NonSdkList(
- status,
- cmd.getOptionValue('s', null),
- cmd.getOptionValue('w', null),
- cmd.getOptionValue('c', null),
- jarFiles);
- c2nsl.main();
- } catch (IOException e) {
- status.error(e);
- }
- }
-
- if (status.ok()) {
- System.exit(0);
- } else {
- System.exit(1);
- }
-
- }
-
- private Class2NonSdkList(Status status, String stubApiFlagsFile, String csvFlagsFile,
- String csvMetadataFile, String[] jarFiles)
- throws IOException {
- mStatus = status;
- mJarFiles = jarFiles;
- if (csvMetadataFile != null) {
- mOutput = new AnnotationPropertyWriter(csvMetadataFile);
- } else {
- mOutput = new HiddenapiFlagsWriter(csvFlagsFile);
- }
-
- if (stubApiFlagsFile != null) {
- mPublicApis =
- Files.readLines(new File(stubApiFlagsFile), StandardCharsets.UTF_8).stream()
- .map(s -> Splitter.on(",").splitToList(s))
- .filter(s -> s.contains(FLAG_PUBLIC_API))
- .map(s -> s.get(0))
- .collect(Collectors.toSet());
- } else {
- mPublicApis = Collections.emptySet();
- }
- }
-
- private Map<String, AnnotationHandler> createAnnotationHandlers() {
- Builder<String, AnnotationHandler> builder = ImmutableMap.builder();
- UnsupportedAppUsageAnnotationHandler greylistAnnotationHandler =
- new UnsupportedAppUsageAnnotationHandler(
- mStatus, mOutput, mPublicApis, TARGET_SDK_TO_LIST_MAP);
-
- addRepeatedAnnotationHandlers(
- builder,
- classNameToSignature(UNSUPPORTED_APP_USAGE_ANNOTATION),
- classNameToSignature(UNSUPPORTED_APP_USAGE_ANNOTATION + "$Container"),
- greylistAnnotationHandler);
-
- CovariantReturnTypeHandler covariantReturnTypeHandler = new CovariantReturnTypeHandler(
- mOutput, mPublicApis, FLAG_PUBLIC_API);
-
- return addRepeatedAnnotationHandlers(builder, CovariantReturnTypeHandler.ANNOTATION_NAME,
- CovariantReturnTypeHandler.REPEATED_ANNOTATION_NAME, covariantReturnTypeHandler)
- .build();
- }
-
- private String classNameToSignature(String a) {
- return "L" + a.replace('.', '/') + ";";
- }
-
- /**
- * Add a handler for an annotation as well as an handler for the container annotation that is
- * used when the annotation is repeated.
- *
- * @param builder the builder for the map to which the handlers will be added.
- * @param annotationName the name of the annotation.
- * @param containerAnnotationName the name of the annotation container.
- * @param handler the handler for the annotation.
- */
- private static Builder<String, AnnotationHandler> addRepeatedAnnotationHandlers(
- Builder<String, AnnotationHandler> builder,
- String annotationName, String containerAnnotationName,
- AnnotationHandler handler) {
- return builder
- .put(annotationName, handler)
- .put(containerAnnotationName, new RepeatedAnnotationHandler(annotationName, handler));
- }
-
- private void main() {
- Map<String, AnnotationHandler> handlers = createAnnotationHandlers();
- for (String jarFile : mJarFiles) {
- mStatus.debug("Processing jar file %s", jarFile);
- try {
- JarReader reader = new JarReader(mStatus, jarFile);
- reader.stream().forEach(clazz -> new AnnotationVisitor(clazz, mStatus, handlers)
- .visit());
- reader.close();
- } catch (IOException e) {
- mStatus.error(e);
- }
- }
- mOutput.close();
- }
-
- private static void dumpAllMembers(Status status, String[] jarFiles) {
- for (String jarFile : jarFiles) {
- status.debug("Processing jar file %s", jarFile);
- try {
- JarReader reader = new JarReader(status, jarFile);
- reader.stream().forEach(clazz -> new MemberDumpingVisitor(clazz, status)
- .visit());
- reader.close();
- } catch (IOException e) {
- status.error(e);
- }
- }
- }
-
- private static void help(Options options) {
- new HelpFormatter().printHelp(
- "class2nonsdklist path/to/classes.jar [classes2.jar ...]",
- "Extracts nonsdk entries from classes jar files given",
- options, null, true);
- System.exit(1);
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/ClassAlternativeNotFoundError.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/ClassAlternativeNotFoundError.java
deleted file mode 100644
index 49135bf793..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/ClassAlternativeNotFoundError.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-public class ClassAlternativeNotFoundError extends AlternativeNotFoundError {
- public final ApiComponents alternative;
-
- ClassAlternativeNotFoundError(ApiComponents alternative) {
- this.alternative = alternative;
- }
-
- @Override
- public String toString() {
- return "Specified class " + alternative.getPackageAndClassName() + " does not exist!";
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/CovariantReturnTypeHandler.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/CovariantReturnTypeHandler.java
deleted file mode 100644
index df300c01a7..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/CovariantReturnTypeHandler.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package com.android.class2nonsdklist;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-
-import org.apache.bcel.classfile.AnnotationEntry;
-import org.apache.bcel.classfile.ElementValuePair;
-import org.apache.bcel.classfile.Method;
-
-import java.util.Locale;
-import java.util.Set;
-
-/**
- * Handles {@code CovariantReturnType} annotations, generating whitelist
- * entries from them.
- *
- * <p>A whitelist entry is generated with the same descriptor as the original
- * method, but with the return type replaced with than specified by the
- * {@link #RETURN_TYPE} property.
- *
- * <p>Methods are also validated against the public API list, to assert that
- * the annotated method is already a public API.
- */
-public class CovariantReturnTypeHandler extends AnnotationHandler {
-
- private static final String SHORT_NAME = "CovariantReturnType";
- public static final String ANNOTATION_NAME = "Ldalvik/annotation/codegen/CovariantReturnType;";
- public static final String REPEATED_ANNOTATION_NAME =
- "Ldalvik/annotation/codegen/CovariantReturnType$CovariantReturnTypes;";
-
- private static final String RETURN_TYPE = "returnType";
-
- private final AnnotationConsumer mAnnotationConsumer;
- private final Set<String> mPublicApis;
- private final String mHiddenapiFlag;
-
- public CovariantReturnTypeHandler(AnnotationConsumer consumer, Set<String> publicApis,
- String hiddenapiFlag) {
- mAnnotationConsumer = consumer;
- mPublicApis = publicApis;
- mHiddenapiFlag = hiddenapiFlag;
- }
-
- @Override
- public void handleAnnotation(AnnotationEntry annotation, AnnotationContext context) {
- if (context instanceof AnnotatedClassContext) {
- return;
- }
- handleAnnotation(annotation, (AnnotatedMemberContext) context);
- }
-
- private void handleAnnotation(AnnotationEntry annotation, AnnotatedMemberContext context) {
- // Verify that the annotation has been applied to what we expect, and
- // has the right form. Note, this should not strictly be necessary, as
- // the annotation has a target of just 'method' and the property
- // returnType does not have a default value, but checking makes the code
- // less brittle to future changes.
- if (!(context.member instanceof Method)) {
- context.reportError("Cannot specify %s on a field", RETURN_TYPE);
- return;
- }
- String returnType = findReturnType(annotation);
- if (returnType == null) {
- context.reportError("No %s set on @%s", RETURN_TYPE, SHORT_NAME);
- return;
- }
- if (!mPublicApis.contains(context.getMemberDescriptor())) {
- context.reportError("Found @%s on non-SDK method", SHORT_NAME);
- return;
- }
-
- // Generate the signature of overload that we expect the annotation will
- // cause the platform dexer to create.
- String typeSignature = context.member.getSignature();
- int closingBrace = typeSignature.indexOf(')');
- Preconditions.checkState(closingBrace != -1,
- "No ) found in method type signature %s", typeSignature);
- typeSignature = new StringBuilder()
- .append(typeSignature.substring(0, closingBrace + 1))
- .append(returnType)
- .toString();
- String signature = String.format(Locale.US, context.signatureFormatString,
- context.getClassDescriptor(), context.member.getName(), typeSignature);
-
- if (mPublicApis.contains(signature)) {
- context.reportError("Signature %s generated from @%s already exists as a public API",
- signature, SHORT_NAME);
- return;
- }
-
- mAnnotationConsumer.consume(signature, stringifyAnnotationProperties(annotation),
- ImmutableSet.of(mHiddenapiFlag));
- }
-
- private String findReturnType(AnnotationEntry a) {
- for (ElementValuePair property : a.getElementValuePairs()) {
- if (property.getNameString().equals(RETURN_TYPE)) {
- return property.getValue().stringifyValue();
- }
- }
- // not found
- return null;
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/HiddenapiFlagsWriter.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/HiddenapiFlagsWriter.java
deleted file mode 100644
index 7c4fd113fc..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/HiddenapiFlagsWriter.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.android.class2nonsdklist;
-
-import com.google.common.annotations.VisibleForTesting;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-public class HiddenapiFlagsWriter implements AnnotationConsumer {
-
- private final PrintStream mOutput;
-
- public HiddenapiFlagsWriter(String csvFile) throws FileNotFoundException {
- mOutput = new PrintStream(new FileOutputStream(new File(csvFile)));
- }
-
- public void consume(String apiSignature, Map<String, String> annotationProperties,
- Set<String> parsedFlags) {
- if (parsedFlags.size() > 0) {
- mOutput.println(apiSignature + "," + String.join(",", asSortedList(parsedFlags)));
- }
- }
-
- public void close() {
- mOutput.close();
- }
-
- private static List<String> asSortedList(Set<String> s) {
- List<String> list = new ArrayList<>(s);
- Collections.sort(list);
- return list;
- }
-
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/JarReader.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/JarReader.java
deleted file mode 100644
index 8d512517f0..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/JarReader.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 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.class2nonsdklist;
-
-import org.apache.bcel.classfile.ClassParser;
-import org.apache.bcel.classfile.JavaClass;
-
-import java.io.IOException;
-import java.util.Objects;
-import java.util.stream.Stream;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-/**
- * Reads {@link JavaClass} members from a zip/jar file, providing a stream of them for processing.
- * Any errors are reported via {@link Status#error(Throwable)}.
- */
-public class JarReader {
-
- private final Status mStatus;
- private final String mFileName;
- private final ZipFile mZipFile;
-
- public JarReader(Status s, String filename) throws IOException {
- mStatus = s;
- mFileName = filename;
- mZipFile = new ZipFile(mFileName);
- }
-
- private JavaClass openZipEntry(ZipEntry e) {
- try {
- mStatus.debug("Reading %s from %s", e.getName(), mFileName);
- return new ClassParser(mZipFile.getInputStream(e), e.getName()).parse();
- } catch (IOException ioe) {
- mStatus.error(ioe);
- return null;
- }
- }
-
-
- public Stream<JavaClass> stream() {
- return mZipFile.stream()
- .filter(zipEntry -> zipEntry.getName().endsWith(".class"))
- .map(zipEntry -> openZipEntry(zipEntry))
- .filter(Objects::nonNull);
- }
-
- public void close() throws IOException {
- mZipFile.close();
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/JavadocLinkSyntaxError.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/JavadocLinkSyntaxError.java
deleted file mode 100644
index eaf78c225e..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/JavadocLinkSyntaxError.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-public class JavadocLinkSyntaxError extends Exception {
- public final String expected;
- public final int position;
- public final String context;
-
- public JavadocLinkSyntaxError(String expected, StringCursor sc) {
- super(expected + " at position " + sc.position() + " in " + sc.getOriginalString());
- this.expected = expected;
- this.position = sc.position();
- this.context = sc.getOriginalString();
- }
-}
-
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/MemberAlternativeNotFoundError.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/MemberAlternativeNotFoundError.java
deleted file mode 100644
index e0547a2962..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/MemberAlternativeNotFoundError.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-public class MemberAlternativeNotFoundError extends AlternativeNotFoundError {
- public final ApiComponents alternative;
-
- MemberAlternativeNotFoundError(ApiComponents alternative) {
- this.alternative = alternative;
- }
-
- @Override
- public String toString() {
- return "Could not find public api " + alternative + ".";
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/MemberDumpingVisitor.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/MemberDumpingVisitor.java
deleted file mode 100644
index e00af53bde..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/MemberDumpingVisitor.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.android.class2nonsdklist;
-
-import org.apache.bcel.classfile.DescendingVisitor;
-import org.apache.bcel.classfile.EmptyVisitor;
-import org.apache.bcel.classfile.Field;
-import org.apache.bcel.classfile.FieldOrMethod;
-import org.apache.bcel.classfile.JavaClass;
-import org.apache.bcel.classfile.Method;
-
-/**
- * A class file visitor that simply prints to stdout the signature of every member within the class.
- */
-public class MemberDumpingVisitor extends EmptyVisitor {
-
- private final Status mStatus;
- private final DescendingVisitor mDescendingVisitor;
-
- /**
- * Creates a visitor for a class.
- *
- * @param clazz Class to visit
- */
- public MemberDumpingVisitor(JavaClass clazz, Status status) {
- mStatus = status;
- mDescendingVisitor = new DescendingVisitor(clazz, this);
- }
-
- public void visit() {
- mDescendingVisitor.visit();
- }
-
- @Override
- public void visitMethod(Method method) {
- visitMember(method, "L%s;->%s%s");
- }
-
- @Override
- public void visitField(Field field) {
- visitMember(field, "L%s;->%s:%s");
- }
-
- private void visitMember(FieldOrMethod member, String signatureFormatString) {
- AnnotationContext context = new AnnotatedMemberContext(mStatus,
- (JavaClass) mDescendingVisitor.predecessor(), member,
- signatureFormatString);
- System.out.println(context.getMemberDescriptor());
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/MultipleAlternativesFoundWarning.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/MultipleAlternativesFoundWarning.java
deleted file mode 100644
index 738c906264..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/MultipleAlternativesFoundWarning.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-import com.google.common.base.Joiner;
-
-import java.util.List;
-
-public class MultipleAlternativesFoundWarning extends Exception {
- public final ApiComponents alternative;
- public final List<ApiComponents> almostMatches;
-
- public MultipleAlternativesFoundWarning(ApiComponents alternative,
- List<ApiComponents> almostMatches) {
- this.alternative = alternative;
- this.almostMatches = almostMatches;
- }
-
- @Override
- public String toString() {
- return "Alternative " + alternative + " returned multiple matches. Consider adding method" +
- " parameters to make the match unique. Matches: "
- + Joiner.on(", ").join(almostMatches);
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/NoAlternativesSpecifiedError.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/NoAlternativesSpecifiedError.java
deleted file mode 100644
index fbc1962555..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/NoAlternativesSpecifiedError.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-public class NoAlternativesSpecifiedError extends AlternativeNotFoundError {
-
- @Override
- public String toString() {
- return "Hidden API has a public alternative annotation field, but no concrete "
- + "explanations. Please provide either a reference to an SDK method using javadoc "
- + "syntax, e.g. {@link foo.bar.Baz#bat}, or a small code snippet if the "
- + "alternative is part of a support library or third party library, e.g. "
- + "{@code foo.bar.Baz bat = new foo.bar.Baz(); bat.doSomething();}.\n"
- + "If this is too restrictive for your use case, please contact compat-team@.";
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/PackageAndClassName.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/PackageAndClassName.java
deleted file mode 100644
index 7967cf5f03..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/PackageAndClassName.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-import java.util.Objects;
-
-class PackageAndClassName{
- public String packageName;
- public String className;
-
- private PackageAndClassName(String packageName, String className) {
- this.packageName = packageName;
- this.className = className;
- }
-
- /**
- * Given a potentially fully qualified class name, split it into package and class.
- *
- * @param fullyQualifiedClassName potentially fully qualified class name.
- * @return A pair of strings, containing the package name (or empty if not specified) and
- * the
- * class name (or empty if string is empty).
- */
- public static PackageAndClassName splitClassName(String fullyQualifiedClassName) {
- int lastDotIdx = fullyQualifiedClassName.lastIndexOf('.');
- if (lastDotIdx == -1) {
- return new PackageAndClassName("", fullyQualifiedClassName);
- }
- String packageName = fullyQualifiedClassName.substring(0, lastDotIdx);
- String className = fullyQualifiedClassName.substring(lastDotIdx + 1);
- return new PackageAndClassName(packageName, className);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof PackageAndClassName)) {
- return false;
- }
- PackageAndClassName other = (PackageAndClassName) obj;
- return Objects.equals(packageName, other.packageName) && Objects.equals(className,
- other.className);
- }
-
- @Override
- public String toString() {
- return packageName + "." + className;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(packageName, className);
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/RepeatedAnnotationHandler.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/RepeatedAnnotationHandler.java
deleted file mode 100644
index 5c796a57fb..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/RepeatedAnnotationHandler.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.android.class2nonsdklist;
-
-import com.google.common.base.Preconditions;
-import org.apache.bcel.classfile.AnnotationElementValue;
-import org.apache.bcel.classfile.AnnotationEntry;
-import org.apache.bcel.classfile.ArrayElementValue;
-import org.apache.bcel.classfile.ElementValue;
-import org.apache.bcel.classfile.ElementValuePair;
-
-/**
- * Handles a repeated annotation container.
- *
- * <p>The enclosed annotations are passed to the {@link #mWrappedHandler}.
- */
-public class RepeatedAnnotationHandler extends AnnotationHandler {
-
- private static final String VALUE = "value";
-
- private final AnnotationHandler mWrappedHandler;
- private final String mInnerAnnotationName;
-
- RepeatedAnnotationHandler(String innerAnnotationName, AnnotationHandler wrappedHandler) {
- mWrappedHandler = wrappedHandler;
- mInnerAnnotationName = innerAnnotationName;
- }
-
- @Override
- public void handleAnnotation(AnnotationEntry annotation, AnnotationContext context) {
- // Verify that the annotation has the form we expect
- ElementValuePair value = findValue(annotation);
- if (value == null) {
- context.reportError("No value found on %s", annotation.getAnnotationType());
- return;
- }
- Preconditions.checkArgument(value.getValue() instanceof ArrayElementValue);
- ArrayElementValue array = (ArrayElementValue) value.getValue();
-
- // call wrapped handler on each enclosed annotation:
- for (ElementValue v : array.getElementValuesArray()) {
- Preconditions.checkArgument(v instanceof AnnotationElementValue);
- AnnotationElementValue aev = (AnnotationElementValue) v;
- Preconditions.checkArgument(
- aev.getAnnotationEntry().getAnnotationType().equals(mInnerAnnotationName));
- mWrappedHandler.handleAnnotation(aev.getAnnotationEntry(), context);
- }
- }
-
- private ElementValuePair findValue(AnnotationEntry a) {
- for (ElementValuePair property : a.getElementValuePairs()) {
- if (property.getNameString().equals(VALUE)) {
- return property;
- }
- }
- // not found
- return null;
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/RequiredAlternativeNotSpecifiedError.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/RequiredAlternativeNotSpecifiedError.java
deleted file mode 100644
index 88c6f7da98..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/RequiredAlternativeNotSpecifiedError.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-/**
- * Exception to be thrown when a greylisted private api gets restricted to max-FOO (where FOO is Q
- * or later), without providing a public API alternative.
- */
-public class RequiredAlternativeNotSpecifiedError extends Exception {
-
-}
-
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/SignatureSyntaxError.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/SignatureSyntaxError.java
deleted file mode 100644
index ca7a83e62f..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/SignatureSyntaxError.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-public class SignatureSyntaxError extends Exception {
- public final String expected;
- public final int position;
- public final String context;
- public SignatureSyntaxError(String expected, StringCursor sc) {
- super(expected + " at position " + sc.position() + " in " + sc.getOriginalString());
- this.expected = expected;
- this.position = sc.position();
- this.context = sc.getOriginalString();
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/Status.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/Status.java
deleted file mode 100644
index 1460a4f71a..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/Status.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2018 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.class2nonsdklist;
-
-import java.util.Locale;
-
-public class Status {
-
- // Highlight "Error:" in red.
- private static final String ERROR = "\u001B[31mError: \u001B[0m";
-
- // Highlight "Warning:" in yellow.
- private static final String WARNING = "\u001B[33mWarning: \u001B[0m";
-
- private final boolean mDebug;
- private boolean mHasErrors;
-
- public Status(boolean debug) {
- mDebug = debug;
- }
-
- public void debug(String msg, Object... args) {
- if (mDebug) {
- System.err.println(String.format(Locale.US, msg, args));
- }
- }
-
- public void error(Throwable t) {
- System.err.print(ERROR);
- t.printStackTrace(System.err);
- mHasErrors = true;
- }
-
- public void error(String message, Object... args) {
- System.err.print(ERROR);
- System.err.println(String.format(Locale.US, message, args));
- mHasErrors = true;
- }
-
- public void warning(String message, Object... args) {
- System.err.print(WARNING);
- System.err.println(String.format(Locale.US, message, args));
- }
-
- public boolean ok() {
- return !mHasErrors;
- }
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/StatusReporter.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/StatusReporter.java
deleted file mode 100644
index 52154909b8..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/StatusReporter.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-public interface StatusReporter {
- /**
- * Report an error in this context. The final error message will include
- * the class and member names, and the source file name.
- */
- void reportError(String message, Object... args);
-
- /**
- * Report a warning in this context. The final message will include the
- * class and member names, and the source file name.
- */
- void reportWarning(String message, Object... args);
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/StringCursor.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/StringCursor.java
deleted file mode 100644
index 45e10f4526..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/StringCursor.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-/**
- * Utility class to simplify parsing of signatures.
- */
-public class StringCursor {
-
- private final String mString;
- private int mCursor;
-
- public StringCursor(String str) {
- mString = str;
- mCursor = 0;
- }
-
- /**
- * Position of cursor in string.
- *
- * @return Current position of cursor in string.
- */
- public int position() {
- return mCursor;
- }
-
- /**
- * Peek current cursor position.
- *
- * @return The character at the current cursor position.
- */
- public char peek() {
- return mString.charAt(mCursor);
- }
-
- /**
- * Peek several characters at the current cursor position without moving the cursor.
- *
- * @param n The number of characters to peek.
- * @return A string with x characters from the cursor position. If n is -1, return the whole
- * rest of the string.
- */
- public String peek(int n) throws StringCursorOutOfBoundsException {
- if (n == -1) {
- return mString.substring(mCursor);
- }
- if (n < 0 || (n + mCursor) >= mString.length()) {
- throw new StringCursorOutOfBoundsException();
- }
- return mString.substring(mCursor, mCursor + n);
- }
-
- /**
- * Consume the character at the current cursor position and move the cursor forwards.
- *
- * @return The character at the current cursor position.
- */
- public char next() throws StringCursorOutOfBoundsException {
- if (!hasNext()) {
- throw new StringCursorOutOfBoundsException();
- }
- return mString.charAt(mCursor++);
- }
-
- /**
- * Consume several characters at the current cursor position and move the cursor further along.
- *
- * @param n The number of characters to consume.
- * @return A string with x characters from the cursor position. If n is -1, return the whole
- * rest of the string.
- */
- public String next(int n) throws StringCursorOutOfBoundsException {
- if (n == -1) {
- String restOfString = mString.substring(mCursor);
- mCursor = mString.length();
- return restOfString;
- }
- if (n < 0) {
- throw new StringCursorOutOfBoundsException();
- }
- mCursor += n;
- return mString.substring(mCursor - n, mCursor);
- }
-
- /**
- * Search for the first occurrence of a character beyond the current cursor position.
- *
- * @param c The character to search for.
- * @return The offset of the first occurrence of c in the string beyond the cursor position.
- * If the character does not exist, return -1.
- */
- public int find(char c) {
- int firstIndex = mString.indexOf(c, mCursor);
- if (firstIndex == -1) {
- return -1;
- }
- return firstIndex - mCursor;
- }
-
- /**
- * Check if cursor has reached end of string.
- *
- * @return Cursor has reached end of string.
- */
- public boolean hasNext() {
- return mCursor < mString.length();
- }
-
- @Override
- public String toString() {
- return mString.substring(mCursor);
- }
-
- public String getOriginalString() {
- return mString;
- }
-} \ No newline at end of file
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/StringCursorOutOfBoundsException.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/StringCursorOutOfBoundsException.java
deleted file mode 100644
index 1c56d5e362..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/StringCursorOutOfBoundsException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-public class StringCursorOutOfBoundsException extends IndexOutOfBoundsException {
-
-}
diff --git a/tools/class2nonsdklist/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandler.java b/tools/class2nonsdklist/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandler.java
deleted file mode 100644
index a213d51a2f..0000000000
--- a/tools/class2nonsdklist/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandler.java
+++ /dev/null
@@ -1,207 +0,0 @@
-package com.android.class2nonsdklist;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableSet;
-
-import org.apache.bcel.Const;
-import org.apache.bcel.classfile.AnnotationEntry;
-import org.apache.bcel.classfile.ElementValue;
-import org.apache.bcel.classfile.ElementValuePair;
-import org.apache.bcel.classfile.FieldOrMethod;
-import org.apache.bcel.classfile.Method;
-import org.apache.bcel.classfile.SimpleElementValue;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Predicate;
-
-/**
- * Processes {@code UnsupportedAppUsage} annotations to generate greylist
- * entries.
- *
- * Any annotations with a {@link #EXPECTED_SIGNATURE_PROPERTY} property will have their
- * generated signature verified against this, and an error will be reported if
- * it does not match. Exclusions are made for bridge methods.
- *
- * Any {@link #MAX_TARGET_SDK_PROPERTY} properties will be validated against the given
- * set of valid values, then passed through to the greylist consumer.
- */
-public class UnsupportedAppUsageAnnotationHandler extends AnnotationHandler {
-
- // properties of greylist annotations:
- private static final String EXPECTED_SIGNATURE_PROPERTY = "expectedSignature";
- private static final String MAX_TARGET_SDK_PROPERTY = "maxTargetSdk";
- private static final String IMPLICIT_MEMBER_PROPERTY = "implicitMember";
- private static final String PUBLIC_ALTERNATIVES_PROPERTY = "publicAlternatives";
- private static final String TRACKING_BUG_PROPERTY = "trackingBug";
- // we are temporarilly treating this bug id as if it is specified with maxTargetSdk=0
- private static final Long RESTRICT_UNUSED_APIS_BUG = 170729553L;
- private static final Integer SDK_VERSION_R = 30;
-
- private final Status mStatus;
- private final Predicate<ClassMember> mClassMemberFilter;
- private final Map<Integer, String> mSdkVersionToFlagMap;
- private final AnnotationConsumer mAnnotationConsumer;
-
- private ApiResolver mApiResolver;
-
- /**
- * Represents a member of a class file (a field or method).
- */
- @VisibleForTesting
- public static class ClassMember {
-
- /**
- * Signature of this class member.
- */
- public final String signature;
-
- /**
- * Indicates if this is a synthetic bridge method.
- */
- public final boolean isBridgeMethod;
-
- public ClassMember(String signature, boolean isBridgeMethod) {
- this.signature = signature;
- this.isBridgeMethod = isBridgeMethod;
- }
- }
-
- public UnsupportedAppUsageAnnotationHandler(Status status,
- AnnotationConsumer annotationConsumer, Set<String> publicApis,
- Map<Integer, String> sdkVersionToFlagMap) {
- this(status, annotationConsumer,
- member -> !(member.isBridgeMethod && publicApis.contains(member.signature)),
- sdkVersionToFlagMap);
- mApiResolver = new ApiResolver(publicApis);
- }
-
- @VisibleForTesting
- public UnsupportedAppUsageAnnotationHandler(Status status,
- AnnotationConsumer annotationConsumer, Predicate<ClassMember> memberFilter,
- Map<Integer, String> sdkVersionToFlagMap) {
- mStatus = status;
- mAnnotationConsumer = annotationConsumer;
- mClassMemberFilter = memberFilter;
- mSdkVersionToFlagMap = sdkVersionToFlagMap;
- mApiResolver = new ApiResolver();
- }
-
- @Override
- public void handleAnnotation(AnnotationEntry annotation, AnnotationContext context) {
- boolean isBridgeMethod = false;
- if (context instanceof AnnotatedMemberContext) {
- AnnotatedMemberContext memberContext = (AnnotatedMemberContext) context;
- FieldOrMethod member = memberContext.member;
- isBridgeMethod = (member instanceof Method) &&
- (member.getAccessFlags() & Const.ACC_BRIDGE) != 0;
- if (isBridgeMethod) {
- mStatus.debug("Member is a bridge method");
- }
- }
-
- String signature = context.getMemberDescriptor();
- Integer maxTargetSdk = null;
- String implicitMemberSignature = null;
- String publicAlternativesString = null;
- Long trackingBug = null;
-
- for (ElementValuePair property : annotation.getElementValuePairs()) {
- switch (property.getNameString()) {
- case EXPECTED_SIGNATURE_PROPERTY:
- String expected = property.getValue().stringifyValue();
- // Don't enforce for bridge methods; they're generated so won't match.
- if (!isBridgeMethod && !signature.equals(expected)) {
- context.reportError("Expected signature does not match generated:\n"
- + "Expected: %s\n"
- + "Generated: %s", expected, signature);
- return;
- }
- break;
- case MAX_TARGET_SDK_PROPERTY:
- if (property.getValue().getElementValueType() != ElementValue.PRIMITIVE_INT) {
- context.reportError("Expected property %s to be of type int; got %d",
- property.getNameString(),
- property.getValue().getElementValueType());
- return;
- }
-
- maxTargetSdk = ((SimpleElementValue) property.getValue()).getValueInt();
- break;
- case IMPLICIT_MEMBER_PROPERTY:
- implicitMemberSignature = property.getValue().stringifyValue();
- if (context instanceof AnnotatedClassContext) {
- signature = String.format("L%s;->%s",
- context.getClassDescriptor(), implicitMemberSignature);
- } else {
- context.reportError(
- "Expected annotation with an %s property to be on a class but is "
- + "on %s",
- IMPLICIT_MEMBER_PROPERTY,
- signature);
- return;
- }
- break;
- case PUBLIC_ALTERNATIVES_PROPERTY:
- publicAlternativesString = property.getValue().stringifyValue();
- break;
- case TRACKING_BUG_PROPERTY:
- if (property.getValue().getElementValueType() != ElementValue.PRIMITIVE_LONG) {
- context.reportError("Expected property %s to be of type long; got %d",
- property.getNameString(),
- property.getValue().getElementValueType());
- return;
- }
- trackingBug = ((SimpleElementValue) property.getValue()).getValueLong();
- break;
- }
- }
-
- boolean isSpecialTrackingBug = RESTRICT_UNUSED_APIS_BUG.equals(trackingBug) &&
- SDK_VERSION_R.equals(maxTargetSdk);
- if (isSpecialTrackingBug) {
- maxTargetSdk = 0;
- }
-
- if (context instanceof AnnotatedClassContext && implicitMemberSignature == null) {
- context.reportError(
- "Missing property %s on annotation on class %s",
- IMPLICIT_MEMBER_PROPERTY,
- signature);
- return;
- }
-
- // Verify that maxTargetSdk is valid.
- if (!mSdkVersionToFlagMap.containsKey(maxTargetSdk)) {
- context.reportError("Invalid value for %s: got %d, expected one of [%s]",
- MAX_TARGET_SDK_PROPERTY,
- maxTargetSdk,
- mSdkVersionToFlagMap.keySet());
- return;
- }
-
- try {
- mApiResolver.resolvePublicAlternatives(publicAlternativesString, signature,
- maxTargetSdk);
- } catch (MultipleAlternativesFoundWarning e) {
- context.reportWarning(e.toString());
- } catch (JavadocLinkSyntaxError | AlternativeNotFoundError e) {
- context.reportError(e.toString());
- } catch (RequiredAlternativeNotSpecifiedError e) {
- context.reportError("Signature %s moved to %s without specifying public "
- + "alternatives; Refer to go/unsupportedappusage-public-alternatives "
- + "for details.",
- signature, mSdkVersionToFlagMap.get(maxTargetSdk));
- }
-
- // Consume this annotation if it matches the predicate.
- if (mClassMemberFilter.test(new ClassMember(signature, isBridgeMethod))) {
- Map<String, String> annotationProperties = stringifyAnnotationProperties(annotation);
- if (isSpecialTrackingBug) {
- annotationProperties.put(MAX_TARGET_SDK_PROPERTY, "0");
- }
- mAnnotationConsumer.consume(signature, annotationProperties,
- ImmutableSet.of(mSdkVersionToFlagMap.get(maxTargetSdk)));
- }
- }
-}
diff --git a/tools/class2nonsdklist/test/Android.bp b/tools/class2nonsdklist/test/Android.bp
deleted file mode 100644
index bd4143c901..0000000000
--- a/tools/class2nonsdklist/test/Android.bp
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2018 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.
-
-java_test_host {
- name: "class2nonsdklisttest",
-
- // Only compile source java files in this apk.
- srcs: ["src/**/*.java"],
-
- static_libs: [
- "class2nonsdklistlib",
- "libjavac",
- "truth-host-prebuilt",
- "mockito-host",
- "junit-host",
- "objenesis",
- ],
-}
diff --git a/tools/class2nonsdklist/test/AndroidTest.xml b/tools/class2nonsdklist/test/AndroidTest.xml
deleted file mode 100644
index 9616c62575..0000000000
--- a/tools/class2nonsdklist/test/AndroidTest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-<configuration description="class2nonsdklist tests">
- <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
- <option name="jar" value="class2nonsdklisttest.jar" />
- <option name="runtime-hint" value="1m" />
- </test>
-</configuration> \ No newline at end of file
diff --git a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/AnnotationHandlerTestBase.java b/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/AnnotationHandlerTestBase.java
deleted file mode 100644
index fa779287e6..0000000000
--- a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/AnnotationHandlerTestBase.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2018 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.class2nonsdklist;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.withSettings;
-
-import com.android.javac.Javac;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.TestName;
-
-import java.io.IOException;
-
-public class AnnotationHandlerTestBase {
-
- @Rule
- public TestName mTestName = new TestName();
-
- protected Javac mJavac;
- protected AnnotationConsumer mConsumer;
- protected Status mStatus;
-
- @Before
- public void baseSetup() throws IOException {
- System.out.println(String.format("\n============== STARTING TEST: %s ==============\n",
- mTestName.getMethodName()));
- mConsumer = mock(AnnotationConsumer.class);
- mStatus = mock(Status.class, withSettings().verboseLogging());
- mJavac = new Javac();
- }
-
- protected void assertNoErrors() {
- verify(mStatus, never()).error(any(Throwable.class));
- verify(mStatus, never()).error(any(), any());
- }
-}
diff --git a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/AnnotationPropertyWriterTest.java b/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/AnnotationPropertyWriterTest.java
deleted file mode 100644
index 4cdf017f40..0000000000
--- a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/AnnotationPropertyWriterTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.collect.ImmutableMap;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.ByteArrayOutputStream;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-
-public class AnnotationPropertyWriterTest {
-
- private ByteArrayOutputStream mByteArrayOutputStream;
- private AnnotationPropertyWriter mAnnotationPropertyWriter;
-
- @Before
- public void setup() {
- mByteArrayOutputStream = new ByteArrayOutputStream();
- mAnnotationPropertyWriter = new AnnotationPropertyWriter(mByteArrayOutputStream);
- }
-
- @Test
- public void testExportPropertiesNoEscaping() {
- String signature = "foo";
- Map<String, String> annotationProperties = ImmutableMap.of(
- "prop", "val"
- );
- Set<String> parsedFlags = new HashSet<String>();
- mAnnotationPropertyWriter.consume(signature, annotationProperties, parsedFlags);
- mAnnotationPropertyWriter.close();
-
- String output = mByteArrayOutputStream.toString();
- String expected = "prop,signature\n"
- + "|val|,|foo|\n";
- assertThat(output).isEqualTo(expected);
- }
-
- @Test
- public void testExportPropertiesEscapeQuotes() {
- String signature = "foo";
- Map<String, String> annotationProperties = ImmutableMap.of(
- "prop", "val1 | val2 | val3"
- );
- Set<String> parsedFlags = new HashSet<String>();
- mAnnotationPropertyWriter.consume(signature, annotationProperties, parsedFlags);
- mAnnotationPropertyWriter.close();
-
- String output = mByteArrayOutputStream.toString();
- String expected = "prop,signature\n"
- + "|val1 || val2 || val3|,|foo|\n";
- assertThat(output).isEqualTo(expected);
- }
-}
diff --git a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiComponentsTest.java b/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiComponentsTest.java
deleted file mode 100644
index 61f502a081..0000000000
--- a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiComponentsTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import org.junit.Test;
-
-
-public class ApiComponentsTest extends AnnotationHandlerTestBase {
-
- @Test
- public void testGetApiComponentsPackageFromSignature() throws SignatureSyntaxError {
- ApiComponents api = ApiComponents.fromDexSignature("La/b/C;->foo()V");
- PackageAndClassName packageAndClassName = api.getPackageAndClassName();
- assertThat(packageAndClassName.packageName).isEqualTo("a.b");
- }
-
- @Test
- public void testGetApiComponentsFromSignature() throws SignatureSyntaxError {
- ApiComponents api = ApiComponents.fromDexSignature("La/b/C;->foo(IJLfoo2/bar/Baz;)V");
- PackageAndClassName packageAndClassName = api.getPackageAndClassName();
- assertThat(packageAndClassName.className).isEqualTo("C");
- assertThat(api.getMemberName()).isEqualTo("foo");
- assertThat(api.getMethodParameterTypes()).isEqualTo("int, long, foo2.bar.Baz");
- }
-
- @Test
- public void testInvalidDexSignatureInvalidClassFormat() throws SignatureSyntaxError {
- assertThrows(SignatureSyntaxError.class, () -> {
- ApiComponents.fromDexSignature("a/b/C;->foo()V");
- });
- assertThrows(SignatureSyntaxError.class, () -> {
- ApiComponents.fromDexSignature("La/b/C->foo()V");
- });
- }
-
- @Test
- public void testInvalidDexSignatureInvalidParameterType() throws SignatureSyntaxError {
- assertThrows(SignatureSyntaxError.class, () -> {
- ApiComponents.fromDexSignature("a/b/C;->foo(foo)V");
- });
- }
-
- @Test
- public void testInvalidDexSignatureInvalidReturnType() throws SignatureSyntaxError {
- assertThrows(SignatureSyntaxError.class, () -> {
- ApiComponents.fromDexSignature("a/b/C;->foo()foo");
- });
- }
-
- @Test
- public void testInvalidDexSignatureMissingReturnType() throws SignatureSyntaxError {
- assertThrows(SignatureSyntaxError.class, () -> {
- ApiComponents.fromDexSignature("a/b/C;->foo(I)");
- });
- }
-
- @Test
- public void testInvalidDexSignatureMissingArrowOrColon() throws SignatureSyntaxError {
- assertThrows(SignatureSyntaxError.class, () -> {
- ApiComponents.fromDexSignature("La/b/C;foo()V");
- });
- }
-
- @Test
- public void testGetApiComponentsFromFieldLink() throws JavadocLinkSyntaxError {
- ApiComponents api = ApiComponents.fromLinkTag("a.b.C#foo(int, long, foo2.bar.Baz)",
- "La/b/C;->foo:I");
- PackageAndClassName packageAndClassName = api.getPackageAndClassName();
- assertThat(packageAndClassName.packageName).isEqualTo("a.b");
- assertThat(packageAndClassName.className).isEqualTo("C");
- assertThat(api.getMemberName()).isEqualTo("foo");
- }
-
- @Test
- public void testGetApiComponentsLinkOnlyClass() throws JavadocLinkSyntaxError {
- ApiComponents api = ApiComponents.fromLinkTag("b.c.D", "La/b/C;->foo:I");
- PackageAndClassName packageAndClassName = api.getPackageAndClassName();
- assertThat(packageAndClassName.packageName).isEqualTo("b.c");
- assertThat(packageAndClassName.className).isEqualTo("D");
- assertThat(api.getMethodParameterTypes()).isEqualTo("");
- }
-
- @Test
- public void testGetApiComponentsFromLinkOnlyClassDeducePackage() throws JavadocLinkSyntaxError {
- ApiComponents api = ApiComponents.fromLinkTag("D", "La/b/C;->foo:I");
- PackageAndClassName packageAndClassName = api.getPackageAndClassName();
- assertThat(packageAndClassName.packageName).isEqualTo("a.b");
- assertThat(packageAndClassName.className).isEqualTo("D");
- assertThat(api.getMemberName().isEmpty()).isTrue();
- assertThat(api.getMethodParameterTypes().isEmpty()).isTrue();
- }
-
- @Test
- public void testGetApiComponentsParametersFromMethodLink() throws JavadocLinkSyntaxError {
- ApiComponents api = ApiComponents.fromLinkTag("a.b.C#foo(int, long, foo2.bar.Baz)",
- "La/b/C;->foo:I");
- assertThat(api.getMethodParameterTypes()).isEqualTo("int, long, foo2.bar.Baz");
- }
-
- @Test
- public void testDeduceApiComponentsPackageFromLinkUsingContext() throws JavadocLinkSyntaxError {
- ApiComponents api = ApiComponents.fromLinkTag("C#foo(int, long, foo2.bar.Baz)",
- "La/b/C;->foo:I");
- PackageAndClassName packageAndClassName = api.getPackageAndClassName();
- assertThat(packageAndClassName.packageName).isEqualTo("a.b");
- }
-
- @Test
- public void testDeduceApiComponentsPackageAndClassFromLinkUsingContext()
- throws JavadocLinkSyntaxError {
- ApiComponents api = ApiComponents.fromLinkTag("#foo(int, long, foo2.bar.Baz)",
- "La/b/C;->foo:I");
- PackageAndClassName packageAndClassName = api.getPackageAndClassName();
- assertThat(packageAndClassName.packageName).isEqualTo("a.b");
- assertThat(packageAndClassName.className).isEqualTo("C");
- }
-
- @Test
- public void testInvalidLinkTagUnclosedParenthesis() throws JavadocLinkSyntaxError {
- assertThrows(JavadocLinkSyntaxError.class, () -> {
- ApiComponents.fromLinkTag("a.b.C#foo(int,float", "La/b/C;->foo()V");
- });
- }
-
-} \ No newline at end of file
diff --git a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiResolverTest.java b/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiResolverTest.java
deleted file mode 100644
index b51efcda86..0000000000
--- a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/ApiResolverTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2019 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.class2nonsdklist;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.expectThrows;
-import static org.testng.Assert.assertThrows;
-
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-public class ApiResolverTest extends AnnotationHandlerTestBase {
- @Test
- public void testFindPublicAlternativeExactly() throws Exception {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
- Arrays.asList("La/b/C;->foo(I)V", "La/b/C;->bar(I)V")));
- ApiResolver resolver = new ApiResolver(publicApis);
- resolver.resolvePublicAlternatives("{@link a.b.C#foo(int)}", "Lb/c/D;->bar()V", 1);
- }
-
- @Test
- public void testFindPublicAlternativeDeducedPackageName() throws Exception {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
- Arrays.asList("La/b/C;->foo(I)V", "La/b/C;->bar(I)V")));
- ApiResolver resolver = new ApiResolver(publicApis);
- resolver.resolvePublicAlternatives("{@link C#foo(int)}", "La/b/D;->bar()V", 1);
- }
-
- @Test
- public void testFindPublicAlternativeDeducedPackageAndClassName() throws Exception {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
- Arrays.asList("La/b/C;->foo(I)V", "La/b/C;->bar(I)V")));
- ApiResolver resolver = new ApiResolver(publicApis);
- resolver.resolvePublicAlternatives("{@link #foo(int)}", "La/b/C;->bar()V", 1);
- }
-
- @Test
- public void testFindPublicAlternativeDeducedParameterTypes() throws Exception {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
- Arrays.asList("La/b/C;->foo(I)V", "La/b/C;->bar(I)V")));
- ApiResolver resolver = new ApiResolver(publicApis);
- resolver.resolvePublicAlternatives("{@link #foo}", "La/b/C;->bar()V", 1);
- }
-
- @Test
- public void testFindPublicAlternativeWarnsOnMultipleParameterTypes()
- throws SignatureSyntaxError {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
- Arrays.asList("La/b/C;->foo(I)V", "La/b/C;->bar(I)I", "La/b/C;->foo(II)V")));
- ApiResolver resolver = new ApiResolver(publicApis);
- MultipleAlternativesFoundWarning e = expectThrows(MultipleAlternativesFoundWarning.class,
- () -> resolver.resolvePublicAlternatives("{@link #foo}", "La/b/C;->bar()V", 1));
- assertThat(e.almostMatches).containsExactly(
- ApiComponents.fromDexSignature("La/b/C;->foo(I)V"),
- ApiComponents.fromDexSignature("La/b/C;->foo(II)V")
- );
- }
-
- @Test
- public void testFindPublicAlternativeFailNoAlternative() {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
- Arrays.asList("La/b/C;->bar(I)V")));
- ApiResolver resolver = new ApiResolver(publicApis);
- assertThrows(MemberAlternativeNotFoundError.class, ()
- -> resolver.resolvePublicAlternatives("{@link #foo(int)}", "La/b/C;->bar()V", 1));
- }
-
- @Test
- public void testFindPublicAlternativeFailNoAlternativeNoParameterTypes() {
-
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
- Arrays.asList("La/b/C;->bar(I)V")));
- ApiResolver resolver = new ApiResolver(publicApis);
- assertThrows(MemberAlternativeNotFoundError.class,
- () -> resolver.resolvePublicAlternatives("{@link #foo}", "La/b/C;->bar()V", 1));
- }
-
- @Test
- public void testNoPublicClassAlternatives() {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>());
- ApiResolver resolver = new ApiResolver(publicApis);
- expectThrows(NoAlternativesSpecifiedError.class,
- () -> resolver.resolvePublicAlternatives("Foo", "La/b/C;->bar()V", 1));
- }
-
- @Test
- public void testPublicAlternativesJustPackageAndClassName() throws Exception {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
- Arrays.asList("La/b/C;->bar(I)V")));
- ApiResolver resolver = new ApiResolver(publicApis);
- resolver.resolvePublicAlternatives("Foo {@link a.b.C}", "Lb/c/D;->bar()V", 1);
- }
-
- @Test
- public void testPublicAlternativesJustClassName() throws Exception {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>(
- Arrays.asList("La/b/C;->bar(I)V")));
- ApiResolver resolver = new ApiResolver(publicApis);
- resolver.resolvePublicAlternatives("Foo {@link C}", "La/b/D;->bar()V", 1);
- }
-
- @Test
- public void testNoPublicAlternativesButHasExplanation() throws Exception {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>());
- ApiResolver resolver = new ApiResolver(publicApis);
- resolver.resolvePublicAlternatives("Foo {@code bar}", "La/b/C;->bar()V", 1);
- }
-
- @Test
- public void testNoPublicAlternativesSpecifiedWithMaxSdk() {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>());
- ApiResolver resolver = new ApiResolver(publicApis);
- assertThrows(RequiredAlternativeNotSpecifiedError.class,
- () -> resolver.resolvePublicAlternatives(null, "La/b/C;->bar()V", 29));
- }
-
- @Test
- public void testNoPublicAlternativesSpecifiedWithMaxLessThanQ() throws Exception {
- Set<String> publicApis = Collections.unmodifiableSet(new HashSet<>());
- ApiResolver resolver = new ApiResolver(publicApis);
- resolver.resolvePublicAlternatives(null, "La/b/C;->bar()V", 28);
- }
-
-} \ No newline at end of file
diff --git a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/CovariantReturnTypeHandlerTest.java b/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/CovariantReturnTypeHandlerTest.java
deleted file mode 100644
index aa87148d44..0000000000
--- a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/CovariantReturnTypeHandlerTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2018 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.class2nonsdklist;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import static java.util.Collections.emptySet;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import java.io.IOException;
-import java.util.Map;
-
-public class CovariantReturnTypeHandlerTest extends AnnotationHandlerTestBase {
-
- private static final String ANNOTATION = "Lannotation/Annotation;";
- private static final String FLAG = "test-flag";
-
- @Before
- public void setup() throws IOException {
- // To keep the test simpler and more concise, we don't use the real
- // @CovariantReturnType annotation here, but use our own @Annotation.
- // It doesn't have to match the real annotation, just have the same
- // property (returnType).
- mJavac.addSource("annotation.Annotation", Joiner.on('\n').join(
- "package annotation;",
- "import static java.lang.annotation.RetentionPolicy.CLASS;",
- "import java.lang.annotation.Retention;",
- "@Retention(CLASS)",
- "public @interface Annotation {",
- " Class<?> returnType();",
- "}"));
- }
-
- @Test
- public void testReturnTypeWhitelisted() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Annotation;",
- "public class Class {",
- " @Annotation(returnType=Integer.class)",
- " public String method() {return null;}",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION,
- new CovariantReturnTypeHandler(
- mConsumer,
- ImmutableSet.of("La/b/Class;->method()Ljava/lang/String;"),
- FLAG));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
-
- assertNoErrors();
- verify(mConsumer, times(1)).consume(
- eq("La/b/Class;->method()Ljava/lang/Integer;"), any(), eq(ImmutableSet.of(FLAG)));
- }
-
- @Test
- public void testAnnotatedMemberNotPublicApi() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Annotation;",
- "public class Class {",
- " @Annotation(returnType=Integer.class)",
- " public String method() {return null;}",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION,
- new CovariantReturnTypeHandler(
- mConsumer,
- emptySet(),
- FLAG));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
-
- verify(mStatus, atLeastOnce()).error(any(), any());
- }
-
- @Test
- public void testReturnTypeAlreadyWhitelisted() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Annotation;",
- "public class Class {",
- " @Annotation(returnType=Integer.class)",
- " public String method() {return null;}",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION,
- new CovariantReturnTypeHandler(
- mConsumer,
- ImmutableSet.of(
- "La/b/Class;->method()Ljava/lang/String;",
- "La/b/Class;->method()Ljava/lang/Integer;"
- ),
- FLAG));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
-
- verify(mStatus, atLeastOnce()).error(any(), any());
- }
-
- @Test
- public void testAnnotationOnField() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Annotation;",
- "public class Class {",
- " @Annotation(returnType=Integer.class)",
- " public String field;",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION,
- new CovariantReturnTypeHandler(
- mConsumer,
- emptySet(),
- FLAG));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
-
- verify(mStatus, atLeastOnce()).error(any(), any());
- }
-}
diff --git a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/RepeatedAnnotationHandlerTest.java b/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/RepeatedAnnotationHandlerTest.java
deleted file mode 100644
index 6d1df31d3a..0000000000
--- a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/RepeatedAnnotationHandlerTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2018 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.class2nonsdklist;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableMap;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import org.apache.bcel.classfile.AnnotationEntry;
-import org.junit.Before;
-import org.junit.Test;
-
-public class RepeatedAnnotationHandlerTest extends AnnotationHandlerTestBase {
-
- @Before
- public void setup() {
- // To keep the test simpler and more concise, we don't use a real annotation here, but use
- // our own @Annotation and @Annotation.Multi that have the same relationship.
- mJavac.addSource("annotation.Annotation", Joiner.on('\n').join(
- "package annotation;",
- "import static java.lang.annotation.RetentionPolicy.CLASS;",
- "import java.lang.annotation.Repeatable;",
- "import java.lang.annotation.Retention;",
- "@Repeatable(Annotation.Multi.class)",
- "@Retention(CLASS)",
- "public @interface Annotation {",
- " Class<?> clazz();",
- " @Retention(CLASS)",
- " @interface Multi {",
- " Annotation[] value();",
- " }",
- "}"));
- }
-
- @Test
- public void testRepeated() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Annotation;",
- "public class Class {",
- " @Annotation(clazz=Integer.class)",
- " @Annotation(clazz=Long.class)",
- " public String method() {return null;}",
- "}"));
- mJavac.compile();
-
- TestAnnotationHandler handler = new TestAnnotationHandler();
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of("Lannotation/Annotation$Multi;",
- new RepeatedAnnotationHandler("Lannotation/Annotation;", handler));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
-
- assertNoErrors();
- assertThat(handler.getClasses()).containsExactly(
- "Ljava/lang/Integer;",
- "Ljava/lang/Long;");
- }
-
- private static class TestAnnotationHandler extends AnnotationHandler {
-
- private final List<String> classes;
-
- private TestAnnotationHandler() {
- this.classes = new ArrayList<>();
- }
-
- @Override
- void handleAnnotation(AnnotationEntry annotation,
- AnnotationContext context) {
- classes.add(annotation.getElementValuePairs()[0].getValue().stringifyValue());
- }
-
- private List<String> getClasses() {
- return classes;
- }
- }
-}
diff --git a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandlerTest.java b/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandlerTest.java
deleted file mode 100644
index 7e7d22cf7c..0000000000
--- a/tools/class2nonsdklist/test/src/com/android/class2nonsdklist/UnsupportedAppUsageAnnotationHandlerTest.java
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- * Copyright (C) 2018 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.class2nonsdklist;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import static java.util.Collections.emptyMap;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Predicate;
-
-public class UnsupportedAppUsageAnnotationHandlerTest extends AnnotationHandlerTestBase {
-
- private static final String ANNOTATION = "Lannotation/Anno;";
-
- private static final Map<Integer, String> NULL_SDK_MAP;
- static {
- Map<Integer, String> map = new HashMap<>();
- map.put(null, "flag-null");
- NULL_SDK_MAP = Collections.unmodifiableMap(map);
- }
-
- @Before
- public void setup() throws IOException {
- mJavac.addSource("annotation.Anno", Joiner.on('\n').join(
- "package annotation;",
- "import static java.lang.annotation.RetentionPolicy.CLASS;",
- "import java.lang.annotation.Retention;",
- "import java.lang.annotation.Repeatable;",
- "@Retention(CLASS)",
- "@Repeatable(Anno.Container.class)",
- "public @interface Anno {",
- " String expectedSignature() default \"\";",
- " int maxTargetSdk() default Integer.MAX_VALUE;",
- " String implicitMember() default \"\";",
- " @Retention(CLASS)",
- " public @interface Container {",
- " Anno[] value();",
- " }",
- "}"));
- }
-
- private UnsupportedAppUsageAnnotationHandler createGreylistHandler(
- Predicate<UnsupportedAppUsageAnnotationHandler.ClassMember> greylistFilter,
- Map<Integer, String> validMaxTargetSdkValues) {
- return new UnsupportedAppUsageAnnotationHandler(
- mStatus, mConsumer, greylistFilter, validMaxTargetSdkValues);
- }
-
- @Test
- public void testGreylistMethod() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class {",
- " @Anno",
- " public void method() {}",
- "}"));
- mJavac.compile();
-
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus,
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP))
- ).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- verify(mConsumer, times(1)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method()V");
- }
-
- @Test
- public void testGreylistConstructor() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class {",
- " @Anno",
- " public Class() {}",
- "}"));
- mJavac.compile();
-
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus,
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP))
- ).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- verify(mConsumer, times(1)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getValue()).isEqualTo("La/b/Class;-><init>()V");
- }
-
- @Test
- public void testGreylistField() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class {",
- " @Anno",
- " public int i;",
- "}"));
- mJavac.compile();
-
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus,
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP))
- ).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- verify(mConsumer, times(1)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getValue()).isEqualTo("La/b/Class;->i:I");
- }
-
- @Test
- public void testGreylistImplicit() throws IOException {
- mJavac.addSource("a.b.EnumClass", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "@Anno(implicitMember=\"values()[La/b/EnumClass;\")",
- "public enum EnumClass {",
- " VALUE",
- "}"));
- mJavac.compile();
-
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.EnumClass"), mStatus,
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP))
- ).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- verify(mConsumer, times(1)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getValue()).isEqualTo("La/b/EnumClass;->values()[La/b/EnumClass;");
- }
-
- @Test
- public void testGreylistImplicit_Invalid_MissingOnClass() throws IOException {
- mJavac.addSource("a.b.EnumClass", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "@Anno",
- "public enum EnumClass {",
- " VALUE",
- "}"));
- mJavac.compile();
-
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.EnumClass"), mStatus,
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP))
- ).visit();
-
- ArgumentCaptor<String> format = ArgumentCaptor.forClass(String.class);
- verify(mStatus, times(1)).error(format.capture(), any());
- // Ensure that the correct error is reported.
- assertThat(format.getValue())
- .contains("Missing property implicitMember on annotation on class");
- }
-
- @Test
- public void testGreylistImplicit_Invalid_PresentOnMember() throws IOException {
- mJavac.addSource("a.b.EnumClass", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public enum EnumClass {",
- " @Anno(implicitMember=\"values()[La/b/EnumClass;\")",
- " VALUE",
- "}"));
- mJavac.compile();
-
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.EnumClass"), mStatus,
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP))
- ).visit();
-
- ArgumentCaptor<String> format = ArgumentCaptor.forClass(String.class);
- verify(mStatus, times(1)).error(format.capture(), any());
- assertThat(format.getValue())
- .contains("Expected annotation with an implicitMember property to be on a class");
- }
-
- @Test
- public void testGreylistMethodExpectedSignature() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class {",
- " @Anno(expectedSignature=\"La/b/Class;->method()V\")",
- " public void method() {}",
- "}"));
- mJavac.compile();
-
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus,
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP))
- ).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- verify(mConsumer, times(1)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method()V");
- }
-
- @Test
- public void testGreylistMethodExpectedSignatureWrong() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class {",
- " @Anno(expectedSignature=\"La/b/Class;->nomethod()V\")",
- " public void method() {}",
- "}"));
- mJavac.compile();
-
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus,
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP))
- ).visit();
-
- verify(mStatus, times(1)).error(any(), any());
- }
-
- @Test
- public void testGreylistInnerClassMethod() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class {",
- " public class Inner {",
- " @Anno",
- " public void method() {}",
- " }",
- "}"));
- mJavac.compile();
-
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class$Inner"), mStatus,
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP))
- ).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- verify(mConsumer, times(1)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getValue()).isEqualTo("La/b/Class$Inner;->method()V");
- }
-
- @Test
- public void testMethodNotGreylisted() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "public class Class {",
- " public void method() {}",
- "}"));
- mJavac.compile();
-
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus,
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP))
- ).visit();
-
- assertNoErrors();
- verify(mConsumer, never()).consume(any(String.class), any(), any());
- }
-
- @Test
- public void testMethodArgGenerics() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class<T extends String> {",
- " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")",
- " public void method(T arg) {}",
- "}"));
- mJavac.compile();
-
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus,
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP))
- ).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- verify(mConsumer, times(1)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method(Ljava/lang/String;)V");
- }
-
- @Test
- public void testOverrideMethodWithBridge() throws IOException {
- mJavac.addSource("a.b.Base", Joiner.on('\n').join(
- "package a.b;",
- "abstract class Base<T> {",
- " protected abstract void method(T arg);",
- "}"));
-
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class<T extends String> extends Base<T> {",
- " @Override",
- " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")",
- " public void method(T arg) {}",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), mStatus, handlerMap).visit();
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- // A bridge method is generated for the above, so we expect 2 greylist entries.
- verify(mConsumer, times(2)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getAllValues()).containsExactly(
- "La/b/Class;->method(Ljava/lang/Object;)V",
- "La/b/Class;->method(Ljava/lang/String;)V");
- }
-
- @Test
- public void testOverridePublicMethodWithBridge() throws IOException {
- mJavac.addSource("a.b.Base", Joiner.on('\n').join(
- "package a.b;",
- "public abstract class Base<T> {",
- " public void method(T arg) {}",
- "}"));
-
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class<T extends String> extends Base<T> {",
- " @Override",
- " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")",
- " public void method(T arg) {}",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), mStatus, handlerMap).visit();
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- // A bridge method is generated for the above, so we expect 2 greylist entries.
- verify(mConsumer, times(2)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getAllValues()).containsExactly(
- "La/b/Class;->method(Ljava/lang/Object;)V",
- "La/b/Class;->method(Ljava/lang/String;)V");
- }
-
- @Test
- public void testBridgeMethodsFromInterface() throws IOException {
- mJavac.addSource("a.b.Interface", Joiner.on('\n').join(
- "package a.b;",
- "public interface Interface {",
- " public void method(Object arg);",
- "}"));
-
- mJavac.addSource("a.b.Base", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "class Base {",
- " @Anno(expectedSignature=\"La/b/Base;->method(Ljava/lang/Object;)V\")",
- " public void method(Object arg) {}",
- "}"));
-
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "public class Class extends Base implements Interface {",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Interface"), mStatus, handlerMap)
- .visit();
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), mStatus, handlerMap).visit();
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- // A bridge method is generated for the above, so we expect 2 greylist entries.
- verify(mConsumer, times(2)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getAllValues()).containsExactly(
- "La/b/Class;->method(Ljava/lang/Object;)V",
- "La/b/Base;->method(Ljava/lang/Object;)V");
- }
-
- @Test
- public void testPublicBridgeExcluded() throws IOException {
- mJavac.addSource("a.b.Base", Joiner.on('\n').join(
- "package a.b;",
- "public abstract class Base<T> {",
- " public void method(T arg) {}",
- "}"));
-
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class<T extends String> extends Base<T> {",
- " @Override",
- " @Anno",
- " public void method(T arg) {}",
- "}"));
- mJavac.compile();
-
- Set<String> publicApis = Sets.newHashSet(
- "La/b/Base;->method(Ljava/lang/Object;)V",
- "La/b/Class;->method(Ljava/lang/Object;)V");
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION,
- new UnsupportedAppUsageAnnotationHandler(
- mStatus,
- mConsumer,
- publicApis,
- NULL_SDK_MAP));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), mStatus, handlerMap).visit();
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- // The bridge method generated for the above, is a public API so should be excluded
- verify(mConsumer, times(1)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method(Ljava/lang/String;)V");
- }
-
- @Test
- public void testVolatileField() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class {",
- " @Anno(expectedSignature=\"La/b/Class;->field:I\")",
- " public volatile int field;",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION, createGreylistHandler(
- member -> !member.isBridgeMethod, // exclude bridge methods
- NULL_SDK_MAP));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
- assertNoErrors();
- ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
- verify(mConsumer, times(1)).consume(greylist.capture(), any(), any());
- assertThat(greylist.getValue()).isEqualTo("La/b/Class;->field:I");
- }
-
- @Test
- public void testVolatileFieldWrongSignature() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class {",
- " @Anno(expectedSignature=\"La/b/Class;->wrong:I\")",
- " public volatile int field;",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION, createGreylistHandler(x -> true, NULL_SDK_MAP));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
- verify(mStatus, times(1)).error(any(), any());
- }
-
- @Test
- public void testMethodMaxTargetSdk() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class {",
- " @Anno(maxTargetSdk=1)",
- " public int field;",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION, createGreylistHandler(
- x -> true,
- ImmutableMap.of(1, "flag1")));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
- assertNoErrors();
- verify(mConsumer, times(1)).consume(any(), any(), eq(ImmutableSet.of("flag1")));
- }
-
- @Test
- public void testMethodNoMaxTargetSdk() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class {",
- " @Anno",
- " public int field;",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION, createGreylistHandler(
- x -> true,
- NULL_SDK_MAP));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
- assertNoErrors();
- verify(mConsumer, times(1)).consume(any(), any(), eq(ImmutableSet.of("flag-null")));
- }
-
- @Test
- public void testMethodMaxTargetSdkOutOfRange() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno;",
- "public class Class {",
- " @Anno(maxTargetSdk=2)",
- " public int field;",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of(ANNOTATION, createGreylistHandler(
- x -> true,
- NULL_SDK_MAP));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
- verify(mStatus, times(1)).error(any(), any());
- }
-
- @Test
- public void testAnnotationPropertiesIntoMap() throws IOException {
- mJavac.addSource("annotation.Anno2", Joiner.on('\n').join(
- "package annotation;",
- "import static java.lang.annotation.RetentionPolicy.CLASS;",
- "import java.lang.annotation.Retention;",
- "@Retention(CLASS)",
- "public @interface Anno2 {",
- " String expectedSignature() default \"\";",
- " int maxTargetSdk() default Integer.MAX_VALUE;",
- " long trackingBug() default 0;",
- "}"));
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno2;",
- "public class Class {",
- " @Anno2(maxTargetSdk=2, trackingBug=123456789)",
- " public int field;",
- "}"));
- mJavac.compile();
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus,
- ImmutableMap.of("Lannotation/Anno2;", createGreylistHandler(x -> true,
- ImmutableMap.of(2, "flag2")))
- ).visit();
-
- assertNoErrors();
- ArgumentCaptor<Map<String, String>> properties = ArgumentCaptor.forClass(Map.class);
- verify(mConsumer, times(1)).consume(any(), properties.capture(), any());
- assertThat(properties.getValue()).containsExactly(
- "maxTargetSdk", "2",
- "trackingBug", "123456789");
- }
-
-
- @Test
- public void testSpecialCaseBug170729553AnnotationPropertiesIntoMap() throws IOException {
- mJavac.addSource("annotation.Anno2", Joiner.on('\n').join(
- "package annotation;",
- "import static java.lang.annotation.RetentionPolicy.CLASS;",
- "import java.lang.annotation.Retention;",
- "@Retention(CLASS)",
- "public @interface Anno2 {",
- " String expectedSignature() default \"\";",
- " int maxTargetSdk() default Integer.MAX_VALUE;",
- " long trackingBug() default 0;",
- "}"));
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Anno2;",
- "public class Class {",
- " @Anno2(maxTargetSdk=30, trackingBug=170729553)",
- " public int field;",
- "}"));
- mJavac.compile();
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus,
- ImmutableMap.of("Lannotation/Anno2;", createGreylistHandler(x -> true,
- ImmutableMap.of(0, "flag0")))
- ).visit();
-
- assertNoErrors();
- ArgumentCaptor<Map<String, String>> properties = ArgumentCaptor.forClass(Map.class);
- verify(mConsumer, times(1)).consume(any(), properties.capture(), any());
- assertThat(properties.getValue()).containsExactly(
- "maxTargetSdk", "0",
- "trackingBug", "170729553");
- }
-}