Skip to content
Snippets Groups Projects
Commit 810d01d7 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 5357520 from a0f64d2e to qt-release

Change-Id: Iee08f1a3b87e5dd565f4ea0ec4f4d5230acb8a5b
parents 19558586 a0f64d2e
No related branches found
No related tags found
No related merge requests found
...@@ -148,6 +148,7 @@ const val ARG_STUB_PACKAGES = "--stub-packages" ...@@ -148,6 +148,7 @@ const val ARG_STUB_PACKAGES = "--stub-packages"
const val ARG_STUB_IMPORT_PACKAGES = "--stub-import-packages" const val ARG_STUB_IMPORT_PACKAGES = "--stub-import-packages"
const val ARG_DELETE_EMPTY_BASELINES = "--delete-empty-baselines" const val ARG_DELETE_EMPTY_BASELINES = "--delete-empty-baselines"
const val ARG_SUBTRACT_API = "--subtract-api" const val ARG_SUBTRACT_API = "--subtract-api"
const val ARG_TYPEDEFS_IN_SIGNATURES = "--typedefs-in-signatures"
class Options( class Options(
private val args: Array<String>, private val args: Array<String>,
...@@ -556,6 +557,15 @@ class Options( ...@@ -556,6 +557,15 @@ class Options(
/** List of signature files to export as JDiff files */ /** List of signature files to export as JDiff files */
val convertToXmlFiles: List<ConvertFile> = mutableConvertToXmlFiles val convertToXmlFiles: List<ConvertFile> = mutableConvertToXmlFiles
enum class TypedefMode {
NONE,
REFERENCE,
INLINE
}
/** How to handle typedef annotations in signature files; corresponds to $ARG_TYPEDEFS_IN_SIGNATURES */
var typedefMode = TypedefMode.NONE
/** File conversion tasks */ /** File conversion tasks */
data class ConvertFile( data class ConvertFile(
val fromApiFile: File, val fromApiFile: File,
...@@ -769,6 +779,17 @@ class Options( ...@@ -769,6 +779,17 @@ class Options(
mutableSkipEmitPackages += packages.split(File.pathSeparatorChar) mutableSkipEmitPackages += packages.split(File.pathSeparatorChar)
} }
ARG_TYPEDEFS_IN_SIGNATURES -> {
val type = getValue(args, ++index)
typedefMode = when (type) {
"ref" -> TypedefMode.REFERENCE
"inline" -> TypedefMode.INLINE
"none" -> TypedefMode.NONE
else -> throw DriverException(
stderr = "$ARG_TYPEDEFS_IN_SIGNATURES must be one of ref, inline, none; was $type")
}
}
ARG_BASELINE -> { ARG_BASELINE -> {
val relative = getValue(args, ++index) val relative = getValue(args, ++index)
assert(baselineFile == null) { "Only one baseline is allowed; found both $baselineFile and $relative" } assert(baselineFile == null) { "Only one baseline is allowed; found both $baselineFile and $relative" }
...@@ -1922,6 +1943,12 @@ class Options( ...@@ -1922,6 +1943,12 @@ class Options(
"$ARG_SUBTRACT_API <api file>", "Subtracts the API in the given signature or jar file from the " + "$ARG_SUBTRACT_API <api file>", "Subtracts the API in the given signature or jar file from the " +
"current API being emitted via $ARG_API, $ARG_STUBS, $ARG_DOC_STUBS, etc. " + "current API being emitted via $ARG_API, $ARG_STUBS, $ARG_DOC_STUBS, etc. " +
"Note that the subtraction only applies to classes; it does not subtract members.", "Note that the subtraction only applies to classes; it does not subtract members.",
"$ARG_TYPEDEFS_IN_SIGNATURES <ref|inline>", "Whether to include typedef annotations in signature " +
"files. `$ARG_TYPEDEFS_IN_SIGNATURES ref` will include just a reference to the typedef class, " +
"which is not itself part of the API and is not included as a class, and " +
"`$ARG_TYPEDEFS_IN_SIGNATURES inline` will include the constants themselves into each usage " +
"site. You can also supply `$ARG_TYPEDEFS_IN_SIGNATURES none` to explicitly turn it off, if the " +
"default ever changes.",
"", "\nDocumentation:", "", "\nDocumentation:",
ARG_PUBLIC, "Only include elements that are public", ARG_PUBLIC, "Only include elements that are public",
......
...@@ -32,6 +32,7 @@ import com.android.tools.metalava.ANDROID_NULLABLE ...@@ -32,6 +32,7 @@ import com.android.tools.metalava.ANDROID_NULLABLE
import com.android.tools.metalava.ANDROID_SUPPORT_ANNOTATION_PREFIX import com.android.tools.metalava.ANDROID_SUPPORT_ANNOTATION_PREFIX
import com.android.tools.metalava.Compatibility import com.android.tools.metalava.Compatibility
import com.android.tools.metalava.JAVA_LANG_PREFIX import com.android.tools.metalava.JAVA_LANG_PREFIX
import com.android.tools.metalava.Options
import com.android.tools.metalava.RECENTLY_NONNULL import com.android.tools.metalava.RECENTLY_NONNULL
import com.android.tools.metalava.RECENTLY_NULLABLE import com.android.tools.metalava.RECENTLY_NULLABLE
import com.android.tools.metalava.doclava1.ApiPredicate import com.android.tools.metalava.doclava1.ApiPredicate
...@@ -85,6 +86,9 @@ interface AnnotationItem { ...@@ -85,6 +86,9 @@ interface AnnotationItem {
/** True if this annotation represents @IntDef, @LongDef or @StringDef */ /** True if this annotation represents @IntDef, @LongDef or @StringDef */
fun isTypeDefAnnotation(): Boolean { fun isTypeDefAnnotation(): Boolean {
val name = qualifiedName() ?: return false val name = qualifiedName() ?: return false
if (!(name.endsWith("Def"))) {
return false
}
return (INT_DEF_ANNOTATION.isEquals(name) || return (INT_DEF_ANNOTATION.isEquals(name) ||
STRING_DEF_ANNOTATION.isEquals(name) || STRING_DEF_ANNOTATION.isEquals(name) ||
LONG_DEF_ANNOTATION.isEquals(name) || LONG_DEF_ANNOTATION.isEquals(name) ||
...@@ -120,6 +124,12 @@ interface AnnotationItem { ...@@ -120,6 +124,12 @@ interface AnnotationItem {
return codebase.findClass(qualifiedName() ?: return null) return codebase.findClass(qualifiedName() ?: return null)
} }
/** If this annotation has a typedef annotation associated with it, return it */
fun findTypedefAnnotation(): AnnotationItem? {
val className = originalName() ?: return null
return codebase.findClass(className)?.modifiers?.annotations()?.firstOrNull { it.isTypeDefAnnotation() }
}
/** Returns the retention of this annotation */ /** Returns the retention of this annotation */
val retention: AnnotationRetention val retention: AnnotationRetention
get() { get() {
...@@ -466,6 +476,12 @@ interface AnnotationItem { ...@@ -466,6 +476,12 @@ interface AnnotationItem {
// See if the annotation is pointing to an annotation class that is part of the API; if not, skip it. // See if the annotation is pointing to an annotation class that is part of the API; if not, skip it.
val cls = codebase.findClass(qualifiedName) ?: return NO_ANNOTATION_TARGETS val cls = codebase.findClass(qualifiedName) ?: return NO_ANNOTATION_TARGETS
if (!ApiPredicate().test(cls)) { if (!ApiPredicate().test(cls)) {
if (options.typedefMode != Options.TypedefMode.NONE) {
if (cls.modifiers.annotations().any { it.isTypeDefAnnotation() }) {
return ANNOTATION_SIGNATURE_ONLY
}
}
return NO_ANNOTATION_TARGETS return NO_ANNOTATION_TARGETS
} }
......
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
package com.android.tools.metalava.model package com.android.tools.metalava.model
import com.android.tools.metalava.Options
import com.android.tools.metalava.options
/** Various places where a given annotation can be written */ /** Various places where a given annotation can be written */
enum class AnnotationTarget { enum class AnnotationTarget {
/** Write the annotation into the signature file */ /** Write the annotation into the signature file */
...@@ -80,4 +83,11 @@ val ANNOTATION_IN_DOC_STUBS_AND_EXTERNAL = setOf( ...@@ -80,4 +83,11 @@ val ANNOTATION_IN_DOC_STUBS_AND_EXTERNAL = setOf(
val ANNOTATION_EXTERNAL = setOf(AnnotationTarget.SIGNATURE_FILE, AnnotationTarget.EXTERNAL_ANNOTATIONS_FILE) val ANNOTATION_EXTERNAL = setOf(AnnotationTarget.SIGNATURE_FILE, AnnotationTarget.EXTERNAL_ANNOTATIONS_FILE)
/** Write it only into the external annotations file, not the signature file */ /** Write it only into the external annotations file, not the signature file */
val ANNOTATION_EXTERNAL_ONLY = setOf(AnnotationTarget.SIGNATURE_FILE, AnnotationTarget.EXTERNAL_ANNOTATIONS_FILE) val ANNOTATION_EXTERNAL_ONLY = if (options.typedefMode == Options.TypedefMode.INLINE ||
options.typedefMode == Options.TypedefMode.NONE) // just here for compatibility purposes
setOf(AnnotationTarget.SIGNATURE_FILE, AnnotationTarget.EXTERNAL_ANNOTATIONS_FILE)
else
setOf(AnnotationTarget.EXTERNAL_ANNOTATIONS_FILE)
/** Write it only into the he signature file */
val ANNOTATION_SIGNATURE_ONLY = setOf(AnnotationTarget.SIGNATURE_FILE)
...@@ -493,6 +493,7 @@ interface ModifierList { ...@@ -493,6 +493,7 @@ interface ModifierList {
continue continue
} }
var printAnnotation = annotation
if (!annotation.targets().contains(target)) { if (!annotation.targets().contains(target)) {
continue continue
} else if ((annotation.isNullnessAnnotation())) { } else if ((annotation.isNullnessAnnotation())) {
...@@ -502,6 +503,23 @@ interface ModifierList { ...@@ -502,6 +503,23 @@ interface ModifierList {
} else if (annotation.qualifiedName() == "java.lang.Deprecated") { } else if (annotation.qualifiedName() == "java.lang.Deprecated") {
// Special cased in stubs and signature files: emitted first // Special cased in stubs and signature files: emitted first
continue continue
} else if (options.typedefMode == Options.TypedefMode.INLINE) {
val typedef = annotation.findTypedefAnnotation()
if (typedef != null) {
printAnnotation = typedef
}
} else if (options.typedefMode == Options.TypedefMode.REFERENCE &&
annotation.targets() === ANNOTATION_SIGNATURE_ONLY &&
annotation.findTypedefAnnotation() != null) {
// For annotation references, only include the simple name
writer.write("@")
writer.write(annotation.resolve()?.simpleName() ?: annotation.qualifiedName()!!)
if (separateLines) {
writer.write("\n")
} else {
writer.write(" ")
}
continue
} }
// Optionally filter out duplicates // Optionally filter out duplicates
...@@ -520,7 +538,8 @@ interface ModifierList { ...@@ -520,7 +538,8 @@ interface ModifierList {
} }
} }
val source = annotation.toSource(target) val source = printAnnotation.toSource(target)
if (omitCommonPackages) { if (omitCommonPackages) {
writer.write(AnnotationItem.shortenAnnotation(source)) writer.write(AnnotationItem.shortenAnnotation(source))
} else { } else {
......
...@@ -21,13 +21,9 @@ import org.junit.Test ...@@ -21,13 +21,9 @@ import org.junit.Test
@SuppressWarnings("ALL") // Sample code @SuppressWarnings("ALL") // Sample code
class ExtractAnnotationsTest : DriverTest() { class ExtractAnnotationsTest : DriverTest() {
@Test private val sourceFiles1 = arrayOf(
fun `Check java typedef extraction and warning about non-source retention of typedefs`() { java(
check( """
includeSourceRetentionAnnotations = false,
sourceFiles = *arrayOf(
java(
"""
package test.pkg; package test.pkg;
import android.annotation.IntDef; import android.annotation.IntDef;
...@@ -70,10 +66,17 @@ class ExtractAnnotationsTest : DriverTest() { ...@@ -70,10 +66,17 @@ class ExtractAnnotationsTest : DriverTest() {
} }
} }
""" """
).indented(), ).indented(),
intDefAnnotationSource, intDefAnnotationSource,
intRangeAnnotationSource intRangeAnnotationSource
), )
@Test
fun `Check java typedef extraction and warning about non-source retention of typedefs`() {
check(
includeSourceRetentionAnnotations = false,
format = FileFormat.V2,
sourceFiles = *sourceFiles1,
warnings = "src/test/pkg/IntDefTest.java:11: error: This typedef annotation class should have @Retention(RetentionPolicy.SOURCE) [AnnotationExtraction]", warnings = "src/test/pkg/IntDefTest.java:11: error: This typedef annotation class should have @Retention(RetentionPolicy.SOURCE) [AnnotationExtraction]",
extractAnnotations = mapOf( extractAnnotations = mapOf(
"test.pkg" to """ "test.pkg" to """
...@@ -509,4 +512,112 @@ class ExtractAnnotationsTest : DriverTest() { ...@@ -509,4 +512,112 @@ class ExtractAnnotationsTest : DriverTest() {
) )
) )
} }
@Test
fun `No typedef signatures in api files`() {
check(
includeSourceRetentionAnnotations = false,
extraArguments = arrayOf(
ARG_HIDE_PACKAGE, "android.annotation",
ARG_TYPEDEFS_IN_SIGNATURES, "none"
),
format = FileFormat.V2,
sourceFiles = *sourceFiles1,
api = """
// Signature format: 2.0
package test.pkg {
public class IntDefTest {
ctor public IntDefTest();
method public void setFlags(Object, int);
method public void setStyle(int, int);
method public void testIntDef(int);
field public static final int STYLE_NORMAL = 0; // 0x0
field public static final int STYLE_NO_FRAME = 2; // 0x2
field public static final int STYLE_NO_INPUT = 3; // 0x3
field public static final int STYLE_NO_TITLE = 1; // 0x1
field public static final String TYPE_1 = "type1";
field public static final String TYPE_2 = "type2";
field public static final int UNRELATED = 3; // 0x3
field public static final String UNRELATED_TYPE = "other";
}
public static class IntDefTest.Inner {
ctor public IntDefTest.Inner();
method public void setInner(int);
}
}
"""
)
}
@Test
fun `Inlining typedef signatures in api files`() {
check(
includeSourceRetentionAnnotations = false,
extraArguments = arrayOf(
ARG_HIDE_PACKAGE, "android.annotation",
ARG_TYPEDEFS_IN_SIGNATURES, "inline"
),
format = FileFormat.V2,
sourceFiles = *sourceFiles1,
api = """
// Signature format: 2.0
package test.pkg {
public class IntDefTest {
ctor public IntDefTest();
method public void setFlags(Object, @IntDef(value={test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 3 + 1}, flag=true) int);
method public void setStyle(@IntDef({test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT}) int, int);
method public void testIntDef(int);
field public static final int STYLE_NORMAL = 0; // 0x0
field public static final int STYLE_NO_FRAME = 2; // 0x2
field public static final int STYLE_NO_INPUT = 3; // 0x3
field public static final int STYLE_NO_TITLE = 1; // 0x1
field public static final String TYPE_1 = "type1";
field public static final String TYPE_2 = "type2";
field public static final int UNRELATED = 3; // 0x3
field public static final String UNRELATED_TYPE = "other";
}
public static class IntDefTest.Inner {
ctor public IntDefTest.Inner();
method public void setInner(@IntDef(value={test.pkg.IntDefTest.STYLE_NORMAL, test.pkg.IntDefTest.STYLE_NO_TITLE, test.pkg.IntDefTest.STYLE_NO_FRAME, test.pkg.IntDefTest.STYLE_NO_INPUT, 3, 3 + 1}, flag=true) int);
}
}
"""
)
}
@Test
fun `Referencing typedef signatures in api files`() {
check(
includeSourceRetentionAnnotations = false,
extraArguments = arrayOf(
ARG_HIDE_PACKAGE, "android.annotation",
ARG_TYPEDEFS_IN_SIGNATURES, "ref"
),
format = FileFormat.V2,
sourceFiles = *sourceFiles1,
api = """
// Signature format: 2.0
package test.pkg {
public class IntDefTest {
ctor public IntDefTest();
method public void setFlags(Object, @DialogFlags int);
method public void setStyle(@DialogStyle int, int);
method public void testIntDef(int);
field public static final int STYLE_NORMAL = 0; // 0x0
field public static final int STYLE_NO_FRAME = 2; // 0x2
field public static final int STYLE_NO_INPUT = 3; // 0x3
field public static final int STYLE_NO_TITLE = 1; // 0x1
field public static final String TYPE_1 = "type1";
field public static final String TYPE_2 = "type2";
field public static final int UNRELATED = 3; // 0x3
field public static final String UNRELATED_TYPE = "other";
}
public static class IntDefTest.Inner {
ctor public IntDefTest.Inner();
method public void setInner(@DialogFlags int);
}
}
"""
)
}
} }
\ No newline at end of file
...@@ -121,6 +121,16 @@ API sources: ...@@ -121,6 +121,16 @@ API sources:
--api, --stubs, --doc-stubs, etc. Note that the --api, --stubs, --doc-stubs, etc. Note that the
subtraction only applies to classes; it does not subtraction only applies to classes; it does not
subtract members. subtract members.
--typedefs-in-signatures <ref|inline> Whether to include typedef annotations in
signature files. `--typedefs-in-signatures ref`
will include just a reference to the typedef
class, which is not itself part of the API and
is not included as a class, and
`--typedefs-in-signatures inline` will include
the constants themselves into each usage site.
You can also supply `--typedefs-in-signatures
none` to explicitly turn it off, if the default
ever changes.
Documentation: Documentation:
--public Only include elements that are public --public Only include elements that are public
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment