Wrong View Cast in findViewById
ID |
kotlin.android_wrong_view_cast |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Reliability |
Language |
Kotlin |
Tags |
CWE:704, android, reliability |
Description
Reports mismatches between the cast target type of a findViewById(R.id.X) as Type expression in Kotlin code and the XML tag declared for that id in a res/layout/*.xml file. At runtime, such a mismatch throws a ClassCastException (unsafe as) or returns null (safe as?) — either way the code is broken.
Rationale
Android layout XML declares the concrete widget class for each view id. When Kotlin code casts the result of findViewById() to a type that does not match the XML declaration, the cast fails at runtime:
// layout/activity_main.xml declares: <EditText android:id="@+id/userName" ... />
// Kotlin code:
val login: Button = findViewById(R.id.userName) as Button // ClassCastException!
The rule performs a strict simple-name match between the cast type and the XML tag. Casting TextView when the XML tag is <EditText> is flagged even though EditText extends TextView, because we do not load the Android widget type hierarchy. This may produce a small number of false positives for valid upcasts, which is an acceptable trade-off for catching real ClassCastException bugs.
If an id appears in multiple layout files with different XML tags, the rule skips that id to avoid false positives from layout variants (landscape, tablet, etc.).
Remediation
Ensure the cast type matches the XML tag, or use the generic typed findViewById<T>() which is checked at compile time when bound to a typed variable:
// Correct: cast matches the XML declaration
val userName: EditText = findViewById(R.id.userName) as EditText
// Better: generic findViewById (API 26+) — no cast needed
val userName: EditText = findViewById(R.id.userName)