Skip to content
Snippets Groups Projects
Commit 6e2a1d9c authored by Tor Norbye's avatar Tor Norbye Committed by Gerrit Code Review
Browse files

Merge "Flag forbidden super classes: AsyncTask and Activity"

parents 0b413159 4fb72ea8
No related branches found
No related tags found
No related merge requests found
......@@ -71,6 +71,7 @@ import com.android.tools.metalava.doclava1.Errors.EXCEPTION_NAME
import com.android.tools.metalava.doclava1.Errors.EXECUTOR_REGISTRATION
import com.android.tools.metalava.doclava1.Errors.EXTENDS_ERROR
import com.android.tools.metalava.doclava1.Errors.Error
import com.android.tools.metalava.doclava1.Errors.FORBIDDEN_SUPER_CLASS
import com.android.tools.metalava.doclava1.Errors.FRACTION_FLOAT
import com.android.tools.metalava.doclava1.Errors.GENERIC_EXCEPTION
import com.android.tools.metalava.doclava1.Errors.GETTER_SETTER_NAMES
......@@ -309,6 +310,7 @@ class ApiLint(private val codebase: Codebase, private val oldCodebase: Codebase?
checkUserHandle(cls, methods)
checkParams(cls)
checkSingleton(cls, methods, constructors)
checkExtends(cls)
// TODO: Not yet working
// checkOverloadArgs(cls, methods)
......@@ -3232,6 +3234,23 @@ class ApiLint(private val codebase: Codebase, private val oldCodebase: Codebase?
}
}
private fun checkExtends(cls: ClassItem) {
// Call cls.superClass().extends() instead of cls.extends() since extends returns true for self
val superCls = cls.superClass() ?: return
if (superCls.extends("android.os.AsyncTask")) {
report(
FORBIDDEN_SUPER_CLASS, cls,
"${cls.simpleName()} should not extend `AsyncTask`. AsyncTask is an implementation detail. Expose a listener or, in androidx, a `ListenableFuture` API instead"
)
}
if (superCls.extends("android.app.Activity")) {
report(
FORBIDDEN_SUPER_CLASS, cls,
"${cls.simpleName()} should not extend `Activity`. Activity subclasses are impossible to compose. Expose a composable API instead."
)
}
}
/**
* Checks whether the given full package name is the same as the given root
* package or a sub package (if we just did full.startsWith("java"), then
......
......@@ -342,6 +342,7 @@ public class Errors {
public static final Error MISSING_JVMSTATIC = new Error(381, WARNING, Category.API_LINT); // Formerly 143
public static final Error DEFAULT_VALUE_CHANGE = new Error(382, ERROR, Category.API_LINT); // Formerly 144
public static final Error DOCUMENT_EXCEPTIONS = new Error(383, ERROR, Category.API_LINT); // Formerly 145
public static final Error FORBIDDEN_SUPER_CLASS = new Error(384, ERROR, Category.API_LINT);
static {
// Attempt to initialize error names based on the field names
......
......@@ -693,9 +693,11 @@ class ApiLintTest : DriverTest() {
src/android/pkg/MyClass1.java:3: error: Inconsistent class name; should be `<Foo>Activity`, was `MyClass1` [ContextNameSuffix] [Rule C4 in go/android-api-guidelines]
src/android/pkg/MyClass1.java:6: warning: Methods implemented by developers should follow the on<Something> style, was `badlyNamedAbstractMethod` [OnNameExpected]
src/android/pkg/MyClass1.java:7: warning: If implemented by developer, should follow the on<Something> style; otherwise consider marking final [OnNameExpected]
src/android/pkg/MyClass1.java:3: error: MyClass1 should not extend `Activity`. Activity subclasses are impossible to compose. Expose a composable API instead. [ForbiddenSuperClass]
src/android/pkg/MyClass2.java:3: error: Inconsistent class name; should be `<Foo>Provider`, was `MyClass2` [ContextNameSuffix] [Rule C4 in go/android-api-guidelines]
src/android/pkg/MyClass3.java:3: error: Inconsistent class name; should be `<Foo>Service`, was `MyClass3` [ContextNameSuffix] [Rule C4 in go/android-api-guidelines]
src/android/pkg/MyClass4.java:3: error: Inconsistent class name; should be `<Foo>Receiver`, was `MyClass4` [ContextNameSuffix] [Rule C4 in go/android-api-guidelines]
src/android/pkg/MyOkActivity.java:3: error: MyOkActivity should not extend `Activity`. Activity subclasses are impossible to compose. Expose a composable API instead. [ForbiddenSuperClass]
""",
sourceFiles = *arrayOf(
java(
......@@ -2030,4 +2032,43 @@ class ApiLintTest : DriverTest() {
)
)
}
@Test
fun `Check forbidden super-classes`() {
check(
apiLint = "", // enabled
compatibilityMode = false,
warnings = """
src/android/pkg/FirstActivity.java:2: error: FirstActivity should not extend `Activity`. Activity subclasses are impossible to compose. Expose a composable API instead. [ForbiddenSuperClass]
src/android/pkg/IndirectActivity.java:2: error: IndirectActivity should not extend `Activity`. Activity subclasses are impossible to compose. Expose a composable API instead. [ForbiddenSuperClass]
src/android/pkg/MyTask.java:2: error: MyTask should not extend `AsyncTask`. AsyncTask is an implementation detail. Expose a listener or, in androidx, a `ListenableFuture` API instead [ForbiddenSuperClass]
""",
sourceFiles = *arrayOf(
java(
"""
package android.pkg;
public abstract class FirstActivity extends android.app.Activity {
private FirstActivity() { }
}
"""
),
java(
"""
package android.pkg;
public abstract class IndirectActivity extends android.app.ListActivity {
private IndirectActivity() { }
}
"""
),
java(
"""
package android.pkg;
public abstract class MyTask extends android.os.AsyncTask<String,String,String> {
private MyTask() { }
}
"""
)
)
)
}
}
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