Skip to content
Snippets Groups Projects
Commit 67cbd3a7 authored by Tor Norbye's avatar Tor Norbye Committed by android-build-merger
Browse files

Merge "Automatic documentation for "@Column" annotation." am: 79d3acf0 am: d66f2002

am: 6e1372ab

Change-Id: I6024e5776fc6e73a717c3b88e0dad1f416d2962d
parents 12f091f0 6e1372ab
No related branches found
No related tags found
No related merge requests found
...@@ -206,6 +206,7 @@ class DocAnalyzer( ...@@ -206,6 +206,7 @@ class DocAnalyzer(
"androidx.annotation.StringDef" -> handleTypeDef(annotation, item) "androidx.annotation.StringDef" -> handleTypeDef(annotation, item)
"android.annotation.RequiresFeature" -> handleRequiresFeature(annotation, item) "android.annotation.RequiresFeature" -> handleRequiresFeature(annotation, item)
"androidx.annotation.RequiresApi" -> handleRequiresApi(annotation, item) "androidx.annotation.RequiresApi" -> handleRequiresApi(annotation, item)
"android.provider.Column" -> handleColumn(annotation, item)
"kotlin.Deprecated" -> handleKotlinDeprecation(annotation, item) "kotlin.Deprecated" -> handleKotlinDeprecation(annotation, item)
} }
...@@ -484,6 +485,48 @@ class DocAnalyzer( ...@@ -484,6 +485,48 @@ class DocAnalyzer(
addApiLevelDocumentation(level, item) addApiLevelDocumentation(level, item)
} }
} }
private fun handleColumn(
annotation: AnnotationItem,
item: Item
) {
val value = annotation.findAttribute("value")?.leafValues()?.firstOrNull() ?: return
val readOnly = annotation.findAttribute("readOnly")?.leafValues()?.firstOrNull()?.value() == true
val sb = StringBuilder(100)
val resolved = value.resolve()
val field = resolved as? FieldItem
sb.append("This constant represents a column name that can be used with a ")
sb.append("{@link android.content.ContentProvider}")
sb.append(" through a ")
sb.append("{@link android.content.ContentValues}")
sb.append(" or ")
sb.append("{@link android.database.Cursor}")
sb.append(" object. The values stored in this column are ")
sb.append("")
if (field == null) {
reporter.report(
Errors.MISSING_COLUMN, item,
"Cannot find feature field for $value required by $item (may be hidden or removed)"
)
sb.append("{@link ${value.toSource()}}")
} else {
if (filterReference.test(field)) {
sb.append("{@link ${field.containingClass().qualifiedName()}#${field.name()} ${field.containingClass().simpleName()}#${field.name()}} ")
} else {
reporter.report(
Errors.MISSING_COLUMN, item,
"Feature field $value required by $item is hidden or removed"
)
sb.append("${field.containingClass().simpleName()}#${field.name()} ")
}
}
if (readOnly) {
sb.append(", and are read-only and cannot be mutated")
}
sb.append(".")
appendDocumentation(sb.toString(), item, false)
}
}) })
} }
......
...@@ -258,6 +258,7 @@ public class Errors { ...@@ -258,6 +258,7 @@ public class Errors {
// and (2) the principle is adopted by the API council // and (2) the principle is adopted by the API council
public static final Error EXTENDS_DEPRECATED = new Error(161, HIDDEN); public static final Error EXTENDS_DEPRECATED = new Error(161, HIDDEN);
public static final Error FORBIDDEN_TAG = new Error(162, ERROR); public static final Error FORBIDDEN_TAG = new Error(162, ERROR);
public static final Error MISSING_COLUMN = new Error(163, WARNING, Category.DOCUMENTATION);
// API lint // API lint
public static final Error START_WITH_LOWER = new Error(300, ERROR, Category.API_LINT, "S1"); public static final Error START_WITH_LOWER = new Error(300, ERROR, Category.API_LINT, "S1");
......
...@@ -1869,4 +1869,75 @@ class DocAnalyzerTest : DriverTest() { ...@@ -1869,4 +1869,75 @@ class DocAnalyzerTest : DriverTest() {
dir.deleteRecursively() dir.deleteRecursively()
} }
@Test
fun `Test Column annotation`() {
// Bug: 120429729
check(
sourceFiles = *arrayOf(
java(
"""
package test.pkg;
import android.provider.Column;
import android.database.Cursor;
@SuppressWarnings("WeakerAccess")
public class ColumnTest {
@Column(Cursor.FIELD_TYPE_STRING)
public static final String DATA = "_data";
@Column(value = Cursor.FIELD_TYPE_BLOB, readOnly = true)
public static final String HASH = "_hash";
@Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
public static final String TITLE = "title";
@Column(value = Cursor.NONEXISTENT, readOnly = true)
public static final String BOGUS = "bogus";
}
"""
),
java(
"""
package android.database;
public interface Cursor {
int FIELD_TYPE_NULL = 0;
int FIELD_TYPE_INTEGER = 1;
int FIELD_TYPE_FLOAT = 2;
int FIELD_TYPE_STRING = 3;
int FIELD_TYPE_BLOB = 4;
}
"""
),
columnSource
),
checkCompilation = true,
checkDoclava1 = false,
warnings = """
src/test/pkg/ColumnTest.java:12: warning: Cannot find feature field for Cursor.NONEXISTENT required by field ColumnTest.BOGUS (may be hidden or removed) [MissingColumn]
""",
stubs = arrayOf(
"""
package test.pkg;
import android.database.Cursor;
@SuppressWarnings({"unchecked", "deprecation", "all"})
public class ColumnTest {
public ColumnTest() { throw new RuntimeException("Stub!"); }
/**
* This constant represents a column name that can be used with a {@link android.content.ContentProvider} through a {@link android.content.ContentValues} or {@link android.database.Cursor} object. The values stored in this column are {@link Cursor.NONEXISTENT}, and are read-only and cannot be mutated.
*/
@android.provider.Column(value=Cursor.NONEXISTENT, readOnly=true) public static final java.lang.String BOGUS = "bogus";
/**
* This constant represents a column name that can be used with a {@link android.content.ContentProvider} through a {@link android.content.ContentValues} or {@link android.database.Cursor} object. The values stored in this column are {@link android.database.Cursor#FIELD_TYPE_STRING Cursor#FIELD_TYPE_STRING} .
*/
@android.provider.Column(android.database.Cursor.FIELD_TYPE_STRING) public static final java.lang.String DATA = "_data";
/**
* This constant represents a column name that can be used with a {@link android.content.ContentProvider} through a {@link android.content.ContentValues} or {@link android.database.Cursor} object. The values stored in this column are {@link android.database.Cursor#FIELD_TYPE_BLOB Cursor#FIELD_TYPE_BLOB} , and are read-only and cannot be mutated.
*/
@android.provider.Column(value=android.database.Cursor.FIELD_TYPE_BLOB, readOnly=true) public static final java.lang.String HASH = "_hash";
/**
* This constant represents a column name that can be used with a {@link android.content.ContentProvider} through a {@link android.content.ContentValues} or {@link android.database.Cursor} object. The values stored in this column are {@link android.database.Cursor#FIELD_TYPE_STRING Cursor#FIELD_TYPE_STRING} , and are read-only and cannot be mutated.
*/
@android.provider.Column(value=android.database.Cursor.FIELD_TYPE_STRING, readOnly=true) public static final java.lang.String TITLE = "title";
}
"""
)
)
}
} }
\ No newline at end of file
...@@ -2453,3 +2453,28 @@ val visibleForTestingSource: TestFile = java( ...@@ -2453,3 +2453,28 @@ val visibleForTestingSource: TestFile = java(
} }
""" """
).indented() ).indented()
val columnSource: TestFile = java(
"""
package android.provider;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Documented
@Retention(RUNTIME)
@Target({FIELD})
public @interface Column {
int value();
boolean readOnly() default false;
}
"""
).indented()
\ No newline at end of file
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